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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <eiseljulian@gmail.com>2018-01-30 00:53:32 +0300
committerJulian Eisel <eiseljulian@gmail.com>2018-01-30 01:24:11 +0300
commit3f0871dfcfbb1dda15c176dba92d36639305385a (patch)
treede7ffeeef7a99fc6103d413ebfa564596811087d /source/blender
parent53d94dafc474380651fc529f9c03f84ce7142b13 (diff)
parent1fe2b4bf608b22ae4513051e01cf45e5012c2409 (diff)
Merge branch 'blender2.8' into topbar
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc23
-rw-r--r--source/blender/avi/CMakeLists.txt1
-rw-r--r--source/blender/avi/intern/avi.c36
-rw-r--r--source/blender/avi/intern/avi_codecs.c2
-rw-r--r--source/blender/avi/intern/avi_intern.h2
-rw-r--r--source/blender/avi/intern/avi_mjpeg.c92
-rw-r--r--source/blender/avi/intern/avi_mjpeg.h4
-rw-r--r--source/blender/avi/intern/avi_rgb.c90
-rw-r--r--source/blender/avi/intern/avi_rgb.h4
-rw-r--r--source/blender/avi/intern/avi_rgb32.c32
-rw-r--r--source/blender/avi/intern/avi_rgb32.h4
-rw-r--r--source/blender/blenkernel/BKE_action.h2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h4
-rw-r--r--source/blender/blenkernel/BKE_camera.h3
-rw-r--r--source/blender/blenkernel/BKE_colorband.h52
-rw-r--r--source/blender/blenkernel/BKE_context.h3
-rw-r--r--source/blender/blenkernel/BKE_font.h2
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h2
-rw-r--r--source/blender/blenkernel/BKE_group.h11
-rw-r--r--source/blender/blenkernel/BKE_idprop.h10
-rw-r--r--source/blender/blenkernel/BKE_lamp.h2
-rw-r--r--source/blender/blenkernel/BKE_layer.h3
-rw-r--r--source/blender/blenkernel/BKE_library.h6
-rw-r--r--source/blender/blenkernel/BKE_library_override.h3
-rw-r--r--source/blender/blenkernel/BKE_main.h3
-rw-r--r--source/blender/blenkernel/BKE_mask.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h2
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/BKE_object.h9
-rw-r--r--source/blender/blenkernel/BKE_paint.h3
-rw-r--r--source/blender/blenkernel/BKE_particle.h5
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h1
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h6
-rw-r--r--source/blender/blenkernel/BKE_texture.h8
-rw-r--r--source/blender/blenkernel/BKE_tracking.h40
-rw-r--r--source/blender/blenkernel/BKE_world.h4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h3
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c108
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c65
-rw-r--r--source/blender/blenkernel/intern/action.c2
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c52
-rw-r--r--source/blender/blenkernel/intern/blender.c23
-rw-r--r--source/blender/blenkernel/intern/brush.c6
-rw-r--r--source/blender/blenkernel/intern/camera.c7
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c46
-rw-r--r--source/blender/blenkernel/intern/collection.c138
-rw-r--r--source/blender/blenkernel/intern/colorband.c629
-rw-r--r--source/blender/blenkernel/intern/colortools.c21
-rw-r--r--source/blender/blenkernel/intern/constraint.c5
-rw-r--r--source/blender/blenkernel/intern/context.c23
-rw-r--r--source/blender/blenkernel/intern/curve.c132
-rw-r--r--source/blender/blenkernel/intern/customdata.c31
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c8
-rw-r--r--source/blender/blenkernel/intern/deform.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c462
-rw-r--r--source/blender/blenkernel/intern/font.c39
-rw-r--r--source/blender/blenkernel/intern/freestyle.c10
-rw-r--r--source/blender/blenkernel/intern/group.c48
-rw-r--r--source/blender/blenkernel/intern/idprop.c11
-rw-r--r--source/blender/blenkernel/intern/image.c6
-rw-r--r--source/blender/blenkernel/intern/ipo.c4
-rw-r--r--source/blender/blenkernel/intern/lamp.c4
-rw-r--r--source/blender/blenkernel/intern/layer.c90
-rw-r--r--source/blender/blenkernel/intern/library.c8
-rw-r--r--source/blender/blenkernel/intern/library_override.c96
-rw-r--r--source/blender/blenkernel/intern/library_query.c14
-rw-r--r--source/blender/blenkernel/intern/library_remap.c6
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c1
-rw-r--r--source/blender/blenkernel/intern/linestyle.c18
-rw-r--r--source/blender/blenkernel/intern/mask.c12
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c13
-rw-r--r--source/blender/blenkernel/intern/material.c14
-rw-r--r--source/blender/blenkernel/intern/mesh.c44
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c146
-rw-r--r--source/blender/blenkernel/intern/modifier.c7
-rw-r--r--source/blender/blenkernel/intern/movieclip.c4
-rw-r--r--source/blender/blenkernel/intern/multires.c394
-rw-r--r--source/blender/blenkernel/intern/node.c27
-rw-r--r--source/blender/blenkernel/intern/object.c48
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c6
-rw-r--r--source/blender/blenkernel/intern/object_update.c10
-rw-r--r--source/blender/blenkernel/intern/ocean.c10
-rw-r--r--source/blender/blenkernel/intern/paint.c13
-rw-r--r--source/blender/blenkernel/intern/particle.c50
-rw-r--r--source/blender/blenkernel/intern/particle_system.c78
-rw-r--r--source/blender/blenkernel/intern/pbvh.c62
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h1
-rw-r--r--source/blender/blenkernel/intern/scene.c17
-rw-r--r--source/blender/blenkernel/intern/screen.c3
-rw-r--r--source/blender/blenkernel/intern/sequencer.c20
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c53
-rw-r--r--source/blender/blenkernel/intern/smoke.c53
-rw-r--r--source/blender/blenkernel/intern/softbody.c10
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c254
-rw-r--r--source/blender/blenkernel/intern/texture.c364
-rw-r--r--source/blender/blenkernel/intern/tracking.c152
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c203
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c11
-rw-r--r--source/blender/blenkernel/intern/world.c6
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c2
-rw-r--r--source/blender/blenlib/BLI_linklist.h3
-rw-r--r--source/blender/blenlib/BLI_listbase.h6
-rw-r--r--source/blender/blenlib/BLI_math_base.h4
-rw-r--r--source/blender/blenlib/BLI_math_bits.h19
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h5
-rw-r--r--source/blender/blenlib/BLI_task.h109
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c83
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c76
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c4
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c2
-rw-r--r--source/blender/blenlib/intern/listbase.c4
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c13
-rw-r--r--source/blender/blenlib/intern/math_bits_inline.c75
-rw-r--r--source/blender/blenlib/intern/math_rotation.c66
-rw-r--r--source/blender/blenlib/intern/math_statistics.c13
-rw-r--r--source/blender/blenlib/intern/rct.c2
-rw-r--r--source/blender/blenlib/intern/task.c225
-rw-r--r--source/blender/blenloader/BLO_blend_defs.h2
-rw-r--r--source/blender/blenloader/intern/readfile.c196
-rw-r--r--source/blender/blenloader/intern/versioning_250.c4
-rw-r--r--source/blender/blenloader/intern/versioning_260.c11
-rw-r--r--source/blender/blenloader/intern/versioning_270.c17
-rw-r--r--source/blender/blenloader/intern/versioning_280.c156
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c7
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c8
-rw-r--r--source/blender/blenloader/intern/writefile.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c10
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c15
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c15
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c580
-rw-r--r--source/blender/collada/AnimationImporter.cpp9
-rw-r--r--source/blender/collada/ArmatureImporter.cpp7
-rw-r--r--source/blender/collada/ArmatureImporter.h3
-rw-r--r--source/blender/collada/DocumentImporter.cpp17
-rw-r--r--source/blender/collada/DocumentImporter.h1
-rw-r--r--source/blender/collada/EffectExporter.cpp2
-rw-r--r--source/blender/collada/GeometryExporter.cpp1
-rw-r--r--source/blender/collada/MeshImporter.cpp8
-rw-r--r--source/blender/collada/MeshImporter.h4
-rw-r--r--source/blender/collada/SkinInfo.cpp4
-rw-r--r--source/blender/collada/SkinInfo.h2
-rw-r--r--source/blender/collada/collada_utils.cpp5
-rw-r--r--source/blender/collada/collada_utils.h2
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h2
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp5
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp25
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp3
-rw-r--r--source/blender/depsgraph/CMakeLists.txt9
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h22
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h9
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h56
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc59
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc35
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc99
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h73
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc16
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc (renamed from source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc)42
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc157
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc35
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc7
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h15
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc24
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc106
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc538
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc31
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h7
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc143
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc172
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc106
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_stats.cc70
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_stats.h40
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc275
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h109
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc45
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h61
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_id.cc217
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_id.h81
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc2
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h3
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_time.cc46
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_time.h52
-rw-r--r--source/blender/draw/CMakeLists.txt7
-rw-r--r--source/blender/draw/DRW_engine.h21
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c1
-rw-r--r--source/blender/draw/engines/clay/clay_engine.c103
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c106
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c25
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c107
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c217
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c334
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c393
-rw-r--r--source/blender/draw/engines/eevee/eevee_lut.h515
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c371
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c82
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c115
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h231
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c278
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c181
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c31
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c119
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c232
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl164
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl26
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl123
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl55
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl49
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl410
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/lamps_lib.glsl43
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl48
-rw-r--r--source/blender/draw/engines/eevee/shaders/ltc_lib.glsl426
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/ssr_lib.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl37
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl22
-rw-r--r--source/blender/draw/engines/external/external_engine.c1
-rw-r--r--source/blender/draw/intern/DRW_render.h39
-rw-r--r--source/blender/draw/intern/draw_armature.c96
-rw-r--r--source/blender/draw/intern/draw_cache.c257
-rw-r--r--source/blender/draw/intern/draw_cache.h8
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h14
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c156
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c338
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c9
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c7
-rw-r--r--source/blender/draw/intern/draw_common.c35
-rw-r--r--source/blender/draw/intern/draw_common.h22
-rw-r--r--source/blender/draw/intern/draw_instance_data.c226
-rw-r--r--source/blender/draw/intern/draw_instance_data.h41
-rw-r--r--source/blender/draw/intern/draw_manager.c716
-rw-r--r--source/blender/draw/intern/draw_view.c34
-rw-r--r--source/blender/draw/intern/draw_view.h5
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c1
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c37
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c1
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c1
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c1
-rw-r--r--source/blender/draw/modes/edit_surface_mode.c1
-rw-r--r--source/blender/draw/modes/edit_text_mode.c1
-rw-r--r--source/blender/draw/modes/object_mode.c106
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c1
-rw-r--r--source/blender/draw/modes/paint_vertex_mode.c1
-rw-r--r--source/blender/draw/modes/paint_weight_mode.c1
-rw-r--r--source/blender/draw/modes/particle_mode.c1
-rw-r--r--source/blender/draw/modes/pose_mode.c1
-rw-r--r--source/blender/draw/modes/sculpt_mode.c1
-rw-r--r--source/blender/draw/modes/shaders/common_globals_lib.glsl14
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl79
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl2
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl40
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl13
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl66
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl14
-rw-r--r--source/blender/draw/modes/shaders/object_particle_prim_frag.glsl9
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/armature/armature_relations.c42
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c5
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_select.c2
-rw-r--r--source/blender/editors/armature/pose_transform.c22
-rw-r--r--source/blender/editors/curve/curve_ops.c3
-rw-r--r--source/blender/editors/curve/editcurve.c6
-rw-r--r--source/blender/editors/curve/editcurve_paint.c6
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt500
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c2
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_manipulator_library.h1
-rw-r--r--source/blender/editors/include/ED_mesh.h2
-rw-r--r--source/blender/editors/include/ED_screen.h4
-rw-r--r--source/blender/editors/include/ED_view3d.h35
-rw-r--r--source/blender/editors/include/UI_icons.h12
-rw-r--r--source/blender/editors/include/UI_interface.h38
-rw-r--r--source/blender/editors/interface/CMakeLists.txt5
-rw-r--r--source/blender/editors/interface/interface_draw.c6
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c1205
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c356
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c337
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c351
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c391
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c234
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h54
-rw-r--r--source/blender/editors/interface/interface_handlers.c96
-rw-r--r--source/blender/editors/interface/interface_intern.h16
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_ops.c5
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c256
-rw-r--r--source/blender/editors/interface/interface_templates.c336
-rw-r--r--source/blender/editors/interface/interface_widgets.c6
-rw-r--r--source/blender/editors/interface/resources.c4
-rw-r--r--source/blender/editors/interface/view2d_ops.c3
-rw-r--r--source/blender/editors/io/io_collada.c3
-rw-r--r--source/blender/editors/manipulator_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/manipulator_library/manipulator_library_utils.c2
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c115
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c262
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c6
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c3
-rw-r--r--source/blender/editors/mesh/editmesh_add.c111
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c10
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c7
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c10
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c1
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c10
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c5
-rw-r--r--source/blender/editors/object/object_add.c19
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/object/object_relations.c182
-rw-r--r--source/blender/editors/object/object_select.c8
-rw-r--r--source/blender/editors/physics/particle_edit.c3
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/render/render_internal.c50
-rw-r--r--source/blender/editors/render/render_opengl.c12
-rw-r--r--source/blender/editors/render/render_preview.c15
-rw-r--r--source/blender/editors/render/render_shading.c5
-rw-r--r--source/blender/editors/render/render_update.c47
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/screen_draw.c138
-rw-r--r--source/blender/editors/screen/screen_edit.c3
-rw-r--r--source/blender/editors/screen/screen_intern.h4
-rw-r--r--source/blender/editors/screen/screen_ops.c632
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c9
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c30
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c141
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c429
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h18
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c14
-rw-r--r--source/blender/editors/space_action/action_data.c2
-rw-r--r--source/blender/editors/space_action/action_select.c6
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c23
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/clip_intern.h2
-rw-r--r--source/blender/editors/space_clip/clip_utils.c58
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c13
-rw-r--r--source/blender/editors/space_clip/tracking_select.c4
-rw-r--r--source/blender/editors/space_file/space_file.c15
-rw-r--r--source/blender/editors/space_graph/graph_edit.c86
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c1
-rw-r--r--source/blender/editors/space_graph/graph_select.c6
-rw-r--r--source/blender/editors/space_image/image_buttons.c7
-rw-r--r--source/blender/editors/space_image/image_ops.c9
-rw-r--r--source/blender/editors/space_image/space_image.c29
-rw-r--r--source/blender/editors/space_info/space_info.c20
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c4
-rw-r--r--source/blender/editors/space_nla/nla_select.c3
-rw-r--r--source/blender/editors/space_node/drawnode.c52
-rw-r--r--source/blender/editors/space_node/node_relationships.c35
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c397
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c163
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h40
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c171
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c40
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c707
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c22
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c9
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c43
-rw-r--r--source/blender/editors/space_text/text_draw.c4
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c18
-rw-r--r--source/blender/editors/space_view3d/drawobject.c64
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c111
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c59
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c1830
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h25
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_camera.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_navigate.c359
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c307
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_ruler.c27
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c19
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c1436
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c714
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c13
-rw-r--r--source/blender/editors/transform/transform.c17
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_manipulator.c6
-rw-r--r--source/blender/editors/transform/transform_orientations.c17
-rw-r--r--source/blender/editors/transform/transform_snap_object.c6
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c89
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp4
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_batch.h25
-rw-r--r--source/blender/gpu/GPU_buffers.h13
-rw-r--r--source/blender/gpu/GPU_framebuffer.h2
-rw-r--r--source/blender/gpu/GPU_texture.h4
-rw-r--r--source/blender/gpu/GPU_viewport.h3
-rw-r--r--source/blender/gpu/intern/gpu_batch.c304
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c200
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c86
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c4
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c9
-rw-r--r--source/blender/gpu/intern/gpu_material.c14
-rw-r--r--source/blender/gpu/intern/gpu_texture.c43
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl11
-rw-r--r--source/blender/imbuf/IMB_imbuf.h6
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h4
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c40
-rw-r--r--source/blender/imbuf/intern/anim_movie.c23
-rw-r--r--source/blender/imbuf/intern/bmp.c30
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c4
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c1
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c4
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c105
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h2
-rw-r--r--source/blender/imbuf/intern/iris.c67
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp54
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp2
-rw-r--r--source/blender/imbuf/intern/png.c54
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c39
-rw-r--r--source/blender/imbuf/intern/tiff.c26
-rw-r--r--source/blender/makesdna/DNA_ID.h47
-rw-r--r--source/blender/makesdna/DNA_curve_types.h4
-rw-r--r--source/blender/makesdna/DNA_layer_types.h7
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h4
-rw-r--r--source/blender/makesdna/DNA_object_types.h41
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h8
-rw-r--r--source/blender/makesdna/DNA_scene_types.h177
-rw-r--r--source/blender/makesdna/DNA_screen_types.h12
-rw-r--r--source/blender/makesdna/DNA_space_types.h63
-rw-r--r--source/blender/makesdna/DNA_text_types.h5
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h34
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h9
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c4
-rw-r--r--source/blender/makesrna/RNA_access.h42
-rw-r--r--source/blender/makesrna/RNA_types.h9
-rw-r--r--source/blender/makesrna/intern/makesrna.c22
-rw-r--r--source/blender/makesrna/intern/rna_ID.c27
-rw-r--r--source/blender/makesrna/intern/rna_access.c579
-rw-r--r--source/blender/makesrna/intern/rna_armature.c2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c4
-rw-r--r--source/blender/makesrna/intern/rna_color.c8
-rw-r--r--source/blender/makesrna/intern/rna_context.c6
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c64
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c2
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_layer.c150
-rw-r--r--source/blender/makesrna/intern/rna_lightprobe.c7
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_material.c5
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c28
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c8
-rw-r--r--source/blender/makesrna/intern/rna_object.c64
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c6
-rw-r--r--source/blender/makesrna/intern/rna_particle.c5
-rw-r--r--source/blender/makesrna/intern/rna_pose.c3
-rw-r--r--source/blender/makesrna/intern/rna_rna.c98
-rw-r--r--source/blender/makesrna/intern/rna_scene.c6
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c22
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c119
-rw-r--r--source/blender/makesrna/intern/rna_texture.c3
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c147
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c20
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c56
-rw-r--r--source/blender/makesrna/intern/rna_wm.c12
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c7
-rw-r--r--source/blender/makesrna/intern/rna_wm_manipulator.c8
-rw-r--r--source/blender/modifiers/intern/MOD_array.c26
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_build.c6
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c20
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c17
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c10
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c28
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c16
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c6
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c21
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c2
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c12
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c25
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c8
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c169
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c12
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c4
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c26
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c4
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c66
-rw-r--r--source/blender/modifiers/intern/MOD_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c2
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c13
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c2
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c16
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c44
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c9
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/composite/node_composite_util.h1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.c2
-rw-r--r--source/blender/nodes/intern/node_socket.c17
-rw-r--r--source/blender/nodes/intern/node_util.c6
-rw-r--r--source/blender/nodes/intern/node_util.h1
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c15
-rw-r--r--source/blender/nodes/shader/node_shader_util.h1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.c65
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c6
-rw-r--r--source/blender/nodes/texture/node_texture_util.h1
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c2
-rw-r--r--source/blender/python/gawain/gwn_py_types.c10
-rw-r--r--source/blender/python/intern/bpy_rna.c10
-rw-r--r--source/blender/python/intern/gpu_offscreen.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c7
-rw-r--r--source/blender/render/extern/include/RE_engine.h2
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h1
-rw-r--r--source/blender/render/intern/source/convertblender.c16
-rw-r--r--source/blender/render/intern/source/external_engine.c7
-rw-r--r--source/blender/render/intern/source/pipeline.c56
-rw-r--r--source/blender/render/intern/source/pixelshading.c2
-rw-r--r--source/blender/render/intern/source/pointdensity.c18
-rw-r--r--source/blender/render/intern/source/render_result.c28
-rw-r--r--source/blender/render/intern/source/render_texture.c13
-rw-r--r--source/blender/render/intern/source/shadeoutput.c12
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h22
-rw-r--r--source/blender/windowmanager/WM_types.h22
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c7
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c70
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c97
-rw-r--r--source/blender/windowmanager/intern/wm_files.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c2
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c2
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c106
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_api.h5
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_types.h9
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator.c31
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c197
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h5
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c110
-rw-r--r--source/blender/windowmanager/manipulators/wm_manipulator_fn.h1
602 files changed, 23561 insertions, 11917 deletions
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
index d6e7a80d174..b3b015c7abf 100644
--- a/source/blender/alembic/intern/abc_customdata.cc
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -235,17 +235,19 @@ static void read_uvs(const CDStreamConfig &config, void *data,
MPoly *mpolys = config.mpoly;
MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
- unsigned int uv_index, loop_index;
+ unsigned int uv_index, loop_index, rev_loop_index;
for (int i = 0; i < config.totpoly; ++i) {
MPoly &poly = mpolys[i];
+ unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1;
for (int f = 0; f < poly.totloop; ++f) {
loop_index = poly.loopstart + f;
+ rev_loop_index = rev_loop_offset - f;
uv_index = (*indices)[loop_index];
const Imath::V2f &uv = (*uvs)[uv_index];
- MLoopUV &loopuv = mloopuvs[loop_index];
+ MLoopUV &loopuv = mloopuvs[rev_loop_index];
loopuv.uv[0] = uv[0];
loopuv.uv[1] = uv[1];
}
@@ -283,6 +285,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name,
{
C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+ Alembic::Abc::UInt32ArraySamplePtr indices;
bool use_c3f_ptr;
bool is_facevarying;
@@ -297,6 +300,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name,
config.totloop == sample.getIndices()->size();
c3f_ptr = sample.getVals();
+ indices = sample.getIndices();
use_c3f_ptr = true;
}
else if (IC4fGeomParam::matches(prop_header)) {
@@ -309,6 +313,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name,
config.totloop == sample.getIndices()->size();
c4f_ptr = sample.getVals();
+ indices = sample.getIndices();
use_c3f_ptr = false;
}
else {
@@ -329,6 +334,12 @@ static void read_custom_data_mcols(const std::string & iobject_full_name,
size_t color_index;
bool bounds_warning_given = false;
+ /* The colors can go through two layers of indexing. Often the 'indices'
+ * array doesn't do anything (i.e. indices[n] = n), but when it does, it's
+ * important. Blender 2.79 writes indices incorrectly (see T53745), which
+ * is why we have to check for indices->size() > 0 */
+ bool use_dual_indexing = is_facevarying && indices->size() > 0;
+
for (int i = 0; i < config.totpoly; ++i) {
MPoly *poly = &mpolys[i];
MCol *cface = &cfaces[poly->loopstart + poly->totloop];
@@ -338,9 +349,13 @@ static void read_custom_data_mcols(const std::string & iobject_full_name,
--cface;
--mloop;
+ color_index = is_facevarying ? face_index : mloop->v;
+ if (use_dual_indexing) {
+ color_index = (*indices)[color_index];
+ }
if (use_c3f_ptr) {
color_index = mcols_out_of_bounds_check(
- is_facevarying ? face_index : mloop->v,
+ color_index,
c3f_ptr->size(),
iobject_full_name, prop_header,
bounds_warning_given);
@@ -353,7 +368,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name,
}
else {
color_index = mcols_out_of_bounds_check(
- is_facevarying ? face_index : mloop->v,
+ color_index,
c4f_ptr->size(),
iobject_full_name, prop_header,
bounds_warning_given);
diff --git a/source/blender/avi/CMakeLists.txt b/source/blender/avi/CMakeLists.txt
index 292206d8cb9..5009bd2a30b 100644
--- a/source/blender/avi/CMakeLists.txt
+++ b/source/blender/avi/CMakeLists.txt
@@ -26,6 +26,7 @@
set(INC
.
../blenlib
+ ../imbuf
../../../intern/guardedalloc
)
diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c
index 9601d6e5002..6695998fd35 100644
--- a/source/blender/avi/intern/avi.c
+++ b/source/blender/avi/intern/avi.c
@@ -285,13 +285,15 @@ bool AVI_is_avi(const char *name)
fseek(movie.fp, movie.header->size - 14 * 4, SEEK_CUR);
- if (movie.header->Streams < 1) {
- DEBUG_PRINT("streams less than 1\n");
+ /* Limit number of streams to some reasonable amount to prevent
+ * buffer oveflow vulnerabilities. */
+ if (movie.header->Streams < 1 || movie.header->Streams > 65536) {
+ DEBUG_PRINT("Number of streams should be in range 1-65536\n");
fclose(movie.fp);
return 0;
}
- movie.streams = (AviStreamRec *) MEM_callocN(sizeof(AviStreamRec) * movie.header->Streams, "moviestreams");
+ movie.streams = (AviStreamRec *) MEM_calloc_arrayN(movie.header->Streams, sizeof(AviStreamRec), "moviestreams");
for (temp = 0; temp < movie.header->Streams; temp++) {
@@ -486,12 +488,14 @@ AviError AVI_open_movie(const char *name, AviMovie *movie)
fseek(movie->fp, movie->header->size - 14 * 4, SEEK_CUR);
- if (movie->header->Streams < 1) {
- DEBUG_PRINT("streams less than 1\n");
+ /* Limit number of streams to some reasonable amount to prevent
+ * buffer oveflow vulnerabilities. */
+ if (movie->header->Streams < 1 || movie->header->Streams > 65536) {
+ DEBUG_PRINT("Number of streams should be in range 1-65536\n");
return AVI_ERROR_FORMAT;
}
- movie->streams = (AviStreamRec *) MEM_callocN(sizeof(AviStreamRec) * movie->header->Streams, "moviestreams");
+ movie->streams = (AviStreamRec *) MEM_calloc_arrayN(movie->header->Streams, sizeof(AviStreamRec), "moviestreams");
for (temp = 0; temp < movie->header->Streams; temp++) {
@@ -689,7 +693,7 @@ AviError AVI_open_movie(const char *name, AviMovie *movie)
void *AVI_read_frame(AviMovie *movie, AviFormat format, int frame, int stream)
{
- int cur_frame = -1, temp, i = 0, rewind = 1;
+ int cur_frame = -1, i = 0, rewind = 1;
void *buffer;
/* Retrieve the record number of the desired frame in the index
@@ -720,16 +724,16 @@ void *AVI_read_frame(AviMovie *movie, AviFormat format, int frame, int stream)
fseek(movie->fp, movie->read_offset + movie->entries[i - 1].Offset, SEEK_SET);
- temp = GET_FCC(movie->fp);
- buffer = MEM_mallocN(temp, "readbuffer");
+ size_t size = GET_FCC(movie->fp);
+ buffer = MEM_mallocN(size, "readbuffer");
- if (fread(buffer, 1, temp, movie->fp) != temp) {
+ if (fread(buffer, 1, size, movie->fp) != size) {
MEM_freeN(buffer);
return NULL;
}
- buffer = avi_format_convert(movie, stream, buffer, movie->streams[stream].format, format, &temp);
+ buffer = avi_format_convert(movie, stream, buffer, movie->streams[stream].format, format, &size);
return buffer;
}
@@ -801,6 +805,13 @@ AviError AVI_open_compress(char *name, AviMovie *movie, int streams, ...)
movie->header->Reserved[2] = 0;
movie->header->Reserved[3] = 0;
+ /* Limit number of streams to some reasonable amount to prevent
+ * buffer oveflow vulnerabilities. */
+ if (movie->header->Streams < 0 || movie->header->Streams > 65536) {
+ DEBUG_PRINT("Number of streams should be in range 0-65536\n");
+ return AVI_ERROR_FORMAT;
+ }
+
movie->streams = (AviStreamRec *) MEM_mallocN(sizeof(AviStreamRec) * movie->header->Streams, "moviestreams");
va_start(ap, streams);
@@ -968,7 +979,6 @@ AviError AVI_write_frame(AviMovie *movie, int frame_num, ...)
int64_t rec_off;
AviFormat format;
void *buffer;
- int size;
if (frame_num < 0)
return AVI_ERROR_OPTION;
@@ -1002,7 +1012,7 @@ AviError AVI_write_frame(AviMovie *movie, int frame_num, ...)
format = va_arg(ap, AviFormat);
buffer = va_arg(ap, void *);
- size = va_arg(ap, int);
+ size_t size = va_arg(ap, int);
/* Convert the buffer into the output format */
buffer = avi_format_convert(movie, stream, buffer, format, movie->streams[stream].format, &size);
diff --git a/source/blender/avi/intern/avi_codecs.c b/source/blender/avi/intern/avi_codecs.c
index c14d088c8ea..f52ec44faab 100644
--- a/source/blender/avi/intern/avi_codecs.c
+++ b/source/blender/avi/intern/avi_codecs.c
@@ -39,7 +39,7 @@
#include "avi_mjpeg.h"
#include "avi_rgb32.h"
-void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size)
+void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, size_t *size)
{
if (from == to)
return buffer;
diff --git a/source/blender/avi/intern/avi_intern.h b/source/blender/avi/intern/avi_intern.h
index 0b494047612..b2fec1edfc1 100644
--- a/source/blender/avi/intern/avi_intern.h
+++ b/source/blender/avi/intern/avi_intern.h
@@ -59,7 +59,7 @@ unsigned int GET_TCC(FILE *fp);
putc(ch2[1], fp); \
} (void)0
-void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size);
+void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, size_t *size);
int avi_get_data_id(AviFormat format, int stream);
int avi_get_format_type(AviFormat format);
diff --git a/source/blender/avi/intern/avi_mjpeg.c b/source/blender/avi/intern/avi_mjpeg.c
index 1fa9da6b3a2..258426809fb 100644
--- a/source/blender/avi/intern/avi_mjpeg.c
+++ b/source/blender/avi/intern/avi_mjpeg.c
@@ -39,15 +39,17 @@
#include "MEM_guardedalloc.h"
+#include "IMB_imbuf.h"
+
#include "jpeglib.h"
#include "jerror.h"
#include "avi_mjpeg.h"
-static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, int bufsize);
-static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, int bufsize);
+static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, size_t bufsize);
+static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, size_t bufsize);
-static int numbytes;
+static size_t numbytes;
static void add_huff_table(j_decompress_ptr dinfo, JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
{
@@ -151,10 +153,8 @@ static void std_huff_tables(j_decompress_ptr dinfo)
bits_ac_chrominance, val_ac_chrominance);
}
-static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsigned int width, unsigned int height, int bufsize)
+static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsigned int width, unsigned int height, size_t bufsize)
{
- int rowstride;
- unsigned int y;
struct jpeg_decompress_struct dinfo;
struct jpeg_error_mgr jerr;
@@ -174,8 +174,8 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign
jpeg_start_decompress(&dinfo);
- rowstride = dinfo.output_width * dinfo.output_components;
- for (y = 0; y < dinfo.output_height; y++) {
+ size_t rowstride = dinfo.output_width * dinfo.output_components;
+ for (size_t y = 0; y < dinfo.output_height; y++) {
jpeg_read_scanlines(&dinfo, (JSAMPARRAY) &outBuffer, 1);
outBuffer += rowstride;
}
@@ -194,7 +194,7 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign
jpeg_start_decompress(&dinfo);
rowstride = dinfo.output_width * dinfo.output_components;
- for (y = 0; y < dinfo.output_height; y++) {
+ for (size_t y = 0; y < dinfo.output_height; y++) {
jpeg_read_scanlines(&dinfo, (JSAMPARRAY) &outBuffer, 1);
outBuffer += rowstride;
}
@@ -204,10 +204,8 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign
return 1;
}
-static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned char *inBuffer, int width, int height, int bufsize)
+static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned char *inBuffer, int width, int height, size_t bufsize)
{
- int i, rowstride;
- unsigned int y;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
unsigned char marker[60];
@@ -240,7 +238,7 @@ static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned
jpeg_start_compress(&cinfo, false);
- i = 0;
+ int i = 0;
marker[i++] = 'A';
marker[i++] = 'V';
marker[i++] = 'I';
@@ -257,8 +255,8 @@ static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned
jpeg_write_marker(&cinfo, JPEG_COM, marker, 60);
- rowstride = cinfo.image_width * cinfo.input_components;
- for (y = 0; y < cinfo.image_height; y++) {
+ size_t rowstride = cinfo.image_width * cinfo.input_components;
+ for (size_t y = 0; y < cinfo.image_height; y++) {
jpeg_write_scanlines(&cinfo, (JSAMPARRAY) &inBuffer, 1);
inBuffer += rowstride;
}
@@ -268,7 +266,7 @@ static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned
static void interlace(unsigned char *to, unsigned char *from, int width, int height)
{
- int i, rowstride = width * 3;
+ size_t i, rowstride = width * 3;
for (i = 0; i < height; i++) {
if (i & 1)
@@ -280,7 +278,7 @@ static void interlace(unsigned char *to, unsigned char *from, int width, int hei
static void deinterlace(int odd, unsigned char *to, unsigned char *from, int width, int height)
{
- int i, rowstride = width * 3;
+ size_t i, rowstride = width * 3;
for (i = 0; i < height; i++) {
if ((i & 1) == odd)
@@ -290,22 +288,27 @@ static void deinterlace(int odd, unsigned char *to, unsigned char *from, int wid
}
}
-void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size)
+void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
{
int deint;
unsigned char *buf;
(void)stream; /* unused */
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 1");
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_from_mjpeg 1");
+ if (!buf) {
+ return NULL;
+ }
deint = Decode_JPEG(buffer, buf, movie->header->Width, movie->header->Height, *size);
MEM_freeN(buffer);
if (deint) {
- buffer = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 2");
- interlace(buffer, buf, movie->header->Width, movie->header->Height);
+ buffer = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_from_mjpeg 2");
+ if (buffer) {
+ interlace(buffer, buf, movie->header->Width, movie->header->Height);
+ }
MEM_freeN(buf);
buf = buffer;
@@ -314,43 +317,50 @@ void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffe
return buf;
}
-void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size)
+void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
{
unsigned char *buf;
- int bufsize = *size;
+ size_t bufsize = *size;
numbytes = 0;
*size = 0;
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1");
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_to_mjpeg 1");
+ if (!buf) {
+ return NULL;
+ }
+
if (!movie->interlace) {
Compress_JPEG(movie->streams[stream].sh.Quality / 100,
buf, buffer,
movie->header->Width,
movie->header->Height,
bufsize);
+ *size += numbytes;
}
else {
deinterlace(movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height);
MEM_freeN(buffer);
buffer = buf;
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2");
-
- Compress_JPEG(movie->streams[stream].sh.Quality / 100,
- buf, buffer,
- movie->header->Width,
- movie->header->Height / 2,
- bufsize / 2);
- *size += numbytes;
- numbytes = 0;
- Compress_JPEG(movie->streams[stream].sh.Quality / 100,
- buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3,
- movie->header->Width,
- movie->header->Height / 2,
- bufsize / 2);
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_to_mjpeg 1");
+
+ if (buf) {
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf, buffer,
+ movie->header->Width,
+ movie->header->Height / 2,
+ bufsize / 2);
+ *size += numbytes;
+ numbytes = 0;
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf + *size, buffer + (size_t)(movie->header->Height / 2) * (size_t)movie->header->Width * 3,
+ movie->header->Width,
+ movie->header->Height / 2,
+ bufsize / 2);
+ *size += numbytes;
+ }
}
- *size += numbytes;
MEM_freeN(buffer);
return buf;
@@ -377,7 +387,7 @@ static void jpegmemdestmgr_term_destination(j_compress_ptr cinfo)
MEM_freeN(cinfo->dest);
}
-static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, int bufsize)
+static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, size_t bufsize)
{
cinfo->dest = MEM_mallocN(sizeof(*(cinfo->dest)), "avi.jpegmemdestmgr_build");
@@ -430,7 +440,7 @@ static void jpegmemsrcmgr_term_source(j_decompress_ptr dinfo)
MEM_freeN(dinfo->src);
}
-static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, int bufsize)
+static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, size_t bufsize)
{
dinfo->src = MEM_mallocN(sizeof(*(dinfo->src)), "avi.jpegmemsrcmgr_build");
diff --git a/source/blender/avi/intern/avi_mjpeg.h b/source/blender/avi/intern/avi_mjpeg.h
index e8cba1849e7..e1e3cdf1fd8 100644
--- a/source/blender/avi/intern/avi_mjpeg.h
+++ b/source/blender/avi/intern/avi_mjpeg.h
@@ -32,7 +32,7 @@
#ifndef __AVI_MJPEG_H__
#define __AVI_MJPEG_H__
-void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size);
-void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size);
+void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
+void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
#endif /* __AVI_MJPEG_H__ */
diff --git a/source/blender/avi/intern/avi_rgb.c b/source/blender/avi/intern/avi_rgb.c
index 632ecad61a6..f0baf7c6c14 100644
--- a/source/blender/avi/intern/avi_rgb.c
+++ b/source/blender/avi/intern/avi_rgb.c
@@ -40,11 +40,12 @@
#include "AVI_avi.h"
#include "avi_rgb.h"
+#include "IMB_imbuf.h"
+
/* implementation */
-void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size)
+void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
{
- int x, y, i, rowstride;
unsigned char *buf;
AviBitmapInfoHeader *bi;
short bits = 32;
@@ -60,33 +61,35 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buf
#ifdef __BIG_ENDIAN__
unsigned char *pxla;
#endif
-
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "fromavirgbbuf");
- y = movie->header->Height;
- to = buf;
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "fromavirgbbuf");
+
+ if (buf) {
+ size_t y = movie->header->Height;
+ to = buf;
+
+ while (y--) {
+ pxl = (unsigned short *) (buffer + y * movie->header->Width * 2);
- while (y--) {
- pxl = (unsigned short *) (buffer + y * movie->header->Width * 2);
-
#ifdef __BIG_ENDIAN__
- pxla = (unsigned char *)pxl;
+ pxla = (unsigned char *)pxl;
#endif
- x = movie->header->Width;
- while (x--) {
+ size_t x = movie->header->Width;
+ while (x--) {
#ifdef __BIG_ENDIAN__
- i = pxla[0];
- pxla[0] = pxla[1];
- pxla[1] = i;
-
- pxla += 2;
+ int i = pxla[0];
+ pxla[0] = pxla[1];
+ pxla[1] = i;
+
+ pxla += 2;
#endif
-
- *(to++) = ((*pxl >> 10) & 0x1f) * 8;
- *(to++) = ((*pxl >> 5) & 0x1f) * 8;
- *(to++) = (*pxl & 0x1f) * 8;
- pxl++;
+
+ *(to++) = ((*pxl >> 10) & 0x1f) * 8;
+ *(to++) = ((*pxl >> 5) & 0x1f) * 8;
+ *(to++) = (*pxl & 0x1f) * 8;
+ pxl++;
+ }
}
}
@@ -95,48 +98,49 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buf
return buf;
}
else {
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "fromavirgbbuf");
-
- rowstride = movie->header->Width * 3;
- if ((bits != 16) && (movie->header->Width % 2)) rowstride++;
-
- for (y = 0; y < movie->header->Height; y++) {
- memcpy(&buf[y * movie->header->Width * 3], &buffer[((movie->header->Height - 1) - y) * rowstride], movie->header->Width * 3);
- }
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "fromavirgbbuf");
- for (y = 0; y < movie->header->Height * movie->header->Width * 3; y += 3) {
- i = buf[y];
- buf[y] = buf[y + 2];
- buf[y + 2] = i;
+ if (buf) {
+ size_t rowstride = movie->header->Width * 3;
+ if ((bits != 16) && (movie->header->Width % 2)) rowstride++;
+
+ for (size_t y = 0; y < movie->header->Height; y++) {
+ memcpy(&buf[y * movie->header->Width * 3], &buffer[((movie->header->Height - 1) - y) * rowstride], movie->header->Width * 3);
+ }
+
+ for (size_t y = 0; y < (size_t)movie->header->Height * (size_t)movie->header->Width * 3; y += 3) {
+ int i = buf[y];
+ buf[y] = buf[y + 2];
+ buf[y + 2] = i;
+ }
}
-
+
MEM_freeN(buffer);
-
+
return buf;
}
}
-void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size)
+void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
{
- int y, x, i, rowstride;
unsigned char *buf;
(void)stream; /* unused */
- rowstride = movie->header->Width * 3;
+ size_t rowstride = movie->header->Width * 3;
/* AVI files has uncompressed lines 4-byte aligned */
rowstride = (rowstride + 3) & ~3;
*size = movie->header->Height * rowstride;
buf = MEM_mallocN(*size, "toavirgbbuf");
- for (y = 0; y < movie->header->Height; y++) {
+ for (size_t y = 0; y < movie->header->Height; y++) {
memcpy(&buf[y * rowstride], &buffer[((movie->header->Height - 1) - y) * movie->header->Width * 3], movie->header->Width * 3);
}
- for (y = 0; y < movie->header->Height; y++) {
- for (x = 0; x < movie->header->Width * 3; x += 3) {
- i = buf[y * rowstride + x];
+ for (size_t y = 0; y < movie->header->Height; y++) {
+ for (size_t x = 0; x < movie->header->Width * 3; x += 3) {
+ int i = buf[y * rowstride + x];
buf[y * rowstride + x] = buf[y * rowstride + x + 2];
buf[y * rowstride + x + 2] = i;
}
diff --git a/source/blender/avi/intern/avi_rgb.h b/source/blender/avi/intern/avi_rgb.h
index 773166e9fab..67bb4172769 100644
--- a/source/blender/avi/intern/avi_rgb.h
+++ b/source/blender/avi/intern/avi_rgb.h
@@ -32,7 +32,7 @@
#ifndef __AVI_RGB_H__
#define __AVI_RGB_H__
-void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size);
-void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size);
+void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
+void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
#endif /* __AVI_RGB_H__ */
diff --git a/source/blender/avi/intern/avi_rgb32.c b/source/blender/avi/intern/avi_rgb32.c
index c9cbcb05bb8..051fdba1cd2 100644
--- a/source/blender/avi/intern/avi_rgb32.c
+++ b/source/blender/avi/intern/avi_rgb32.c
@@ -37,24 +37,28 @@
#include "MEM_guardedalloc.h"
+#include "IMB_imbuf.h"
+
#include "AVI_avi.h"
#include "avi_rgb32.h"
-void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size)
+void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
{
- int y, x, rowstridea, rowstrideb;
unsigned char *buf;
(void)stream; /* unused */
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "fromrgb32buf");
- *size = movie->header->Height * movie->header->Width * 3;
+ *size = (size_t)movie->header->Height * (size_t)movie->header->Width * 3;
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "fromrgb32buf");
+ if (!buf) {
+ return NULL;
+ }
- rowstridea = movie->header->Width * 3;
- rowstrideb = movie->header->Width * 4;
+ size_t rowstridea = movie->header->Width * 3;
+ size_t rowstrideb = movie->header->Width * 4;
- for (y = 0; y < movie->header->Height; y++) {
- for (x = 0; x < movie->header->Width; x++) {
+ for (size_t y = 0; y < movie->header->Height; y++) {
+ for (size_t x = 0; x < movie->header->Width; x++) {
buf[y * rowstridea + x * 3 + 0] = buffer[y * rowstrideb + x * 4 + 3];
buf[y * rowstridea + x * 3 + 1] = buffer[y * rowstrideb + x * 4 + 2];
buf[y * rowstridea + x * 3 + 2] = buffer[y * rowstrideb + x * 4 + 1];
@@ -66,21 +70,23 @@ void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffe
return buf;
}
-void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size)
+void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
{
- int i;
unsigned char *buf;
unsigned char *to, *from;
(void)stream; /* unused */
- *size = movie->header->Height * movie->header->Width * 4;
- buf = MEM_mallocN(*size, "torgb32buf");
+ *size = (size_t)movie->header->Height * (size_t)movie->header->Width * 4;
+ buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "torgb32buf");
+ if (!buf) {
+ return NULL;
+ }
memset(buf, 255, *size);
to = buf; from = buffer;
- i = movie->header->Height * movie->header->Width;
+ size_t i = (size_t)movie->header->Height * (size_t)movie->header->Width;
while (i--) {
memcpy(to, from, 3);
diff --git a/source/blender/avi/intern/avi_rgb32.h b/source/blender/avi/intern/avi_rgb32.h
index 523f9e795fd..a9373a69821 100644
--- a/source/blender/avi/intern/avi_rgb32.h
+++ b/source/blender/avi/intern/avi_rgb32.h
@@ -32,7 +32,7 @@
#ifndef __AVI_RGB32_H__
#define __AVI_RGB32_H__
-void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size);
-void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size);
+void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
+void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
#endif /* __AVI_RGB32_H__ */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 28be2b04c71..f7ebe85bcef 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -55,7 +55,7 @@ extern "C" {
/* Action Lib Stuff ----------------- */
/* Allocate a new bAction with the given name */
-struct bAction *add_empty_action(struct Main *bmain, const char name[]);
+struct bAction *BKE_action_add(struct Main *bmain, const char name[]);
void BKE_action_copy_data(struct Main *bmain, struct bAction *act_dst, const struct bAction *act_src, const int flag);
/* Allocate a copy of the given Action and all its data */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 8d326c6441c..ceb466ebdcd 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 2
+#define BLENDER_SUBVERSION 4
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index cb72f0859d5..b3122f8adb9 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -46,7 +46,7 @@ struct MFace;
typedef struct LinkNode BVHCache;
/**
- * struct that kepts basic information about a BVHTree build from a editmesh
+ * Struct that stores basic information about a BVHTree built from a edit-mesh.
*/
typedef struct BVHTreeFromEditMesh {
struct BVHTree *tree;
@@ -66,7 +66,7 @@ typedef struct BVHTreeFromEditMesh {
} BVHTreeFromEditMesh;
/**
- * struct that kepts basic information about a BVHTree build from a mesh
+ * Struct that stores basic information about a BVHTree built from a mesh.
*/
typedef struct BVHTreeFromMesh {
struct BVHTree *tree;
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index f69ac7e01cd..d5bf2177f71 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -39,6 +39,7 @@ extern "C" {
#include "DNA_vec_types.h"
struct Camera;
+struct Depsgraph;
struct Main;
struct Object;
struct RegionView3D;
@@ -113,7 +114,7 @@ typedef struct CameraParams {
void BKE_camera_params_init(CameraParams *params);
void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera);
-void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d);
+void BKE_camera_params_from_view3d(CameraParams *params, const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d);
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy);
void BKE_camera_params_compute_matrix(CameraParams *params);
diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h
new file mode 100644
index 00000000000..edb724d2aec
--- /dev/null
+++ b/source/blender/blenkernel/BKE_colorband.h
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_COLORBAND_H__
+#define __BKE_COLORBAND_H__
+
+/** \file BKE_colorband.h
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ColorBand;
+
+/* in ColorBand struct */
+#define MAXCOLORBAND 32
+
+void BKE_colorband_init(struct ColorBand *coba, bool rangetype);
+void BKE_colorband_init_from_table_rgba(
+ struct ColorBand *coba, const float (*array)[4], const int array_len, bool filter_sample);
+struct ColorBand *BKE_colorband_add(bool rangetype);
+bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4]);
+void BKE_colorband_evaluate_table_rgba(const struct ColorBand *coba, float **array, int *size);
+struct CBData *BKE_colorband_element_add(struct ColorBand *coba, float position);
+int BKE_colorband_element_remove(struct ColorBand *coba, int index);
+void BKE_colorband_update_sort(struct ColorBand *coba);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_COLORBAND_H__ */
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 31d26d5d4fa..3d53f28c185 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -118,7 +118,8 @@ enum {
CTX_MODE_PAINT_VERTEX,
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
- CTX_MODE_OBJECT
+ CTX_MODE_OBJECT,
+ CTX_MODE_NUM /* must be last */
};
/* Context */
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index 60ad061bf77..e5eea4423c9 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -86,7 +86,7 @@ struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath);
void BKE_vfont_make_local(struct Main *bmain, struct VFont *vfont, const bool lib_local);
-bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode,
+bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, struct Curve *cu, int mode,
struct ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
struct CharTrans **r_chartransdata);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index 1045fde0039..f7368683d93 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -49,7 +49,7 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings;
/* FreestyleConfig */
void BKE_freestyle_config_init(FreestyleConfig *config);
-void BKE_freestyle_config_free(FreestyleConfig *config);
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user);
void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag);
/* FreestyleConfig.modules */
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index ac436876dc4..74255cfc941 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -55,10 +55,17 @@ bool BKE_group_is_animated(struct Group *group, struct Object *parent);
void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *parent, struct Group *group);
+/* Dependency graph evaluation. */
+
+void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx,
+ struct Group *group);
+
+/* Helper macros. */
+
#define FOREACH_GROUP_BASE(_group, _base) \
for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \
_base; \
- _base = _base->next) \
+ _base = _base->next) \
{
#define FOREACH_GROUP_BASE_END \
@@ -67,7 +74,7 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext
#define FOREACH_GROUP_OBJECT(_group, _object) \
for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \
_base; \
- _base = _base->next) \
+ _base = _base->next) \
{ \
Object *_object = _base->object; \
BLI_assert(_object != NULL);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 055c530d255..02912739e86 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -32,6 +32,10 @@
#include "BLI_compiler_attrs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct IDProperty;
struct ID;
@@ -119,6 +123,8 @@ void IDP_ClearProperty(IDProperty *prop);
void IDP_RelinkProperty(struct IDProperty *prop);
+void IDP_Reset(IDProperty *prop, const IDProperty *reference);
+
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Array(prop) ((prop)->data.pointer)
/* C11 const correctness for casts */
@@ -151,4 +157,8 @@ void IDP_RelinkProperty(struct IDProperty *prop);
void IDP_spit(IDProperty *prop);
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_IDPROP_H__ */
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index 56b72282513..aa655c66477 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -46,7 +46,7 @@ void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
void BKE_lamp_copy_data(struct Main *bmain, struct Lamp *la_dst, const struct Lamp *la_src, const int flag);
struct Lamp *BKE_lamp_copy(struct Main *bmain, const struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
-struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
+struct Lamp *BKE_lamp_localize(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local);
void BKE_lamp_free(struct Lamp *la);
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index e4f8b8790f6..b605b208f66 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -33,7 +33,6 @@
extern "C" {
#endif
-#define TODO_LAYER_SYNC_FILTER /* syncing of filter_objects across all trees */
#define TODO_LAYER_OVERRIDE /* CollectionOverride */
#define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */
#define TODO_LAYER /* generic todo */
@@ -66,6 +65,7 @@ struct ViewLayer *BKE_view_layer_group_add(struct Group *group);
struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
void BKE_view_layer_free(struct ViewLayer *view_layer);
+void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user);
void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
@@ -102,7 +102,6 @@ struct LayerCollection *BKE_collection_link(struct ViewLayer *view_layer, struct
void BKE_collection_unlink(struct ViewLayer *view_layer, struct LayerCollection *lc);
void BKE_collection_enable(struct ViewLayer *view_layer, struct LayerCollection *lc);
-void BKE_collection_disable(struct ViewLayer *view_layer, struct LayerCollection *lc);
bool BKE_view_layer_has_collection(struct ViewLayer *view_layer, const struct SceneCollection *sc);
bool BKE_scene_has_object(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 0abf99415c7..f3df8b9b363 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -51,9 +51,9 @@ struct PointerRNA;
struct PropertyRNA;
size_t BKE_libblock_get_alloc_info(short type, const char **name);
-void *BKE_libblock_alloc_notest(short type);
-void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BKE_libblock_init_empty(struct ID *id);
+void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
+void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
/**
* New ID creation/copying options.
diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h
index 1ba009660f2..35672cb5ded 100644
--- a/source/blender/blenkernel/BKE_library_override.h
+++ b/source/blender/blenkernel/BKE_library_override.h
@@ -43,7 +43,8 @@ void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id);
void BKE_override_static_clear(struct IDOverrideStatic *override);
void BKE_override_static_free(struct IDOverrideStatic **override);
-struct ID *BKE_override_static_create_from(struct Main *bmain, struct ID *reference_id);
+struct ID *BKE_override_static_create_from_id(struct Main *bmain, struct ID *reference_id);
+bool BKE_override_static_create_from_tag(struct Main *bmain);
struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path);
struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index faa91fd4f79..79f56cf25ef 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -147,7 +147,8 @@ typedef struct Main {
#define BLEN_THUMB_SIZE 128
-#define BLEN_THUMB_MEMSIZE(_x, _y) (sizeof(BlendThumbnail) + (size_t)((_x) * (_y)) * sizeof(int))
+#define BLEN_THUMB_MEMSIZE(_x, _y) (sizeof(BlendThumbnail) + ((size_t)(_x) * (size_t)(_y)) * sizeof(int))
+#define BLEN_THUMB_SAFE_MEMSIZE(_x, _y) ((uint64_t)_x * (uint64_t)_y < (SIZE_MAX / (sizeof(int) * 4)))
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 5598f0dc473..8b9fea071b0 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -145,7 +145,6 @@ void BKE_mask_update_display(struct Mask *mask, float ctime);
void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const bool do_newframe);
void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
-void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene);
void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u);
void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline, struct MaskSplinePoint *point, float t[2]);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index cb4ee9c2543..f4c98fc0aea 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -56,7 +56,7 @@ void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_sr
struct Material *BKE_material_add(struct Main *bmain, const char *name);
void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
-struct Material *localize_material(struct Material *ma);
+struct Material *BKE_material_localize(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 0bdff3eb795..bd193b82b9e 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -74,8 +74,8 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, stru
void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip, struct ImBuf *ibuf, struct MovieDistortion *distortion,
int cfra, int *build_sizes, int build_count, bool undistorted);
-float BKE_movieclip_remap_scene_to_clip_frame(struct MovieClip *clip, float framenr);
-float BKE_movieclip_remap_clip_to_scene_frame(struct MovieClip *clip, float framenr);
+float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr);
+float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr);
void BKE_movieclip_filename_for_frame(struct MovieClip *clip, struct MovieClipUser *user, char *name);
struct ImBuf *BKE_movieclip_anim_ibuf_for_frame(struct MovieClip *clip, struct MovieClipUser *user);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 39535ffd403..4e30cb076d4 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -448,6 +448,7 @@ struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree, struct bNode
struct bNodeSocket *next_sock, const char *identifier, const char *name);
void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node);
+void nodeModifySocketType(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, int type, int subtype);
struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname);
struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type);
@@ -514,7 +515,7 @@ int BKE_node_clipboard_get_type(void);
/* Node Instance Hash */
typedef struct bNodeInstanceHash {
- GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */
+ GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */
} bNodeInstanceHash;
typedef void (*bNodeInstanceValueFP)(void *value);
@@ -799,6 +800,7 @@ struct ShadeResult;
#define SH_NODE_BSDF_PRINCIPLED 193
#define SH_NODE_EEVEE_SPECULAR 195
#define SH_NODE_BEVEL 197
+#define SH_NODE_DISPLACEMENT 198
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 2b183906f57..d98c52aa91a 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -82,7 +82,14 @@ bool BKE_object_exists_check(struct Object *obtest);
bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(struct Object *ob);
-bool BKE_object_is_visible(struct Object *ob);
+
+typedef enum eObjectVisibilityCheck {
+ OB_VISIBILITY_CHECK_FOR_VIEWPORT,
+ OB_VISIBILITY_CHECK_FOR_RENDER,
+ OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE,
+} eObjectVisibilityCheck;
+
+bool BKE_object_is_visible(struct Object *ob, const eObjectVisibilityCheck mode);
void BKE_object_init(struct Object *ob);
struct Object *BKE_object_add_only_object(
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 31f4695201c..b952859e508 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -157,7 +157,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
unsigned x, unsigned y);
/* stroke related */
-void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]);
+bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]);
void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation);
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
@@ -196,6 +196,7 @@ typedef struct SculptSession {
/* PBVH acceleration structure */
struct PBVH *pbvh;
bool show_diffuse_color;
+ bool show_mask;
/* Painting on deformed mesh */
bool modifiers_active; /* object is deformed with some modifiers */
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 1776872f455..8bc521c515f 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -246,7 +246,8 @@ typedef struct ParticleDrawData {
float *cdata, *cd; /* color data */
float *vedata, *ved; /* velocity data */
float *ma_col;
- int tot_vec_size, flag;
+ int totpart, partsize;
+ int flag;
int totpoint, totve;
} ParticleDrawData;
@@ -326,7 +327,7 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P
struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name);
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
-struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
+struct ParticleSettings *BKE_particlesettings_add(struct Main *main, const char *name);
void BKE_particlesettings_copy_data(
struct Main *bmain, struct ParticleSettings *part_dst, const struct ParticleSettings *part_src,
const int flag);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 9aea5dc95a0..5f37aa25de7 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -375,5 +375,6 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
bool pbvh_has_mask(PBVH *bvh);
void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color);
+void pbvh_show_mask_set(PBVH *bvh, bool show_mask);
#endif /* __BKE_PBVH_H__ */
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 92170325113..96320415b16 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -34,6 +34,9 @@
/* struct DerivedMesh is used directly */
#include "BKE_DerivedMesh.h"
+/* Thread sync primitives used directly. */
+#include "BLI_threads.h"
+
struct CCGElem;
struct DMFlagMat;
struct DMGridAdjacency;
@@ -140,6 +143,9 @@ typedef struct CCGDerivedMesh {
} multires;
struct EdgeHash *ehash;
+
+ ThreadMutex loops_cache_lock;
+ ThreadRWMutex origindex_cache_rwlock;
} CCGDerivedMesh;
#ifdef WITH_OPENSUBDIV
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 8a9171673ea..4e98852c995 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -60,14 +60,6 @@ struct World;
#define MAXCOLORBAND 32
-void init_colorband(struct ColorBand *coba, bool rangetype);
-struct ColorBand *add_colorband(bool rangetype);
-bool do_colorband(const struct ColorBand *coba, float in, float out[4]);
-void colorband_table_RGBA(struct ColorBand *coba, float **array, int *size);
-struct CBData *colorband_element_add(struct ColorBand *coba, float position);
-int colorband_element_remove(struct ColorBand *coba, int index);
-void colorband_update_sort(struct ColorBand *coba);
-
void BKE_texture_free(struct Tex *tex);
void BKE_texture_default(struct Tex *tex);
void BKE_texture_copy_data(struct Main *bmain, struct Tex *tex_dst, const struct Tex *tex_src, const int flag);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index b4ca1b79238..5da87de1cc9 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -289,6 +289,46 @@ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking);
void BKE_tracking_dopesheet_update(struct MovieTracking *tracking);
+/* **** Query/search **** */
+
+struct MovieTrackingObject *BKE_tracking_find_object_for_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track);
+struct ListBase *BKE_tracking_find_tracks_list_for_track(
+ struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track);
+
+struct MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track);
+struct ListBase *BKE_tracking_find_tracks_list_for_plane_track(
+ struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track);
+
+
+void BKE_tracking_get_rna_path_for_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track,
+ char *rna_path,
+ size_t rna_path_len);
+void BKE_tracking_get_rna_path_prefix_for_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track,
+ char *rna_path,
+ size_t rna_path_len);
+void BKE_tracking_get_rna_path_for_plane_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track,
+ char *rna_path,
+ size_t rna_path_len);
+void BKE_tracking_get_rna_path_prefix_for_plane_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track,
+ char *rna_path,
+ size_t rna_path_len);
+
+/* **** Utility macros **** */
+
#define TRACK_SELECTED(track) ((track)->flag & SELECT || (track)->pat_flag & SELECT || (track)->search_flag & SELECT)
#define TRACK_AREA_SELECTED(track, area) ((area) == TRACK_AREA_POINT ? (track)->flag & SELECT : \
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index ea0cd125b06..b45d7a7e6ec 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -38,10 +38,10 @@ struct World;
void BKE_world_free(struct World *sc);
void BKE_world_init(struct World *wrld);
-struct World *add_world(struct Main *bmian, const char *name);
+struct World *BKE_world_add(struct Main *bmain, const char *name);
void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struct World *wrld_src, const int flag);
struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld);
-struct World *localize_world(struct World *wrld);
+struct World *BKE_world_localize(struct World *wrld);
void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
/* Evaluation. */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c99c3d6ffa9..279068c440e 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -89,6 +89,7 @@ set(SRC
intern/cloth.c
intern/collection.c
intern/collision.c
+ intern/colorband.c
intern/colortools.c
intern/constraint.c
intern/context.c
@@ -225,6 +226,7 @@ set(SRC
BKE_cloth.h
BKE_collection.h
BKE_collision.h
+ BKE_colorband.h
BKE_colortools.h
BKE_constraint.h
BKE_context.h
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index 4c913e79586..8cdbd2a7a98 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -73,6 +73,9 @@ typedef enum {
#define CCG_OMP_LIMIT 1000000
+/* TODO(sergey): This actually depends on subsurf level as well. */
+#define CCG_TASK_LIMIT 16
+
/***/
CCGSubSurf* ccgSubSurf_new (CCGMeshIFC *ifc, int subdivisionLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator);
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index f68d1a2697c..756935b50ba 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -136,7 +136,10 @@ typedef struct CCGSubSurfCalcSubdivData {
int curLvl;
} CCGSubSurfCalcSubdivData;
-static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(void *userdata, int ptrIdx)
+static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(
+ void *__restrict userdata,
+ const int ptrIdx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGSubSurfCalcSubdivData *data = userdata;
@@ -227,7 +230,10 @@ static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(void *userdata, int
}
}
-static void ccgSubSurf__calcVertNormals_faces_finalize_cb(void *userdata, int ptrIdx)
+static void ccgSubSurf__calcVertNormals_faces_finalize_cb(
+ void *__restrict userdata,
+ const int ptrIdx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGSubSurfCalcSubdivData *data = userdata;
@@ -265,7 +271,10 @@ static void ccgSubSurf__calcVertNormals_faces_finalize_cb(void *userdata, int pt
}
}
-static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(void *userdata, int ptrIdx)
+static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(
+ void *__restrict userdata,
+ const int ptrIdx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGSubSurfCalcSubdivData *data = userdata;
@@ -328,10 +337,15 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
.numEffectedF = numEffectedF
};
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcVertNormals_faces_accumulate_cb,
- numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcVertNormals_faces_accumulate_cb,
+ &settings);
+ }
/* XXX can I reduce the number of normalisations here? */
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
@@ -357,15 +371,25 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
}
}
- BLI_task_parallel_range(0, numEffectedE,
- &data,
- ccgSubSurf__calcVertNormals_edges_accumulate_cb,
- numEffectedE * edgeSize * 4 >= CCG_OMP_LIMIT);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0, numEffectedE,
+ &data,
+ ccgSubSurf__calcVertNormals_edges_accumulate_cb,
+ &settings);
+ }
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcVertNormals_faces_finalize_cb,
- numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcVertNormals_faces_finalize_cb,
+ &settings);
+ }
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
@@ -396,7 +420,10 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
}
-static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(void *userdata, int ptrIdx)
+static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(
+ void *__restrict userdata,
+ const int ptrIdx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGSubSurfCalcSubdivData *data = userdata;
@@ -483,7 +510,10 @@ static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(void *
}
}
-static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(void *userdata, int ptrIdx)
+static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(
+ void *__restrict userdata,
+ const int ptrIdx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGSubSurfCalcSubdivData *data = userdata;
@@ -588,7 +618,10 @@ static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_
}
}
-static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(void *userdata, int ptrIdx)
+static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(
+ void *__restrict userdata,
+ const int ptrIdx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CCGSubSurfCalcSubdivData *data = userdata;
@@ -647,10 +680,15 @@ static void ccgSubSurf__calcSubdivLevel(
.curLvl = curLvl
};
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb,
- numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb,
+ &settings);
+ }
/* exterior edge midpoints
* - old exterior edge points
@@ -925,10 +963,15 @@ static void ccgSubSurf__calcSubdivLevel(
}
}
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb,
- numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb,
+ &settings);
+ }
/* copy down */
edgeSize = ccg_edgesize(nextLvl);
@@ -940,10 +983,15 @@ static void ccgSubSurf__calcSubdivLevel(
VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss);
}
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcSubdivLevel_verts_copydata_cb,
- numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_verts_copydata_cb,
+ &settings);
+ }
}
void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 1367157c13c..cfeca50a751 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -52,6 +52,7 @@
#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_colorband.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -64,7 +65,6 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
-#include "BKE_texture.h"
#include "BKE_multires.h"
#include "BKE_bvhutils.h"
#include "BKE_deform.h"
@@ -187,7 +187,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm)
static MVert *dm_dupVertArray(DerivedMesh *dm)
{
- MVert *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumVerts(dm),
+ MVert *tmp = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(*tmp),
"dm_dupVertArray tmp");
if (tmp) dm->copyVertArray(dm, tmp);
@@ -197,7 +197,7 @@ static MVert *dm_dupVertArray(DerivedMesh *dm)
static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
{
- MEdge *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumEdges(dm),
+ MEdge *tmp = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(*tmp),
"dm_dupEdgeArray tmp");
if (tmp) dm->copyEdgeArray(dm, tmp);
@@ -207,7 +207,7 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
static MFace *dm_dupFaceArray(DerivedMesh *dm)
{
- MFace *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumTessFaces(dm),
+ MFace *tmp = MEM_malloc_arrayN(dm->getNumTessFaces(dm), sizeof(*tmp),
"dm_dupFaceArray tmp");
if (tmp) dm->copyTessFaceArray(dm, tmp);
@@ -217,7 +217,7 @@ static MFace *dm_dupFaceArray(DerivedMesh *dm)
static MLoop *dm_dupLoopArray(DerivedMesh *dm)
{
- MLoop *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumLoops(dm),
+ MLoop *tmp = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(*tmp),
"dm_dupLoopArray tmp");
if (tmp) dm->copyLoopArray(dm, tmp);
@@ -227,7 +227,7 @@ static MLoop *dm_dupLoopArray(DerivedMesh *dm)
static MPoly *dm_dupPolyArray(DerivedMesh *dm)
{
- MPoly *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumPolys(dm),
+ MPoly *tmp = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(*tmp),
"dm_dupPolyArray tmp");
if (tmp) dm->copyPolyArray(dm, tmp);
@@ -529,7 +529,7 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
if (totpoly) {
if (dm->looptris.array_wip == NULL) {
- dm->looptris.array_wip = MEM_mallocN(sizeof(*dm->looptris.array_wip) * looptris_num, __func__);
+ dm->looptris.array_wip = MEM_malloc_arrayN(looptris_num, sizeof(*dm->looptris.array_wip), __func__);
dm->looptris.num_alloc = looptris_num;
}
@@ -577,7 +577,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
CustomData_has_layer(fdata, CD_TESSLOOPNORMAL) ||
CustomData_has_layer(fdata, CD_TANGENT))
{
- loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
+ loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
const int mf_len = mf->v4 ? 4 : 3;
@@ -637,7 +637,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
CustomData_bmesh_update_active_layers(fdata, ldata);
if (!loopindex) {
- loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
+ loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
const int mf_len = mf->v4 ? 4 : 3;
unsigned int *ml_idx = loopindex[mf_idx];
@@ -682,7 +682,7 @@ void DM_update_materials(DerivedMesh *dm, Object *ob)
if (dm->mat)
MEM_freeN(dm->mat);
- dm->mat = MEM_mallocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
+ dm->mat = MEM_malloc_arrayN(totmat, sizeof(*dm->mat), "DerivedMesh.mat");
}
/* we leave last material as empty - rationale here is being able to index
@@ -872,7 +872,7 @@ void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb)
}
if (kb->data) MEM_freeN(kb->data);
- kb->data = MEM_mallocN(me->key->elemsize * me->totvert, "kb->data");
+ kb->data = MEM_malloc_arrayN(me->key->elemsize, me->totvert, "kb->data");
kb->totelem = totvert;
fp = kb->data;
@@ -1208,7 +1208,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
/* these may not really be the orco's, but it's only for preview.
* could be solver better once, but isn't simple */
- orco = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "BMEditMesh Orco");
+ orco = MEM_malloc_arrayN(em->bm->totvert, sizeof(float) * 3, "BMEditMesh Orco");
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(orco[i], eve->co);
@@ -1282,7 +1282,7 @@ static void add_orco_dm(
totvert = dm->getNumVerts(dm);
if (orcodm) {
- orco = MEM_callocN(sizeof(float[3]) * totvert, "dm orco");
+ orco = MEM_calloc_arrayN(totvert, sizeof(float[3]), "dm orco");
free = 1;
if (orcodm->getNumVerts(orcodm) == totvert)
@@ -1379,7 +1379,7 @@ static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcin
float colf[4];
if (dm_wcinfo && dm_wcinfo->coba) {
- do_colorband(dm_wcinfo->coba, input, colf);
+ BKE_colorband_evaluate(dm_wcinfo->coba, input, colf);
}
else {
weight_to_rgb(colf, input);
@@ -1564,7 +1564,7 @@ void DM_update_weight_mcol(
wtcol_v = em->derivedVertColor;
}
else {
- wtcol_v = MEM_mallocN(sizeof(*wtcol_v) * numVerts, __func__);
+ wtcol_v = MEM_malloc_arrayN(numVerts, sizeof(*wtcol_v), __func__);
}
/* Weights are given by caller. */
@@ -1573,7 +1573,7 @@ void DM_update_weight_mcol(
/* If indices is not NULL, it means we do not have weights for all vertices,
* so we must create them (and set them to zero)... */
if (indices) {
- w = MEM_callocN(sizeof(float) * numVerts, "Temp weight array DM_update_weight_mcol");
+ w = MEM_calloc_arrayN(numVerts, sizeof(float), "Temp weight array DM_update_weight_mcol");
i = num;
while (i--)
w[indices[i]] = weights[i];
@@ -1605,7 +1605,7 @@ void DM_update_weight_mcol(
/* now add to loops, so the data can be passed through the modifier stack
* If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
if (!wtcol_l) {
- wtcol_l = MEM_mallocN(sizeof(*wtcol_l) * dm_totloop, __func__);
+ wtcol_l = MEM_malloc_arrayN(dm_totloop, sizeof(*wtcol_l), __func__);
CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, dm_totloop);
}
@@ -1660,7 +1660,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i);
kb->totelem = dm->numVertData;
- kb->data = kbcos = MEM_mallocN(sizeof(float) * 3 * kb->totelem, "kbcos DerivedMesh.c");
+ kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, sizeof(float), "kbcos DerivedMesh.c");
if (kb->uid == actshape_uid) {
MVert *mvert = dm->getVertArray(dm);
@@ -1681,7 +1681,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
MEM_freeN(kb->data);
kb->totelem = dm->numVertData;
- kb->data = MEM_callocN(sizeof(float) * 3 * kb->totelem, "kb->data derivedmesh.c");
+ kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), "kb->data derivedmesh.c");
fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name);
}
}
@@ -1692,7 +1692,6 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
KeyBlock *kb;
Key *key = me->key;
int i;
- const size_t shape_alloc_len = sizeof(float) * 3 * me->totvert;
if (!me->key)
return;
@@ -1713,11 +1712,11 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
fprintf(stderr,
"%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n",
__func__, me->id.name + 2, me->totvert, kb->name, kb->totelem);
- array = MEM_callocN(shape_alloc_len, __func__);
+ array = MEM_calloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__);
}
else {
- array = MEM_mallocN(shape_alloc_len, __func__);
- memcpy(array, kb->data, shape_alloc_len);
+ array = MEM_malloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__);
+ memcpy(array, kb->data, (size_t)me->totvert * 3 * sizeof(float));
}
CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_ASSIGN, array, dm->numVertData, kb->name);
@@ -1990,7 +1989,7 @@ static void mesh_calc_modifiers(
*/
numVerts = dm->getNumVerts(dm);
deformedVerts =
- MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
+ MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
dm->getVertCos(dm, deformedVerts);
}
else {
@@ -2283,7 +2282,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
*r_numVerts = em->bm->totvert;
- cos = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "vertexcos");
+ cos = MEM_malloc_arrayN(em->bm->totvert, 3 * sizeof(float), "vertexcos");
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(cos[i], eve->co);
@@ -2389,7 +2388,7 @@ static void editbmesh_calc_modifiers(
*/
numVerts = dm->getNumVerts(dm);
deformedVerts =
- MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
+ MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
dm->getVertCos(dm, deformedVerts);
}
else {
@@ -3010,11 +3009,11 @@ DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
if (dm->foreachMappedVert) {
- vertexcosnos = MEM_callocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map");
+ vertexcosnos = MEM_calloc_arrayN(me->totvert, sizeof(DMCoNo), "vertexcosnos map");
dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos);
}
else {
- DMCoNo *v_co_no = vertexcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map");
+ DMCoNo *v_co_no = vertexcosnos = MEM_malloc_arrayN(me->totvert, sizeof(DMCoNo), "vertexcosnos map");
int a;
for (a = 0; a < me->totvert; a++, v_co_no++) {
dm->getVertCo(dm, a, v_co_no->co);
@@ -3907,7 +3906,7 @@ MVert *DM_get_vert_array(DerivedMesh *dm, bool *allocated)
*allocated = false;
if (mvert == NULL) {
- mvert = MEM_mallocN(sizeof(MVert) * dm->getNumVerts(dm), "dmvh vert data array");
+ mvert = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(MVert), "dmvh vert data array");
dm->copyVertArray(dm, mvert);
*allocated = true;
}
@@ -3922,7 +3921,7 @@ MEdge *DM_get_edge_array(DerivedMesh *dm, bool *allocated)
*allocated = false;
if (medge == NULL) {
- medge = MEM_mallocN(sizeof(MEdge) * dm->getNumEdges(dm), "dm medge data array");
+ medge = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(MEdge), "dm medge data array");
dm->copyEdgeArray(dm, medge);
*allocated = true;
}
@@ -3937,7 +3936,7 @@ MLoop *DM_get_loop_array(DerivedMesh *dm, bool *r_allocated)
*r_allocated = false;
if (mloop == NULL) {
- mloop = MEM_mallocN(sizeof(MLoop) * dm->getNumLoops(dm), "dm loop data array");
+ mloop = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(MLoop), "dm loop data array");
dm->copyLoopArray(dm, mloop);
*r_allocated = true;
}
@@ -3952,7 +3951,7 @@ MPoly *DM_get_poly_array(DerivedMesh *dm, bool *r_allocated)
*r_allocated = false;
if (mpoly == NULL) {
- mpoly = MEM_mallocN(sizeof(MPoly) * dm->getNumPolys(dm), "dm poly data array");
+ mpoly = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(MPoly), "dm poly data array");
dm->copyPolyArray(dm, mpoly);
*r_allocated = true;
}
@@ -3970,7 +3969,7 @@ MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated)
int numTessFaces = dm->getNumTessFaces(dm);
if (numTessFaces > 0) {
- mface = MEM_mallocN(sizeof(MFace) * numTessFaces, "bvh mface data array");
+ mface = MEM_malloc_arrayN(numTessFaces, sizeof(MFace), "bvh mface data array");
dm->copyTessFaceArray(dm, mface);
*r_allocated = true;
}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 88c0aa6f35a..acb2db8d7ad 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -85,7 +85,7 @@
/* ***************** Library data level operations on action ************** */
-bAction *add_empty_action(Main *bmain, const char name[])
+bAction *BKE_action_add(Main *bmain, const char name[])
{
bAction *act;
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 07de2ad6342..844a2a50bb3 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -75,6 +75,8 @@
#include "nla_private.h"
+#include "atomic_ops.h"
+
/* ***************************************** */
/* AnimData API */
@@ -527,7 +529,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths
if (srcAdt->action) {
/* set up an action if necessary, and name it in a similar way so that it can be easily found again */
if (dstAdt->action == NULL) {
- dstAdt->action = add_empty_action(G.main, srcAdt->action->id.name + 2);
+ dstAdt->action = BKE_action_add(G.main, srcAdt->action->id.name + 2);
}
else if (dstAdt->action == srcAdt->action) {
printf("Argh! Source and Destination share animation! ('%s' and '%s' both use '%s') Making new empty action\n",
@@ -535,7 +537,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths
/* TODO: review this... */
id_us_min(&dstAdt->action->id);
- dstAdt->action = add_empty_action(G.main, dstAdt->action->id.name + 2);
+ dstAdt->action = BKE_action_add(G.main, dstAdt->action->id.name + 2);
}
/* loop over base paths, trying to fix for each one... */
@@ -818,7 +820,7 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *
/* if no action, no need to proceed */
if (ELEM(NULL, owner_id, old_path)) {
- printf("early abort\n");
+ if (G.debug & G_DEBUG) printf("%s: early abort\n", __func__);
return old_path;
}
@@ -841,9 +843,9 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *
}
/* fix given path */
- printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
+ if (G.debug & G_DEBUG) 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);
+ if (G.debug & G_DEBUG) printf("path rename result = %p\n", result);
/* free the temp names */
MEM_freeN(oldN);
@@ -1563,12 +1565,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* caller must ensure this is animatable */
BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
- /* set value for animatable numerical values only
- * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
- * without an ID provided, which causes the animateable test to fail!
- */
- bool written = false;
-
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
{
@@ -1576,13 +1572,11 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
if (array_index != -1) {
if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) {
RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
- written = true;
}
}
else {
if (RNA_property_boolean_get(ptr, prop) != value_coerce) {
RNA_property_boolean_set(ptr, prop, value_coerce);
- written = true;
}
}
break;
@@ -1594,13 +1588,11 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
if (array_index != -1) {
if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) {
RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
- written = true;
}
}
else {
if (RNA_property_int_get(ptr, prop) != value_coerce) {
RNA_property_int_set(ptr, prop, value_coerce);
- written = true;
}
}
break;
@@ -1612,13 +1604,11 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
if (array_index != -1) {
if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) {
RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
- written = true;
}
}
else {
if (RNA_property_float_get(ptr, prop) != value_coerce) {
RNA_property_float_set(ptr, prop, value_coerce);
- written = true;
}
}
break;
@@ -1628,7 +1618,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
const int value_coerce = (int)value;
if (RNA_property_enum_get(ptr, prop) != value_coerce) {
RNA_property_enum_set(ptr, prop, value_coerce);
- written = true;
}
break;
}
@@ -1657,20 +1646,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
}
#endif
- /* as long as we don't do property update, we still tag datablock
- * as having been updated. this flag does not cause any updates to
- * be run, it's for e.g. render engines to synchronize data */
- if (written && ptr->id.data) {
- ID *id = ptr->id.data;
-
- /* for cases like duplifarmes it's only a temporary so don't
- * notify anyone of updates */
- if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC);
- DEG_id_type_tag(G.main, GS(id->name));
- }
- }
-
/* successful */
return true;
}
@@ -2614,17 +2589,6 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
/* 3. free temporary evaluation data that's not used elsewhere */
BLI_freelistN(&estrips);
-
- /* Tag ID as updated so render engines will recognize changes in data
- * which is animated but doesn't have actions.
- */
- if (ptr->id.data != NULL) {
- ID *id = ptr->id.data;
- if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- id->tag |= LIB_TAG_ID_RECALC;
- DEG_id_type_tag(G.main, GS(id->name));
- }
- }
}
/* NLA Evaluation function (mostly for use through do_animdata)
@@ -2921,7 +2885,7 @@ void BKE_animsys_eval_animdata(const EvaluationContext *eval_ctx, ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
- * which should get handled as part of the graph instead...
+ * which should get handled as part of the dependency graph instead...
*/
DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime);
BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 50764e10ceb..182b88c1c57 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -247,7 +247,6 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *userdef_b)
{
/* TODO:
- * - keymaps
* - various minor settings (add as needed).
*/
@@ -263,9 +262,15 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
SWAP(ListBase, userdef_a->id, userdef_b->id); \
} ((void)0)
- /* for some types we need custom free functions */
- LIST_SWAP(addons);
- LIST_SWAP(user_keymaps);
+#define FLAG_SWAP(id, ty, flags) { \
+ CHECK_TYPE(&(userdef_a->id), ty *); \
+ const ty f = flags; \
+ const ty a = userdef_a->id; \
+ const ty b = userdef_b->id; \
+ userdef_a->id = (userdef_a->id & ~f) | (b & f); \
+ userdef_b->id = (userdef_b->id & ~f) | (a & f); \
+} ((void)0)
+
LIST_SWAP(uistyles);
LIST_SWAP(uifonts);
@@ -277,10 +282,18 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
DATA_SWAP(font_path_ui);
DATA_SWAP(font_path_ui_mono);
+ DATA_SWAP(keyconfigstr);
+
+ DATA_SWAP(manipulator_flag);
+ DATA_SWAP(app_flag);
+
+ /* We could add others. */
+ FLAG_SWAP(uiflag, int, USER_QUIT_PROMPT);
#undef SWAP_TYPELESS
-#undef LIST_SWAP
#undef DATA_SWAP
+#undef LIST_SWAP
+#undef FLAG_SWAP
}
void BKE_blender_userdef_app_template_data_set(UserDef *userdef)
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 230db6dccff..8d63c1cfb44 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -148,6 +148,9 @@ void BKE_brush_init(Brush *brush)
BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
}
+/**
+ * \note Resulting brush will have two users: one as a fake user, another is assumed to be used by the caller.
+ */
Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
{
Brush *brush;
@@ -1063,7 +1066,8 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
for (i = 0; i < side; ++i) {
for (j = 0; j < side; ++j) {
const int col = texcache[i * side + j];
- im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] + ((char *)&col)[2]) / 3.0f / 255.0f;
+ im->rect_float[i * side + j] *=
+ (((char *)&col)[0] + ((char *)&col)[1] + ((char *)&col)[2]) / 3.0f / 255.0f;
}
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 4993caf14f1..869e312614e 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -57,6 +57,8 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "DEG_depsgraph_query.h"
+
#include "MEM_guardedalloc.h"
#include "GPU_compositing.h"
@@ -262,7 +264,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
}
}
-void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d)
+void BKE_camera_params_from_view3d(CameraParams *params, const Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d)
{
/* common */
params->lens = v3d->lens;
@@ -271,7 +273,8 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
if (rv3d->persp == RV3D_CAMOB) {
/* camera view */
- BKE_camera_params_from_object(params, v3d->camera);
+ Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_camera_params_from_object(params, camera_object);
params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index d1282c1a0fe..ea54548ab09 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -288,6 +288,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
ob->sculpt->cd_face_node_offset);
pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask);
}
@@ -303,7 +304,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
cddm->pbvh = BKE_pbvh_new();
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
- looptri = MEM_mallocN(sizeof(*looptri) * looptris_num, __func__);
+ looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
BKE_mesh_recalc_looptri(
me->mloop, me->mpoly,
@@ -318,6 +319,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
looptri, looptris_num);
pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask);
deformed = check_sculpt_object_deformed(ob, true);
@@ -327,7 +329,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
int totvert;
totvert = deformdm->getNumVerts(deformdm);
- vertCos = MEM_mallocN(totvert * sizeof(float[3]), "cdDM_getPBVH vertCos");
+ vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos);
MEM_freeN(vertCos);
@@ -891,9 +893,9 @@ static void cdDM_drawMappedFacesGLSL(
tot_active_mat = dm->drawObject->totmaterial;
- matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat,
+ matconv = MEM_calloc_arrayN(tot_active_mat, sizeof(*matconv),
"cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
+ mat_orig_to_new = MEM_malloc_arrayN(dm->totmat, sizeof(*mat_orig_to_new),
"cdDM_drawMappedFacesGLSL.mat_orig_to_new");
/* part one, check what attributes are needed per material */
@@ -1182,7 +1184,7 @@ static void cdDM_buffer_copy_triangles(
const MLoopTri *lt = dm->getLoopTriArray(dm);
const int totpoly = dm->getNumPolys(dm);
- FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount");
+ FaceCount *fc = MEM_malloc_arrayN(gpu_totmat, sizeof(*fc), "gpumaterial.facecount");
for (i = 0; i < gpu_totmat; i++) {
fc[i].i_visible = 0;
@@ -1363,7 +1365,7 @@ static void cdDM_buffer_copy_uv_texpaint(
/* should have been checked for before, reassert */
BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- uv_base = MEM_mallocN(totmaterial * sizeof(*uv_base), "texslots");
+ uv_base = MEM_malloc_arrayN(totmaterial, sizeof(*uv_base), "texslots");
for (i = 0; i < totmaterial; i++) {
uv_base[i] = DM_paint_uvlayer_active_get(dm, i);
@@ -1577,10 +1579,10 @@ static void cdDM_drawobject_init_vert_points(
int tot_loops = 0;
/* allocate the array and space for links */
- gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert,
+ gdo->vert_points = MEM_malloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
"GPUDrawObject.vert_points");
#ifdef USE_GPU_POINT_LINK
- gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->totvert,
+ gdo->vert_points_mem = MEM_calloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
"GPUDrawObject.vert_points_mem");
gdo->vert_points_usage = 0;
#endif
@@ -1635,7 +1637,7 @@ static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm)
/* get the number of points used by each material, treating
* each quad as two triangles */
- mat_info = MEM_callocN(sizeof(*mat_info) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new");
+ mat_info = MEM_calloc_arrayN(dm_totmat, sizeof(*mat_info), "GPU_drawobject_new.mat_orig_to_new");
for (i = 0; i < totpolys; i++) {
const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
@@ -2474,7 +2476,7 @@ void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals)
}
#endif
- face_nors = MEM_mallocN(sizeof(*face_nors) * dm->numPolyData, "face_nors");
+ face_nors = MEM_malloc_arrayN(dm->numPolyData, sizeof(*face_nors), "face_nors");
/* calculate face normals */
BKE_mesh_calc_normals_poly(
@@ -2855,31 +2857,31 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
const int totvert_final = totvert - tot_vtargetmap;
- MVert *mv, *mvert = MEM_mallocN(sizeof(*mvert) * totvert_final, __func__);
- int *oldv = MEM_mallocN(sizeof(*oldv) * totvert_final, __func__);
- int *newv = MEM_mallocN(sizeof(*newv) * totvert, __func__);
+ MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
+ int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
+ int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
STACK_DECLARE(mvert);
STACK_DECLARE(oldv);
/* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
* generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
* cases can be forged that would end requiring more... */
- MEdge *med, *medge = MEM_mallocN(sizeof(*medge) * (totedge + totloop), __func__);
- int *olde = MEM_mallocN(sizeof(*olde) * (totedge + totloop), __func__);
- int *newe = MEM_mallocN(sizeof(*newe) * (totedge + totloop), __func__);
+ MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
+ int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
+ int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
STACK_DECLARE(medge);
STACK_DECLARE(olde);
- MLoop *ml, *mloop = MEM_mallocN(sizeof(*mloop) * totloop, __func__);
- int *oldl = MEM_mallocN(sizeof(*oldl) * totloop, __func__);
+ MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
+ int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
#ifdef USE_LOOPS
- int newl = MEM_mallocN(sizeof(*newl) * totloop, __func__);
+ int newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
#endif
STACK_DECLARE(mloop);
STACK_DECLARE(oldl);
- MPoly *mp, *mpoly = MEM_mallocN(sizeof(*medge) * totpoly, __func__);
- int *oldp = MEM_mallocN(sizeof(*oldp) * totpoly, __func__);
+ MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
+ int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
STACK_DECLARE(mpoly);
STACK_DECLARE(oldp);
@@ -2957,7 +2959,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
/* if the targets already make up a poly, in which case the new poly is dropped */
/* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
PolyKey *mpgh;
- poly_keys = MEM_mallocN(sizeof(PolyKey) * totpoly, __func__);
+ poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
/* Duplicates allowed because our compare function is not pure equality */
BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 8d69563f5ff..ca77969ccaa 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -30,6 +30,7 @@
#include "BLI_ghash.h"
#include "BLI_iterator.h"
#include "BLI_listbase.h"
+#include "BLI_math_base.h"
#include "BLT_translation.h"
#include "BLI_string_utils.h"
@@ -50,6 +51,7 @@
#include "MEM_guardedalloc.h"
/* Prototypes. */
+static SceneCollection *find_collection_parent(const struct SceneCollection *sc_child, struct SceneCollection *sc_parent);
static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent);
static SceneCollection *collection_master_from_id(const ID *owner_id)
@@ -69,24 +71,40 @@ static SceneCollection *collection_master_from_id(const ID *owner_id)
* Add a collection to a collection ListBase and syncronize all render layers
* The ListBase is NULL when the collection is to be added to the master collection
*/
-SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name)
+SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom)
{
SceneCollection *sc_master = collection_master_from_id(owner_id);
SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection");
sc->type = type;
-
- if (!name) {
- name = DATA_("New Collection");
- }
+ const char *name = name_custom;
if (!sc_parent) {
sc_parent = sc_master;
}
- BKE_collection_rename((Scene *)owner_id, sc, name);
+ if (!name) {
+ if (sc_parent == sc_master) {
+ name = BLI_sprintfN("Collection %d", BLI_listbase_count(&sc_master->scene_collections) + 1);
+ }
+ else {
+ const int number = BLI_listbase_count(&sc_parent->scene_collections) + 1;
+ const int digits = integer_digits_i(number);
+ const int max_len = sizeof(sc_parent->name)
+ - 1 /* NULL terminator */
+ - (1 + digits) /* " %d" */;
+ name = BLI_sprintfN("%.*s %d", max_len, sc_parent->name, number);
+ }
+ }
+
BLI_addtail(&sc_parent->scene_collections, sc);
+ BKE_collection_rename((Scene *)owner_id, sc, name);
BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc);
+
+ if (name != name_custom) {
+ MEM_freeN((char *)name);
+ }
+
return sc;
}
@@ -99,13 +117,9 @@ static void collection_free(SceneCollection *sc, const bool do_id_user)
for (LinkData *link = sc->objects.first; link; link = link->next) {
id_us_min(link->data);
}
- for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
- id_us_min(link->data);
- }
}
BLI_freelistN(&sc->objects);
- BLI_freelistN(&sc->filter_objects);
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
collection_free(nsc, do_id_user);
@@ -164,6 +178,8 @@ static void layer_collection_remove(ViewLayer *view_layer, ListBase *lb, const S
/**
* Remove a collection from the scene, and syncronize all render layers
+ *
+ * If an object is in any other collection, link the object to the master collection.
*/
bool BKE_collection_remove(ID *owner_id, SceneCollection *sc)
{
@@ -174,11 +190,50 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc)
return false;
}
+ /* We need to do bottom up removal, otherwise we get a crash when we remove a collection that
+ * has one of its nested collections linked to a view layer. */
+ SceneCollection *scene_collection_nested = sc->scene_collections.first;
+ while (scene_collection_nested != NULL) {
+ SceneCollection *scene_collection_next = scene_collection_nested->next;
+ BKE_collection_remove(owner_id, scene_collection_nested);
+ scene_collection_nested = scene_collection_next;
+ }
+
/* Unlink from the respective collection tree. */
if (!collection_remlink(sc_master, sc)) {
BLI_assert(false);
}
+ /* If an object is no longer in any collection, we add it to the master collection. */
+ ListBase collection_objects;
+ BLI_duplicatelist(&collection_objects, &sc->objects);
+
+ FOREACH_SCENE_COLLECTION(owner_id, scene_collection_iter)
+ {
+ if (scene_collection_iter == sc) {
+ continue;
+ }
+
+ LinkData *link_next, *link = collection_objects.first;
+ while (link) {
+ link_next = link->next;
+
+ if (BLI_findptr(&scene_collection_iter->objects, link->data, offsetof(LinkData, data))) {
+ BLI_remlink(&collection_objects, link);
+ MEM_freeN(link);
+ }
+
+ link = link_next;
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END
+
+ for (LinkData *link = collection_objects.first; link; link = link->next) {
+ BKE_collection_object_add(owner_id, sc_master, link->data);
+ }
+
+ BLI_freelistN(&collection_objects);
+
/* Clear the collection items. */
collection_free(sc, true);
@@ -206,13 +261,6 @@ void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src,
}
}
- BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects);
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) {
- id_us_plus(link->data);
- }
- }
-
BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections);
for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first;
nsc_src;
@@ -243,38 +291,11 @@ SceneCollection *BKE_collection_master(const ID *owner_id)
return master_collection_from_id(owner_id);
}
-struct UniqueNameCheckData {
- ListBase *lb;
- SceneCollection *lookup_sc;
-};
-
-static bool collection_unique_name_check(void *arg, const char *name)
-{
- struct UniqueNameCheckData *data = arg;
-
- for (SceneCollection *sc = data->lb->first; sc; sc = sc->next) {
- struct UniqueNameCheckData child_data = {.lb = &sc->scene_collections, .lookup_sc = data->lookup_sc};
-
- if (sc != data->lookup_sc) {
- if (STREQ(sc->name, name)) {
- return true;
- }
- }
- if (collection_unique_name_check(&child_data, name)) {
- return true;
- }
- }
-
- return false;
-}
-
static void collection_rename(const ID *owner_id, SceneCollection *sc, const char *name)
{
- SceneCollection *sc_master = collection_master_from_id(owner_id);
- struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc};
-
+ SceneCollection *sc_parent = find_collection_parent(sc, collection_master_from_id(owner_id));
BLI_strncpy(sc->name, name, sizeof(sc->name));
- BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name));
+ BLI_uniquename(&sc_parent->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name));
}
void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name)
@@ -283,6 +304,15 @@ void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *
}
/**
+ * Make sure the collection name is still unique within its siblings.
+ */
+static void collection_name_check(const ID *owner_id, SceneCollection *sc)
+{
+ /* It's a bit of a hack, we simply try to make sure the collection name is valid. */
+ collection_rename(owner_id, sc, sc->name);
+}
+
+/**
* Free (or release) any data used by the master collection (does not free the master collection itself).
* Used only to clear the entire scene or group data since it's not doing re-syncing of the LayerCollection tree
*/
@@ -363,7 +393,6 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc
BLI_remlink(&sc->objects, link);
MEM_freeN(link);
- TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */
BKE_layer_sync_object_unlink(owner_id, sc, ob);
if (GS(owner_id->name) == ID_SCE) {
@@ -386,8 +415,9 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc
*/
void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob)
{
- BKE_collection_object_add(owner_id, sc_dst, ob);
- BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false);
+ if (BKE_collection_object_add(owner_id, sc_dst, ob)) {
+ BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false);
+ }
}
/**
@@ -556,6 +586,9 @@ bool BKE_collection_move_above(const ID *owner_id, SceneCollection *sc_dst, Scen
BKE_layer_collection_resync(owner_id, sc_src_parent);
BKE_layer_collection_resync(owner_id, sc_dst_parent);
+ /* Keep names unique. */
+ collection_name_check(owner_id, sc_src);
+
return true;
}
@@ -595,6 +628,9 @@ bool BKE_collection_move_below(const ID *owner_id, SceneCollection *sc_dst, Scen
BKE_layer_collection_resync(owner_id, sc_src_parent);
BKE_layer_collection_resync(owner_id, sc_dst_parent);
+ /* Keep names unique. */
+ collection_name_check(owner_id, sc_src);
+
return true;
}
@@ -630,6 +666,9 @@ bool BKE_collection_move_into(const ID *owner_id, SceneCollection *sc_dst, Scene
BKE_layer_collection_resync(owner_id, sc_src_parent);
BKE_layer_collection_resync(owner_id, sc_dst);
+ /* Keep names unique. */
+ collection_name_check(owner_id, sc_src);
+
return true;
}
@@ -699,6 +738,7 @@ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
data->owner_id = owner_id;
iter->data = data;
+ iter->valid = true;
scene_collections_array(owner_id, (SceneCollection ***)&data->array, &data->tot);
BLI_assert(data->tot != 0);
diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c
new file mode 100644
index 00000000000..d35e797ddac
--- /dev/null
+++ b/source/blender/blenkernel/intern/colorband.c
@@ -0,0 +1,629 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/colorband.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_color.h"
+#include "BLI_heap.h"
+
+#include "DNA_key_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_colorband.h"
+#include "BKE_material.h"
+#include "BKE_key.h"
+
+void BKE_colorband_init(ColorBand *coba, bool rangetype)
+{
+ int a;
+
+ coba->data[0].pos = 0.0;
+ coba->data[1].pos = 1.0;
+
+ if (rangetype == 0) {
+ coba->data[0].r = 0.0;
+ coba->data[0].g = 0.0;
+ coba->data[0].b = 0.0;
+ coba->data[0].a = 0.0;
+
+ coba->data[1].r = 1.0;
+ coba->data[1].g = 1.0;
+ coba->data[1].b = 1.0;
+ coba->data[1].a = 1.0;
+ }
+ else {
+ coba->data[0].r = 0.0;
+ coba->data[0].g = 0.0;
+ coba->data[0].b = 0.0;
+ coba->data[0].a = 1.0;
+
+ coba->data[1].r = 1.0;
+ coba->data[1].g = 1.0;
+ coba->data[1].b = 1.0;
+ coba->data[1].a = 1.0;
+ }
+
+ for (a = 2; a < MAXCOLORBAND; a++) {
+ coba->data[a].r = 0.5;
+ coba->data[a].g = 0.5;
+ coba->data[a].b = 0.5;
+ coba->data[a].a = 1.0;
+ coba->data[a].pos = 0.5;
+ }
+
+ coba->tot = 2;
+ coba->color_mode = COLBAND_BLEND_RGB;
+}
+
+static void colorband_init_from_table_rgba_simple(
+ ColorBand *coba,
+ const float (*array)[4], const int array_len)
+{
+ /* No Re-sample, just de-duplicate. */
+ const float eps = (1.0f / 255.0f) + 1e-6f;
+ BLI_assert(array_len < MAXCOLORBAND);
+ int stops = min_ii(MAXCOLORBAND, array_len);
+ if (stops) {
+ const float step_size = 1.0f / (float)max_ii(stops - 1, 1);
+ int i_curr = -1;
+ for (int i_step = 0; i_step < stops; i_step++) {
+ if ((i_curr != -1) && compare_v4v4(&coba->data[i_curr].r, array[i_step], eps)) {
+ continue;
+ }
+ i_curr += 1;
+ copy_v4_v4(&coba->data[i_curr].r, array[i_step]);
+ coba->data[i_curr].pos = i_step * step_size;
+ coba->data[i_curr].cur = i_curr;
+ }
+ coba->tot = i_curr + 1;
+ coba->cur = 0;
+ }
+ else {
+ /* coba is empty, set 1 black stop */
+ zero_v3(&coba->data[0].r);
+ coba->data[0].a = 1.0f;
+ coba->cur = 0;
+ coba->tot = 1;
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Color Ramp Re-Sample
+ *
+ * Local functions for #BKE_colorband_init_from_table_rgba
+ * \{ */
+
+/**
+ * Used for calculating which samples of a color-band to remove (when simplifying).
+ */
+struct ColorResampleElem {
+ struct ColorResampleElem *next, *prev;
+ HeapNode *node;
+ float rgba[4];
+ float pos;
+};
+
+/**
+ * Measure the 'area' of each channel and combine to use as a cost for this samples removal.
+ */
+static float color_sample_remove_cost(const struct ColorResampleElem *c)
+{
+ if (c->next == NULL || c->prev == NULL) {
+ return -1.0f;
+ }
+ float area = 0.0f;
+#if 0
+ float xy_prev[2], xy_curr[2], xy_next[2];
+ xy_prev[0] = c->prev->pos;
+ xy_curr[0] = c->pos;
+ xy_next[0] = c->next->pos;
+ for (int i = 0; i < 4; i++) {
+ xy_prev[1] = c->prev->rgba[i];
+ xy_curr[1] = c->rgba[i];
+ xy_next[1] = c->next->rgba[i];
+ area += fabsf(cross_tri_v2(xy_prev, xy_curr, xy_next));
+ }
+#else
+ /* Above logic, optimized (p: previous, c: current, n: next). */
+ const float xpc = c->prev->pos - c->pos;
+ const float xnc = c->next->pos - c->pos;
+ for (int i = 0; i < 4; i++) {
+ const float ycn = c->rgba[i] - c->next->rgba[i];
+ const float ypc = c->prev->rgba[i] - c->rgba[i];
+ area += fabsf((xpc * ycn) + (ypc * xnc));
+ }
+#endif
+ return area;
+}
+
+/* TODO(campbell): create BLI_math_filter? */
+static float filter_gauss(float x)
+{
+ const float gaussfac = 1.6f;
+ const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
+ x *= 3.0f * gaussfac;
+ return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2);
+}
+
+static void colorband_init_from_table_rgba_resample(
+ ColorBand *coba,
+ const float (*array)[4], const int array_len,
+ bool filter_samples)
+{
+ BLI_assert(array_len >= 2);
+ const float eps_2x = ((1.0f / 255.0f) + 1e-6f);
+ struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__);
+ int carr_len = array_len;
+ c = carr;
+ {
+ const float step_size = 1.0f / (float)(array_len - 1);
+ for (int i = 0; i < array_len; i++, c++) {
+ copy_v4_v4(carr[i].rgba, array[i]);
+ c->next = c + 1;
+ c->prev = c - 1;
+ c->pos = i * step_size;
+ }
+ }
+ carr[0].prev = NULL;
+ carr[array_len - 1].next = NULL;
+
+ /* -2 to remove endpoints. */
+ Heap *heap = BLI_heap_new_ex(array_len - 2);
+ c = carr;
+ for (int i = 0; i < array_len; i++, c++) {
+ float cost = color_sample_remove_cost(c);
+ if (cost != -1.0f) {
+ c->node = BLI_heap_insert(heap, cost, c);
+ }
+ else {
+ c->node = NULL;
+ }
+ }
+
+ while ((carr_len > 1 && !BLI_heap_is_empty(heap)) &&
+ ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x)))
+ {
+ c = BLI_heap_popmin(heap);
+ struct ColorResampleElem *c_next = c->next, *c_prev = c->prev;
+ c_prev->next = c_next;
+ c_next->prev = c_prev;
+ /* Clear data (not essential, avoid confusion). */
+ c->prev = c->next = NULL;
+ c->node = NULL;
+
+ /* Update adjacent */
+ for (int i = 0; i < 2; i++) {
+ struct ColorResampleElem *c_other = i ? c_next : c_prev;
+ if (c_other->node != NULL) {
+ const float cost = color_sample_remove_cost(c_other);
+ if (cost != -1.0) {
+ BLI_heap_node_value_update(heap, c_other->node, cost);
+ }
+ else {
+ BLI_heap_remove(heap, c_other->node);
+ c_other->node = NULL;
+ }
+ }
+ }
+ carr_len -= 1;
+ }
+ BLI_heap_free(heap, NULL);
+
+ /* First member is never removed. */
+ int i = 0;
+ BLI_assert(carr_len < MAXCOLORBAND);
+ if (filter_samples == false) {
+ for (c = carr; c != NULL; c = c->next, i++) {
+ copy_v4_v4(&coba->data[i].r, c->rgba);
+ coba->data[i].pos = c->pos;
+ coba->data[i].cur = i;
+ }
+ }
+ else {
+ for (c = carr; c != NULL; c = c->next, i++) {
+ const int steps_prev = c->prev ? (c - c->prev) - 1 : 0;
+ const int steps_next = c->next ? (c->next - c) - 1 : 0;
+ if (steps_prev == 0 && steps_next == 0) {
+ copy_v4_v4(&coba->data[i].r, c->rgba);
+ }
+ else {
+ float rgba[4];
+ float rgba_accum = 1;
+ copy_v4_v4(rgba, c->rgba);
+
+ if (steps_prev) {
+ const float step_size = 1.0 / (float)(steps_prev + 1);
+ int j = steps_prev;
+ for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) {
+ const float step_pos = (float)j * step_size;
+ BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
+ const float f = filter_gauss(step_pos);
+ madd_v4_v4fl(rgba, c_other->rgba, f);
+ rgba_accum += f;
+ }
+ }
+ if (steps_next) {
+ const float step_size = 1.0 / (float)(steps_next + 1);
+ int j = steps_next;
+ for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) {
+ const float step_pos = (float)j * step_size;
+ BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
+ const float f = filter_gauss(step_pos);
+ madd_v4_v4fl(rgba, c_other->rgba, f);
+ rgba_accum += f;
+ }
+ }
+
+ mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum);
+ }
+ coba->data[i].pos = c->pos;
+ coba->data[i].cur = i;
+ }
+ }
+ BLI_assert(i == carr_len);
+ coba->tot = i;
+ coba->cur = 0;
+
+ MEM_freeN(carr);
+}
+
+void BKE_colorband_init_from_table_rgba(
+ ColorBand *coba,
+ const float (*array)[4], const int array_len,
+ bool filter_samples)
+{
+ /* Note, we could use MAXCOLORBAND here, but results of re-sampling are nicer,
+ * avoid different behavior when limit is hit. */
+ if (array_len < 2) {
+ /* No Re-sample, just de-duplicate. */
+ colorband_init_from_table_rgba_simple(coba, array, array_len);
+ }
+ else {
+ /* Re-sample */
+ colorband_init_from_table_rgba_resample(coba, array, array_len, filter_samples);
+ }
+}
+
+/** \} */
+
+ColorBand *BKE_colorband_add(bool rangetype)
+{
+ ColorBand *coba;
+
+ coba = MEM_callocN(sizeof(ColorBand), "colorband");
+ BKE_colorband_init(coba, rangetype);
+
+ return coba;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static float colorband_hue_interp(
+ const int ipotype_hue,
+ const float mfac, const float fac,
+ float h1, float h2)
+{
+ float h_interp;
+ int mode = 0;
+
+#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b)))
+#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f)
+
+ h1 = HUE_MOD(h1);
+ h2 = HUE_MOD(h2);
+
+ BLI_assert(h1 >= 0.0f && h1 < 1.0f);
+ BLI_assert(h2 >= 0.0f && h2 < 1.0f);
+
+ switch (ipotype_hue) {
+ case COLBAND_HUE_NEAR:
+ {
+ if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1;
+ else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2;
+ else mode = 0;
+ break;
+ }
+ case COLBAND_HUE_FAR:
+ {
+ if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1;
+ else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2;
+ else mode = 0;
+ break;
+ }
+ case COLBAND_HUE_CCW:
+ {
+ if (h1 > h2) mode = 2;
+ else mode = 0;
+ break;
+ }
+ case COLBAND_HUE_CW:
+ {
+ if (h1 < h2) mode = 1;
+ else mode = 0;
+ break;
+ }
+ }
+
+ switch (mode) {
+ case 0:
+ h_interp = HUE_INTERP(h1, h2);
+ break;
+ case 1:
+ h_interp = HUE_INTERP(h1 + 1.0f, h2);
+ h_interp = HUE_MOD(h_interp);
+ break;
+ case 2:
+ h_interp = HUE_INTERP(h1, h2 + 1.0f);
+ h_interp = HUE_MOD(h_interp);
+ break;
+ }
+
+ BLI_assert(h_interp >= 0.0f && h_interp < 1.0f);
+
+#undef HUE_INTERP
+#undef HUE_MOD
+
+ return h_interp;
+}
+
+bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
+{
+ const CBData *cbd1, *cbd2, *cbd0, *cbd3;
+ float fac;
+ int ipotype;
+ int a;
+
+ if (coba == NULL || coba->tot == 0) return false;
+
+ cbd1 = coba->data;
+
+ ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR;
+
+ if (coba->tot == 1) {
+ out[0] = cbd1->r;
+ out[1] = cbd1->g;
+ out[2] = cbd1->b;
+ out[3] = cbd1->a;
+ }
+ else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) {
+ out[0] = cbd1->r;
+ out[1] = cbd1->g;
+ out[2] = cbd1->b;
+ out[3] = cbd1->a;
+ }
+ else {
+ CBData left, right;
+
+ /* we're looking for first pos > in */
+ for (a = 0; a < coba->tot; a++, cbd1++) {
+ if (cbd1->pos > in) {
+ break;
+ }
+ }
+
+ if (a == coba->tot) {
+ cbd2 = cbd1 - 1;
+ right = *cbd2;
+ right.pos = 1.0f;
+ cbd1 = &right;
+ }
+ else if (a == 0) {
+ left = *cbd1;
+ left.pos = 0.0f;
+ cbd2 = &left;
+ }
+ else {
+ cbd2 = cbd1 - 1;
+ }
+
+ if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) {
+ out[0] = cbd1->r;
+ out[1] = cbd1->g;
+ out[2] = cbd1->b;
+ out[3] = cbd1->a;
+ }
+ else {
+
+ if (cbd2->pos != cbd1->pos) {
+ fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos);
+ }
+ else {
+ /* was setting to 0.0 in 2.56 & previous, but this
+ * is incorrect for the last element, see [#26732] */
+ fac = (a != coba->tot) ? 0.0f : 1.0f;
+ }
+
+ if (ipotype == COLBAND_INTERP_CONSTANT) {
+ /* constant */
+ out[0] = cbd2->r;
+ out[1] = cbd2->g;
+ out[2] = cbd2->b;
+ out[3] = cbd2->a;
+ }
+ else if (ipotype >= COLBAND_INTERP_B_SPLINE) {
+ /* ipo from right to left: 3 2 1 0 */
+ float t[4];
+
+ if (a >= coba->tot - 1) cbd0 = cbd1;
+ else cbd0 = cbd1 + 1;
+ if (a < 2) cbd3 = cbd2;
+ else cbd3 = cbd2 - 1;
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ if (ipotype == COLBAND_INTERP_CARDINAL) {
+ key_curve_position_weights(fac, t, KEY_CARDINAL);
+ }
+ else {
+ key_curve_position_weights(fac, t, KEY_BSPLINE);
+ }
+
+ out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r;
+ out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g;
+ out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b;
+ out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a;
+ CLAMP(out[0], 0.0f, 1.0f);
+ CLAMP(out[1], 0.0f, 1.0f);
+ CLAMP(out[2], 0.0f, 1.0f);
+ CLAMP(out[3], 0.0f, 1.0f);
+ }
+ else {
+ float mfac;
+
+ if (ipotype == COLBAND_INTERP_EASE) {
+ mfac = fac * fac;
+ fac = 3.0f * mfac - 2.0f * mfac * fac;
+ }
+
+ mfac = 1.0f - fac;
+
+ if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) {
+ float col1[3], col2[3];
+
+ rgb_to_hsv_v(&cbd1->r, col1);
+ rgb_to_hsv_v(&cbd2->r, col2);
+
+ out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
+ out[1] = mfac * col1[1] + fac * col2[1];
+ out[2] = mfac * col1[2] + fac * col2[2];
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+
+ hsv_to_rgb_v(out, out);
+ }
+ else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) {
+ float col1[3], col2[3];
+
+ rgb_to_hsl_v(&cbd1->r, col1);
+ rgb_to_hsl_v(&cbd2->r, col2);
+
+ out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
+ out[1] = mfac * col1[1] + fac * col2[1];
+ out[2] = mfac * col1[2] + fac * col2[2];
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+
+ hsl_to_rgb_v(out, out);
+ }
+ else {
+ /* COLBAND_BLEND_RGB */
+ out[0] = mfac * cbd1->r + fac * cbd2->r;
+ out[1] = mfac * cbd1->g + fac * cbd2->g;
+ out[2] = mfac * cbd1->b + fac * cbd2->b;
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+ }
+ }
+ }
+ }
+ return true; /* OK */
+}
+
+void BKE_colorband_evaluate_table_rgba(const ColorBand *coba, float **array, int *size)
+{
+ int a;
+
+ *size = CM_TABLE + 1;
+ *array = MEM_callocN(sizeof(float) * (*size) * 4, "ColorBand");
+
+ for (a = 0; a < *size; a++)
+ BKE_colorband_evaluate(coba, (float)a / (float)CM_TABLE, &(*array)[a * 4]);
+}
+
+static int vergcband(const void *a1, const void *a2)
+{
+ const CBData *x1 = a1, *x2 = a2;
+
+ if (x1->pos > x2->pos) return 1;
+ else if (x1->pos < x2->pos) return -1;
+ return 0;
+}
+
+void BKE_colorband_update_sort(ColorBand *coba)
+{
+ int a;
+
+ if (coba->tot < 2)
+ return;
+
+ for (a = 0; a < coba->tot; a++)
+ coba->data[a].cur = a;
+
+ qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
+
+ for (a = 0; a < coba->tot; a++) {
+ if (coba->data[a].cur == coba->cur) {
+ coba->cur = a;
+ break;
+ }
+ }
+}
+
+CBData *BKE_colorband_element_add(struct ColorBand *coba, float position)
+{
+ if (coba->tot == MAXCOLORBAND) {
+ return NULL;
+ }
+ else {
+ CBData *xnew;
+
+ xnew = &coba->data[coba->tot];
+ xnew->pos = position;
+
+ if (coba->tot != 0) {
+ BKE_colorband_evaluate(coba, position, &xnew->r);
+ }
+ else {
+ zero_v4(&xnew->r);
+ }
+ }
+
+ coba->tot++;
+ coba->cur = coba->tot - 1;
+
+ BKE_colorband_update_sort(coba);
+
+ return coba->data + coba->cur;
+}
+
+int BKE_colorband_element_remove(struct ColorBand *coba, int index)
+{
+ int a;
+
+ if (coba->tot < 2)
+ return 0;
+
+ if (index < 0 || index >= coba->tot)
+ return 0;
+
+ coba->tot--;
+ for (a = index; a < coba->tot; a++) {
+ coba->data[a] = coba->data[a + 1];
+ }
+ if (coba->cur) coba->cur--;
+ return 1;
+}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 310255a15c1..0fe429312db 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1165,7 +1165,9 @@ typedef struct ScopesUpdateDataChunk {
float min[3], max[3];
} ScopesUpdateDataChunk;
-static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+static void scopes_update_cb(void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict tls)
{
const ScopesUpdateData *data = userdata;
@@ -1175,7 +1177,7 @@ static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y,
const unsigned char *display_buffer = data->display_buffer;
const int ycc_mode = data->ycc_mode;
- ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+ ScopesUpdateDataChunk *data_chunk = tls->userdata_chunk;
unsigned int *bin_lum = data_chunk->bin_lum;
unsigned int *bin_r = data_chunk->bin_r;
unsigned int *bin_g = data_chunk->bin_g;
@@ -1259,7 +1261,8 @@ static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y,
}
}
-static void scopes_update_finalize(void *userdata, void *userdata_chunk)
+static void scopes_update_finalize(void *__restrict userdata,
+ void *__restrict userdata_chunk)
{
const ScopesUpdateData *data = userdata;
const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
@@ -1387,8 +1390,16 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
ScopesUpdateDataChunk data_chunk = {{0}};
INIT_MINMAX(data_chunk.min, data_chunk.max);
- BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
- scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (ibuf->y > 256);
+ settings.userdata_chunk = &data_chunk;
+ settings.userdata_chunk_size = sizeof(data_chunk);
+ settings.func_finalize = scopes_update_finalize;
+ BLI_task_parallel_range(0, ibuf->y,
+ &data,
+ scopes_update_cb,
+ &settings);
/* test for nicer distribution even - non standard, leave it out for a while */
#if 0
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index d429149f0c4..b8dc7944a75 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -1013,8 +1013,11 @@ static void vectomat(const float vec[3], const float target_up[3], short axis, s
u[2] = 1;
}
+ /* note: even though 'n' is normalized, don't use 'project_v3_v3v3_normalized' below
+ * because precision issues cause a problem in near degenerate states, see: T53455. */
+
/* project the up vector onto the plane specified by n */
- project_v3_v3v3_normalized(proj, u, n); /* first u onto n... */
+ project_v3_v3v3(proj, u, n); /* first u onto n... */
sub_v3_v3v3(proj, u, proj); /* then onto the plane */
/* proj specifies the transformation of the up axis */
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 1f673d2c15f..a92299810ec 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -976,11 +976,11 @@ RenderEngineType *CTX_data_engine_type(const bContext *C)
LayerCollection *CTX_data_layer_collection(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *lc;
+ LayerCollection *layer_collection;
- if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) {
- if (BKE_view_layer_has_collection(view_layer, lc->scene_collection)) {
- return lc;
+ if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) {
+ if (BKE_view_layer_has_collection(view_layer, layer_collection->scene_collection)) {
+ return layer_collection;
}
}
@@ -990,16 +990,14 @@ LayerCollection *CTX_data_layer_collection(const bContext *C)
SceneCollection *CTX_data_scene_collection(const bContext *C)
{
- SceneCollection *sc;
- if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) {
- if (BKE_view_layer_has_collection(CTX_data_view_layer(C), sc)) {
- return sc;
- }
+ SceneCollection *scene_collection;
+ if (ctx_data_pointer_verify(C, "scene_collection", (void *)&scene_collection)) {
+ return scene_collection;
}
- LayerCollection *lc = CTX_data_layer_collection(C);
- if (lc) {
- return lc->scene_collection;
+ LayerCollection *layer_collection = CTX_data_layer_collection(C);
+ if (layer_collection) {
+ return layer_collection->scene_collection;
}
/* fallback */
@@ -1069,6 +1067,7 @@ static const char *data_mode_strings[] = {
"objectmode",
NULL
};
+BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
const char *CTX_data_mode_string(const bContext *C)
{
return data_mode_strings[CTX_data_mode_enum(C)];
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index ba9ccf94303..2a27bad0fb5 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -169,12 +169,12 @@ void BKE_curve_init(Curve *cu)
if (cu->type == OB_FONT) {
cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
cu->vfont->id.us += 4;
- cu->str = MEM_mallocN(12, "str");
+ cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
BLI_strncpy(cu->str, "Text", 12);
cu->len = cu->len_wchar = cu->pos = 4;
- cu->strinfo = MEM_callocN(12 * sizeof(CharInfo), "strinfo new");
+ cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
cu->totbox = cu->actbox = 1;
- cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "textbox");
+ cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
}
@@ -481,13 +481,13 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
if (nu->bezt) {
newnu->bezt =
- (BezTriple *)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "duplicateNurb2");
+ (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2");
memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple));
}
else {
len = nu->pntsu * nu->pntsv;
newnu->bp =
- (BPoint *)MEM_mallocN((len) * sizeof(BPoint), "duplicateNurb3");
+ (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
newnu->knotsu = newnu->knotsv = NULL;
@@ -495,14 +495,14 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
if (nu->knotsu) {
len = KNOTSU(nu);
if (len) {
- newnu->knotsu = MEM_mallocN(len * sizeof(float), "duplicateNurb4");
+ newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
}
}
if (nu->pntsv > 1 && nu->knotsv) {
len = KNOTSV(nu);
if (len) {
- newnu->knotsv = MEM_mallocN(len * sizeof(float), "duplicateNurb5");
+ newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
}
}
@@ -525,10 +525,10 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
newnu->knotsv = NULL;
if (src->bezt) {
- newnu->bezt = (BezTriple *)MEM_mallocN(pntsu * pntsv * sizeof(BezTriple), "copyNurb2");
+ newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
}
else {
- newnu->bp = (BPoint *)MEM_mallocN(pntsu * pntsv * sizeof(BPoint), "copyNurb3");
+ newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3");
}
return newnu;
@@ -975,7 +975,7 @@ static void makeknots(Nurb *nu, short uv)
if (nu->knotsu)
MEM_freeN(nu->knotsu);
if (BKE_nurb_check_valid_u(nu)) {
- nu->knotsu = MEM_callocN(4 + sizeof(float) * KNOTSU(nu), "makeknots");
+ nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
if (nu->flagu & CU_NURB_CYCLIC) {
calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
@@ -991,7 +991,7 @@ static void makeknots(Nurb *nu, short uv)
if (nu->knotsv)
MEM_freeN(nu->knotsv);
if (BKE_nurb_check_valid_v(nu)) {
- nu->knotsv = MEM_callocN(4 + sizeof(float) * KNOTSV(nu), "makeknots");
+ nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
if (nu->flagv & CU_NURB_CYCLIC) {
calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
@@ -1108,7 +1108,7 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu,
if (len == 0)
return;
- sum = (float *)MEM_callocN(sizeof(float) * len, "makeNurbfaces1");
+ sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1");
bp = nu->bp;
i = nu->pntsu * nu->pntsv;
@@ -1129,7 +1129,7 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu,
uend = fp[nu->pntsu];
ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1);
- basisu = (float *)MEM_mallocN(sizeof(float) * KNOTSU(nu), "makeNurbfaces3");
+ basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3");
fp = nu->knotsv;
vstart = fp[nu->orderv - 1];
@@ -1141,9 +1141,9 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu,
vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1);
len = KNOTSV(nu);
- basisv = (float *)MEM_mallocN(sizeof(float) * len * totv, "makeNurbfaces3");
- jstart = (int *)MEM_mallocN(sizeof(float) * totv, "makeNurbfaces4");
- jend = (int *)MEM_mallocN(sizeof(float) * totv, "makeNurbfaces5");
+ basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3");
+ jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
+ jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
/* precalculation of basisv and jstart, jend */
if (nu->flagv & CU_NURB_CYCLIC)
@@ -1281,7 +1281,7 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
len = nu->pntsu;
if (len == 0)
return;
- sum = (float *)MEM_callocN(sizeof(float) * len, "makeNurbcurve1");
+ sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1");
resolu = (resolu * SEGMENTSU(nu));
@@ -1298,7 +1298,7 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
uend = fp[nu->pntsu];
ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1));
- basisu = (float *)MEM_mallocN(sizeof(float) * KNOTSU(nu), "makeNurbcurve3");
+ basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3");
if (nu->flagu & CU_NURB_CYCLIC)
cycl = nu->orderu - 1;
@@ -1549,7 +1549,7 @@ float *BKE_curve_surf_make_orco(Object *ob)
nu = nu->next;
}
/* makeNurbfaces wants zeros */
- fp = coord_array = MEM_callocN(3 * sizeof(float) * tot, "make_orco");
+ fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco");
nu = cu->nurb.first;
while (nu) {
@@ -1660,7 +1660,7 @@ float *BKE_curve_make_orco(const EvaluationContext *eval_ctx, Scene *scene, Obje
if (r_numVerts)
*r_numVerts = numVerts;
- fp = coord_array = MEM_mallocN(3 * sizeof(float) * numVerts, "cu_orco");
+ fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco");
for (dl = disp.first; dl; dl = dl->next) {
if (dl->type == DL_INDEX3) {
for (u = 0; u < dl->nr; u++, fp += 3) {
@@ -1764,7 +1764,7 @@ void BKE_curve_bevel_make(
if (ELEM(dl->type, DL_POLY, DL_SEGM)) {
dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1");
*dlnew = *dl;
- dlnew->verts = MEM_mallocN(3 * sizeof(float) * dl->parts * dl->nr, "makebevelcurve1");
+ dlnew->verts = MEM_malloc_arrayN(dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1");
memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr);
if (dlnew->type == DL_SEGM)
@@ -1791,7 +1791,7 @@ void BKE_curve_bevel_make(
}
else if (cu->ext2 == 0.0f) {
dl = MEM_callocN(sizeof(DispList), "makebevelcurve2");
- dl->verts = MEM_mallocN(2 * sizeof(float[3]), "makebevelcurve2");
+ dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->parts = 1;
@@ -1808,7 +1808,7 @@ void BKE_curve_bevel_make(
nr = 4 + 2 * cu->bevresol;
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p1");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
BLI_addtail(disp, dl);
dl->type = DL_POLY;
dl->parts = 1;
@@ -1840,7 +1840,7 @@ void BKE_curve_bevel_make(
nr = 3 + 2 * cu->bevresol;
}
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p1");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->parts = 1;
@@ -1866,7 +1866,7 @@ void BKE_curve_bevel_make(
nr = 2;
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2");
- dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p2");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->parts = 1;
@@ -1898,7 +1898,7 @@ void BKE_curve_bevel_make(
nr = 3 + 2 * cu->bevresol;
}
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3");
- dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p3");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->flag = DL_FRONT_CURVE;
@@ -2628,6 +2628,9 @@ void BKE_curve_bevelList_free(ListBase *bev)
if (bl->segbevcount != NULL) {
MEM_freeN(bl->segbevcount);
}
+ if (bl->bevpoints != NULL) {
+ MEM_freeN(bl->bevpoints);
+ }
MEM_freeN(bl);
}
@@ -2692,7 +2695,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* check we are a single point? also check we are not a surface and that the orderu is sane,
* enforced in the UI but can go wrong possibly */
if (!BKE_nurb_check_valid_u(nu)) {
- bl = MEM_callocN(sizeof(BevList) + 1 * sizeof(BevPoint), "makeBevelList1");
+ bl = MEM_callocN(sizeof(BevList), "makeBevelList1");
+ bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
BLI_addtail(bev, bl);
bl->nr = 0;
bl->charidx = nu->charidx;
@@ -2709,10 +2713,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
if (nu->type == CU_POLY) {
len = nu->pntsu;
- bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2");
+ bl = MEM_callocN(sizeof(BevList), "makeBevelList2");
+ bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2");
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList2_seglen");
- bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList2_segbevcount");
+ bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen");
+ bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount");
}
BLI_addtail(bev, bl);
@@ -2755,10 +2760,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* in case last point is not cyclic */
len = segcount * resolu + 1;
- bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints");
+ bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints");
+ bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints");
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelBPoints_seglen");
- bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelBPoints_segbevcount");
+ bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen");
+ bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelBPoints_segbevcount");
}
BLI_addtail(bev, bl);
@@ -2891,10 +2897,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
if (nu->pntsv == 1) {
len = (resolu * segcount);
- bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3");
+ bl = MEM_callocN(sizeof(BevList), "makeBevelList3");
+ bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3");
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList3_seglen");
- bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList3_segbevcount");
+ bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen");
+ bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList3_segbevcount");
}
BLI_addtail(bev, bl);
bl->nr = len;
@@ -2989,8 +2996,13 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
blnext = bl->next;
if (bl->nr && bl->dupe_nr) {
nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
- blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4");
+ blnew = MEM_callocN(sizeof(BevList), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
+ blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
+ if (!blnew->bevpoints) {
+ MEM_freeN(blnew);
+ break;
+ }
blnew->segbevcount = bl->segbevcount;
blnew->seglen = bl->seglen;
blnew->nr = 0;
@@ -3007,6 +3019,9 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
}
bevp0++;
}
+ if (bl->bevpoints != NULL) {
+ MEM_freeN(bl->bevpoints);
+ }
MEM_freeN(bl);
blnew->dupe_nr = 0;
}
@@ -3027,7 +3042,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* find extreme left points, also test (turning) direction */
if (poly > 0) {
- sd = sortdata = MEM_mallocN(sizeof(struct BevelSort) * poly, "makeBevelList5");
+ sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5");
bl = bev->first;
while (bl) {
if (bl->poly > 0) {
@@ -3445,7 +3460,7 @@ static void calchandlesNurb_intern(Nurb *nu, bool skip_align)
*/
static void *allocate_arrays(int count, float ***floats, char ***chars, const char *name)
{
- int num_floats = 0, num_chars = 0;
+ size_t num_floats = 0, num_chars = 0;
while (floats && floats[num_floats]) {
num_floats++;
@@ -3455,7 +3470,7 @@ static void *allocate_arrays(int count, float ***floats, char ***chars, const ch
num_chars++;
}
- void *buffer = (float *)MEM_mallocN(count * (sizeof(float) * num_floats + num_chars), name);
+ void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
if (!buffer)
return NULL;
@@ -4429,7 +4444,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
/* and make in increasing order again */
a = KNOTSU(nu);
fp1 = nu->knotsu;
- fp2 = tempf = MEM_mallocN(sizeof(float) * a, "switchdirect");
+ fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
a--;
fp2[a] = fp1[a];
while (a--) {
@@ -4473,7 +4488,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
float (*BKE_curve_nurbs_vertexCos_get(ListBase *lb, int *r_numVerts))[3]
{
int i, numVerts = *r_numVerts = BKE_nurbList_verts_count(lb);
- float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "cu_vcos");
+ float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos");
Nurb *nu;
co = cos[0];
@@ -4530,7 +4545,7 @@ void BK_curve_nurbs_vertexCos_apply(ListBase *lb, float (*vertexCos)[3])
float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3]
{
int i, numVerts = BKE_nurbList_verts_count(lb);
- float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "cu_vcos");
+ float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos");
Nurb *nu;
co = cos[0];
@@ -4677,7 +4692,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
if (nu->type == CU_POLY) {
if (type == CU_BEZIER) { /* to Bezier with vecthandles */
nr = nu->pntsu;
- bezt = (BezTriple *)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
+ bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
a = nr;
bp = nu->bp;
@@ -4713,7 +4728,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
else if (nu->type == CU_BEZIER) { /* Bezier */
if (type == CU_POLY || type == CU_NURBS) {
nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
- nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
+ nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
a = nu->pntsu;
bezt = nu->bezt;
bp = nu->bp;
@@ -4776,7 +4791,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
return false; /* conversion impossible */
}
else {
- bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
+ bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
a = nr;
bp = nu->bp;
@@ -4938,12 +4953,27 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
{
ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- Nurb *nu;
-
- for (nu = nurb_lb->first; nu; nu = nu->next)
+ ListBase temp_nurb_lb = {NULL, NULL};
+ const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
+ /* For font curves we generate temp list of splines.
+ *
+ * This is likely to be fine, this function is not supposed to be called
+ * often, and it's the only way to get meaningful bounds for fonts.
+ */
+ if (is_font) {
+ nurb_lb = &temp_nurb_lb;
+ BKE_vfont_to_curve_ex(G.main, NULL, cu, FO_EDIT, nurb_lb,
+ NULL, NULL, NULL, NULL);
+ use_radius = false;
+ }
+ /* Do bounding box based on splines. */
+ for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) {
BKE_nurb_minmax(nu, use_radius, min, max);
-
- return (BLI_listbase_is_empty(nurb_lb) == false);
+ }
+ const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
+ /* Cleanup if needed. */
+ BKE_nurbList_free(&temp_nurb_lb);
+ return result;
}
bool BKE_curve_center_median(Curve *cu, float cent[3])
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 3bf5784e674..9c0ace2f654 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -157,7 +157,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest,
MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
if (dvert->totweight) {
- MDeformWeight *dw = MEM_mallocN(dvert->totweight * sizeof(*dw),
+ MDeformWeight *dw = MEM_malloc_arrayN(dvert->totweight, sizeof(*dw),
"layerCopy_mdeformvert dw");
memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
@@ -281,7 +281,7 @@ static void layerInterp_mdeformvert(
}
if (totweight) {
- dvert->dw = MEM_mallocN(sizeof(*dvert->dw) * totweight, __func__);
+ dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__);
}
}
@@ -518,11 +518,11 @@ static void layerSwap_mdisps(void *data, const int *ci)
MEM_freeN(s->disps);
s->totdisp = (s->totdisp / corners) * nverts;
- s->disps = MEM_callocN(s->totdisp * sizeof(float) * 3, "mdisp swap");
+ s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float) * 3, "mdisp swap");
return;
}
- d = MEM_callocN(sizeof(float) * 3 * s->totdisp, "mdisps swap");
+ d = MEM_calloc_arrayN(s->totdisp, 3 * sizeof(float), "mdisps swap");
for (S = 0; S < corners; S++)
memcpy(d + cornersize * S, s->disps + cornersize * ci[S], cornersize * 3 * sizeof(float));
@@ -578,7 +578,7 @@ static int layerRead_mdisps(CDataFile *cdf, void *data, int count)
for (i = 0; i < count; ++i) {
if (!d[i].disps)
- d[i].disps = MEM_callocN(sizeof(float) * 3 * d[i].totdisp, "mdisps read");
+ d[i].disps = MEM_calloc_arrayN(d[i].totdisp, 3 * sizeof(float), "mdisps read");
if (!cdf_read_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
printf("failed to read multires displacement %d/%d %d\n", i, count, d[i].totdisp);
@@ -1796,7 +1796,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
static int customData_resize(CustomData *data, int amount)
{
- CustomDataLayer *tmp = MEM_callocN(sizeof(*tmp) * (data->maxlayer + amount),
+ CustomDataLayer *tmp = MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp),
"CustomData->layers");
if (!tmp) return 0;
@@ -1814,7 +1814,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- const size_t size = (size_t)totelem * typeInfo->size;
int flag = 0, index = data->totlayer;
void *newlayerdata = NULL;
@@ -1831,12 +1830,12 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
if ((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) {
newlayerdata = layerdata;
}
- else if (size > 0) {
+ else if (totelem > 0 && typeInfo->size > 0) {
if (alloctype == CD_DUPLICATE && layerdata) {
- newlayerdata = MEM_mallocN(size, layerType_getName(type));
+ newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type));
}
else {
- newlayerdata = MEM_callocN(size, layerType_getName(type));
+ newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type));
}
if (!newlayerdata)
@@ -1847,7 +1846,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
if (typeInfo->copy)
typeInfo->copy(layerdata, newlayerdata, totelem);
else
- memcpy(newlayerdata, layerdata, size);
+ memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size);
}
else if (alloctype == CD_DEFAULT) {
if (typeInfo->set_default)
@@ -2038,7 +2037,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->copy) {
- void *dst_data = MEM_mallocN((size_t)totelem * typeInfo->size, "CD duplicate ref layer");
+ void *dst_data = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, "CD duplicate ref layer");
typeInfo->copy(layer->data, dst_data, totelem);
layer->data = dst_data;
}
@@ -2267,7 +2266,7 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
* elements
*/
if (count > SOURCE_BUF_SIZE)
- sources = MEM_mallocN(sizeof(*sources) * count, __func__);
+ sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
/* interpolates a layer at a time */
dest_i = 0;
@@ -3122,7 +3121,7 @@ void CustomData_bmesh_interp(
* elements
*/
if (count > SOURCE_BUF_SIZE)
- sources = MEM_mallocN(sizeof(*sources) * count, __func__);
+ sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
/* interpolates a layer at a time */
for (i = 0; i < data->totlayer; ++i) {
@@ -3312,7 +3311,7 @@ void CustomData_file_write_prepare(
else {
if (UNLIKELY((size_t)j >= write_layers_size)) {
if (write_layers == write_layers_buff) {
- write_layers = MEM_mallocN(sizeof(*write_layers) * (write_layers_size + chunk_size), __func__);
+ write_layers = MEM_malloc_arrayN((write_layers_size + chunk_size), sizeof(*write_layers), __func__);
if (write_layers_buff) {
memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size);
}
@@ -3980,7 +3979,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTra
}
if (data_src) {
- tmp_data_src = MEM_mallocN(sizeof(*tmp_data_src) * tmp_buff_size, __func__);
+ tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__);
}
if (data_type & CD_FAKE) {
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index 41579aaa568..d17c9ef5cc6 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -210,9 +210,13 @@ static int cdf_read_header(CDataFile *cdf)
if (fseek(f, offset, SEEK_SET) != 0)
return 0;
- cdf->layer = MEM_callocN(sizeof(CDataFileLayer) * header->totlayer, "CDataFileLayer");
+ cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
cdf->totlayer = header->totlayer;
+ if (!cdf->layer) {
+ return 0;
+ }
+
for (a = 0; a < header->totlayer; a++) {
layer = &cdf->layer[a];
@@ -429,7 +433,7 @@ CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t
CDataFileLayer *newlayer, *layer;
/* expand array */
- newlayer = MEM_callocN(sizeof(CDataFileLayer) * (cdf->totlayer + 1), "CDataFileLayer");
+ newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
cdf->layer = newlayer;
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 1fc83b69bfe..d4ff9bd5c0c 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -628,7 +628,7 @@ float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int
* (i.e. maximum weight, as if no vgroup was selected).
* But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid,
* and just totally empty, so we shall return '0.0' value then!
- */
+ */
if (defgroup == -1) {
return 1.0f;
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 80a31697424..2591c3c3c47 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -55,6 +55,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h" /* bvh tree */
+#include "BKE_colorband.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
@@ -72,7 +73,6 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
@@ -604,16 +604,19 @@ static void freeGrid(PaintSurfaceData *data)
bData->grid = NULL;
}
-static void grid_bound_insert_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+static void grid_bound_insert_cb_ex(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
PaintBakeData *bData = userdata;
- Bounds3D *grid_bound = userdata_chunk;
+ Bounds3D *grid_bound = tls->userdata_chunk;
boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
}
-static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk)
+static void grid_bound_insert_finalize(void *__restrict userdata,
+ void *__restrict userdata_chunk)
{
PaintBakeData *bData = userdata;
VolumeGrid *grid = bData->grid;
@@ -624,12 +627,14 @@ static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk)
boundInsert(&grid->grid_bounds, grid_bound->max);
}
-static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+static void grid_cell_points_cb_ex(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
PaintBakeData *bData = userdata;
VolumeGrid *grid = bData->grid;
int *temp_t_index = grid->temp_t_index;
- int *s_num = userdata_chunk;
+ int *s_num = tls->userdata_chunk;
int co[3];
@@ -643,7 +648,8 @@ static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const i
s_num[temp_t_index[i]]++;
}
-static void grid_cell_points_finalize(void *userdata, void *userdata_chunk)
+static void grid_cell_points_finalize(void *__restrict userdata,
+ void *__restrict userdata_chunk)
{
PaintBakeData *bData = userdata;
VolumeGrid *grid = bData->grid;
@@ -657,7 +663,9 @@ static void grid_cell_points_finalize(void *userdata, void *userdata_chunk)
}
}
-static void grid_cell_bounds_cb(void *userdata, const int x)
+static void grid_cell_bounds_cb(void *__restrict userdata,
+ const int x,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
PaintBakeData *bData = userdata;
VolumeGrid *grid = bData->grid;
@@ -702,10 +710,19 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* calculate canvas dimensions */
/* Important to init correctly our ref grid_bound... */
boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
- BLI_task_parallel_range_finalize(
- 0, sData->total_points, bData, &grid->grid_bounds, sizeof(grid->grid_bounds),
- grid_bound_insert_cb_ex, grid_bound_insert_finalize, sData->total_points > 1000, false);
-
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ settings.userdata_chunk = &grid->grid_bounds;
+ settings.userdata_chunk_size = sizeof(grid->grid_bounds);
+ settings.func_finalize = grid_bound_insert_finalize;
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ bData,
+ grid_bound_insert_cb_ex,
+ &settings);
+ }
/* get dimensions */
sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
copy_v3_v3(td, dim);
@@ -754,9 +771,19 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
if (!error) {
/* calculate number of points withing each cell */
- BLI_task_parallel_range_finalize(
- 0, sData->total_points, bData, grid->s_num, sizeof(*grid->s_num) * grid_cells,
- grid_cell_points_cb_ex, grid_cell_points_finalize, sData->total_points > 1000, false);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ settings.userdata_chunk = grid->s_num;
+ settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
+ settings.func_finalize = grid_cell_points_finalize;
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ bData,
+ grid_cell_points_cb_ex,
+ &settings);
+ }
/* calculate grid indexes (not needed for first cell, which is zero). */
for (i = 1; i < grid_cells; i++) {
@@ -772,7 +799,15 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
}
/* calculate cell bounds */
- BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, grid_cells > 1000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid_cells > 1000);
+ BLI_task_parallel_range(0, grid->dim[0],
+ bData,
+ grid_cell_bounds_cb,
+ &settings);
+ }
}
if (temp_s_num)
@@ -1085,7 +1120,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
{
CBData *ramp;
- brush->paint_ramp = add_colorband(false);
+ brush->paint_ramp = BKE_colorband_add(false);
if (!brush->paint_ramp)
return false;
ramp = brush->paint_ramp->data;
@@ -1101,7 +1136,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
{
CBData *ramp;
- brush->vel_ramp = add_colorband(false);
+ brush->vel_ramp = BKE_colorband_add(false);
if (!brush->vel_ramp)
return false;
ramp = brush->vel_ramp->data;
@@ -1390,7 +1425,10 @@ typedef struct DynamicPaintSetInitColorData {
const bool scene_color_manage;
} DynamicPaintSetInitColorData;
-static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const int i)
+static void dynamic_paint_set_init_color_tex_to_vcol_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintSetInitColorData *data = userdata;
@@ -1424,7 +1462,10 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const in
}
}
-static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const int i)
+static void dynamic_paint_set_init_color_tex_to_imseq_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintSetInitColorData *data = userdata;
@@ -1462,7 +1503,10 @@ static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const i
pPoint[i].color[3] = texres.tin;
}
-static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *userdata, const int i)
+static void dynamic_paint_set_init_color_vcol_to_imseq_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintSetInitColorData *data = userdata;
@@ -1540,7 +1584,13 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
.mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
.scene_color_manage = scene_color_manage
};
- BLI_task_parallel_range(0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, tottri > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (tottri > 1000);
+ BLI_task_parallel_range(0, tottri,
+ &data,
+ dynamic_paint_set_init_color_tex_to_vcol_cb,
+ &settings);
BKE_image_pool_free(pool);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -1549,8 +1599,13 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
.mlooptri = mlooptri, .mloopuv = mloopuv,
.scene_color_manage = scene_color_manage
};
- BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb,
- sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_set_init_color_tex_to_imseq_cb,
+ &settings);
}
}
/* vertex color layer */
@@ -1578,8 +1633,13 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
.surface = surface,
.mlooptri = mlooptri, .mloopcol = col,
};
- BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb,
- sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_set_init_color_vcol_to_imseq_cb,
+ &settings);
}
}
}
@@ -1666,7 +1726,10 @@ typedef struct DynamicPaintModifierApplyData {
MLoopCol *mloopcol_preview;
} DynamicPaintModifierApplyData;
-static void dynamic_paint_apply_surface_displace_cb(void *userdata, const int i)
+static void dynamic_paint_apply_surface_displace_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintModifierApplyData *data = userdata;
@@ -1696,12 +1759,20 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri
MVert *mvert = result->getVertArray(result);
DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
- BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb,
- sData->total_points > 10000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_apply_surface_displace_cb,
+ &settings);
}
}
-static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const int i)
+static void dynamic_paint_apply_surface_vpaint_blend_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintModifierApplyData *data = userdata;
@@ -1712,7 +1783,10 @@ static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const in
blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
}
-static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_index)
+static void dynamic_paint_apply_surface_vpaint_cb(
+ void *__restrict userdata,
+ const int p_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintModifierApplyData *data = userdata;
Object *ob = data->ob;
@@ -1782,7 +1856,10 @@ static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_in
}
}
-static void dynamic_paint_apply_surface_wave_cb(void *userdata, const int i)
+static void dynamic_paint_apply_surface_wave_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintModifierApplyData *data = userdata;
@@ -1829,9 +1906,16 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor};
- BLI_task_parallel_range(0, sData->total_points, &data,
- dynamic_paint_apply_surface_vpaint_blend_cb,
- sData->total_points > 1000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ &settings);
+ }
/* paint layer */
MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
@@ -1866,8 +1950,16 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
data.mloopcol_wet = mloopcol_wet;
data.mloopcol_preview = mloopcol_preview;
- BLI_task_parallel_range(0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb,
- totpoly > 1000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totpoly > 1000);
+ BLI_task_parallel_range(
+ 0, totpoly,
+ &data,
+ dynamic_paint_apply_surface_vpaint_cb,
+ &settings);
+ }
MEM_freeN(fcolor);
@@ -1917,8 +2009,14 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
MVert *mvert = result->getVertArray(result);
DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
- BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb,
- sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ &data,
+ dynamic_paint_apply_surface_wave_cb,
+ &settings);
update_normals = true;
}
@@ -2103,7 +2201,10 @@ typedef struct DynamicPaintCreateUVSurfaceData {
uint32_t *active_points;
} DynamicPaintCreateUVSurfaceData;
-static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int ty)
+static void dynamic_paint_create_uv_surface_direct_cb(
+ void *__restrict userdata,
+ const int ty,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintCreateUVSurfaceData *data = userdata;
@@ -2200,7 +2301,10 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int
}
}
-static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const int ty)
+static void dynamic_paint_create_uv_surface_neighbor_cb(
+ void *__restrict userdata,
+ const int ty,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintCreateUVSurfaceData *data = userdata;
@@ -2760,7 +2864,15 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
.mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri,
.faceBB = faceBB,
};
- BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, h > 64 || tottri > 1000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (h > 64 || tottri > 1000);
+ BLI_task_parallel_range(0, h,
+ &data,
+ dynamic_paint_create_uv_surface_direct_cb,
+ &settings);
+ }
*progress = 0.04f;
*do_update = true;
@@ -2772,7 +2884,15 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
* (To avoid seams on uv island edges)
*/
data.active_points = &active_points;
- BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, h > 64);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (h > 64);
+ BLI_task_parallel_range(0, h,
+ &data,
+ dynamic_paint_create_uv_surface_neighbor_cb,
+ &settings);
+ }
*progress = 0.06f;
*do_update = true;
@@ -2931,7 +3051,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
if (tempPoints[index].tri_index != -1) {
memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples],
- sizeof(*tempWeights) * aa_samples);
+ sizeof(*tempWeights) * aa_samples);
cursor++;
}
}
@@ -2992,7 +3112,10 @@ typedef struct DynamicPaintOutputSurfaceImageData {
ImBuf *ibuf;
} DynamicPaintOutputSurfaceImageData;
-static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const int index)
+static void dynamic_paint_output_surface_image_paint_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintOutputSurfaceImageData *data = userdata;
@@ -3012,7 +3135,10 @@ static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const in
}
}
-static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const int index)
+static void dynamic_paint_output_surface_image_displace_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintOutputSurfaceImageData *data = userdata;
@@ -3036,7 +3162,10 @@ static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const
ibuf->rect_float[pos + 3] = 1.0f;
}
-static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int index)
+static void dynamic_paint_output_surface_image_wave_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintOutputSurfaceImageData *data = userdata;
@@ -3058,7 +3187,10 @@ static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int
ibuf->rect_float[pos + 3] = 1.0f;
}
-static void dynamic_paint_output_surface_image_wetmap_cb(void *userdata, const int index)
+static void dynamic_paint_output_surface_image_wetmap_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintOutputSurfaceImageData *data = userdata;
@@ -3109,13 +3241,29 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
case MOD_DPAINT_SURFACE_T_PAINT:
switch (output_layer) {
case 0:
- BLI_task_parallel_range(0, sData->total_points, &data,
- dynamic_paint_output_surface_image_paint_cb, sData->total_points > 10000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_paint_cb,
+ &settings);
break;
+ }
case 1:
- BLI_task_parallel_range(0, sData->total_points, &data,
- dynamic_paint_output_surface_image_wetmap_cb, sData->total_points > 10000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_wetmap_cb,
+ &settings);
break;
+ }
default:
BLI_assert(0);
break;
@@ -3124,9 +3272,17 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
case MOD_DPAINT_SURFACE_T_DISPLACE:
switch (output_layer) {
case 0:
- BLI_task_parallel_range(0, sData->total_points, &data,
- dynamic_paint_output_surface_image_displace_cb, sData->total_points > 10000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_displace_cb,
+ &settings);
break;
+ }
case 1:
break;
default:
@@ -3137,9 +3293,17 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
case MOD_DPAINT_SURFACE_T_WAVE:
switch (output_layer) {
case 0:
- BLI_task_parallel_range(0, sData->total_points, &data,
- dynamic_paint_output_surface_image_wave_cb, sData->total_points > 10000);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(
+ 0, sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_wave_cb,
+ &settings);
break;
+ }
case 1:
break;
default:
@@ -3459,7 +3623,7 @@ static void dynamicPaint_updatePointData(
vel_factor /= brush->max_velocity;
CLAMP(vel_factor, 0.0f, 1.0f);
- if (do_colorband(brush->vel_ramp, vel_factor, coba_res)) {
+ if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
copy_v3_v3(paint, coba_res);
}
@@ -3546,7 +3710,10 @@ typedef struct DynamicPaintBrushVelocityData {
const float timescale;
} DynamicPaintBrushVelocityData;
-static void dynamic_paint_brush_velocity_compute_cb(void *userdata, const int i)
+static void dynamic_paint_brush_velocity_compute_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintBrushVelocityData *data = userdata;
@@ -3626,7 +3793,13 @@ static void dynamicPaint_brushMeshCalculateVelocity(
.mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
.timescale = timescale,
};
- BLI_task_parallel_range(0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, numOfVerts_c > 10000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numOfVerts_c > 10000);
+ BLI_task_parallel_range(0, numOfVerts_c,
+ &data,
+ dynamic_paint_brush_velocity_compute_cb,
+ &settings);
dm_p->release(dm_p);
}
@@ -3697,7 +3870,9 @@ typedef struct DynamicPaintPaintData {
* Paint a brush object mesh to the surface
*/
static void dynamic_paint_paint_mesh_cell_point_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int id,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintPaintData *data = userdata;
@@ -3906,7 +4081,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
else if (hit_found == HIT_PROXIMITY) {
/* apply falloff curve to the proximity_factor */
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
+ BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
{
proximity_factor = prox_colorband[3];
}
@@ -4115,9 +4290,13 @@ static int dynamicPaint_paintMesh(const struct EvaluationContext *eval_ctx, Dyna
.brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
.treeData = &treeData
};
- BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
- dynamic_paint_paint_mesh_cell_point_cb_ex,
- grid->s_num[c_index] > 250, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid->s_num[c_index] > 250);
+ BLI_task_parallel_range(0, grid->s_num[c_index],
+ &data,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ &settings);
}
}
}
@@ -4138,7 +4317,9 @@ static int dynamicPaint_paintMesh(const struct EvaluationContext *eval_ctx, Dyna
* Paint a particle system to the surface
*/
static void dynamic_paint_paint_particle_cell_point_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int id,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintPaintData *data = userdata;
@@ -4400,9 +4581,13 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
.solidradius = solidradius, .timescale = timescale, .c_index = c_index,
.treeData = tree,
};
- BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
- dynamic_paint_paint_particle_cell_point_cb_ex,
- grid->s_num[c_index] > 250, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid->s_num[c_index] > 250);
+ BLI_task_parallel_range(0, grid->s_num[c_index],
+ &data,
+ dynamic_paint_paint_particle_cell_point_cb_ex,
+ &settings);
}
}
BLI_end_threaded_malloc();
@@ -4413,7 +4598,9 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
/* paint a single point of defined proximity radius to the surface */
static void dynamic_paint_paint_single_point_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintPaintData *data = userdata;
@@ -4470,7 +4657,7 @@ static void dynamic_paint_paint_single_point_cb_ex(
/* color ramp */
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
+ BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
{
strength = colorband[3];
}
@@ -4545,9 +4732,13 @@ static int dynamicPaint_paintSinglePoint(
.brush_radius = brush_radius, .brushVelocity = &brushVel,
.pointCoord = pointCoord,
};
- BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0,
- dynamic_paint_paint_single_point_cb_ex,
- sData->total_points > 1000, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_paint_single_point_cb_ex,
+ &settings);
return 1;
}
@@ -4559,7 +4750,10 @@ static int dynamicPaint_paintSinglePoint(
* Calculate current frame distances and directions for adjacency data
*/
-static void dynamic_paint_prepare_adjacency_cb(void *userdata, const int index)
+static void dynamic_paint_prepare_adjacency_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
PaintSurfaceData *sData = userdata;
PaintBakeData *bData = sData->bData;
@@ -4598,8 +4792,13 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons
if (!bNeighs)
return;
- BLI_task_parallel_range(
- 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ sData,
+ dynamic_paint_prepare_adjacency_cb,
+ &settings);
/* calculate average values (single thread).
* Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
@@ -4786,7 +4985,10 @@ typedef struct DynamicPaintEffectData {
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
-static void dynamic_paint_prepare_effect_cb(void *userdata, const int index)
+static void dynamic_paint_prepare_effect_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintEffectData *data = userdata;
@@ -4858,8 +5060,13 @@ static int dynamicPaint_prepareEffectStep(
.surface = surface, .scene = scene,
.force = *force, .effectors = effectors,
};
- BLI_task_parallel_range(
- 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_prepare_effect_cb,
+ &settings);
/* calculate average values (single thread) */
for (int index = 0; index < sData->total_points; index++) {
@@ -4891,7 +5098,10 @@ static int dynamicPaint_prepareEffectStep(
/**
* Processes active effect step.
*/
-static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
+static void dynamic_paint_effect_spread_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintEffectData *data = userdata;
@@ -4936,7 +5146,10 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
}
}
-static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
+static void dynamic_paint_effect_shrink_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintEffectData *data = userdata;
@@ -4986,7 +5199,10 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
}
}
-static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
+static void dynamic_paint_effect_drip_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintEffectData *data = userdata;
@@ -5119,8 +5335,13 @@ static void dynamicPaint_doEffectStep(
DynamicPaintEffectData data = {
.surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
};
- BLI_task_parallel_range(
- 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_effect_spread_cb,
+ &settings);
}
/*
@@ -5135,8 +5356,13 @@ static void dynamicPaint_doEffectStep(
DynamicPaintEffectData data = {
.surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
};
- BLI_task_parallel_range(
- 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_effect_shrink_cb,
+ &settings);
}
/*
@@ -5157,14 +5383,22 @@ static void dynamicPaint_doEffectStep(
.eff_scale = eff_scale, .force = force,
.point_locks = point_locks,
};
- BLI_task_parallel_range(
- 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_effect_drip_cb,
+ &settings);
MEM_freeN(point_locks);
}
}
-static void dynamic_paint_border_cb(void *userdata, const int b_index)
+static void dynamic_paint_border_cb(
+ void *__restrict userdata,
+ const int b_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintEffectData *data = userdata;
@@ -5234,11 +5468,19 @@ static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
.surface = surface
};
- BLI_task_parallel_range(
- 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->adj_data->total_border > 1000);
+ BLI_task_parallel_range(0, sData->adj_data->total_border,
+ &data,
+ dynamic_paint_border_cb,
+ &settings);
}
-static void dynamic_paint_wave_step_cb(void *userdata, const int index)
+static void dynamic_paint_wave_step_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintEffectData *data = userdata;
@@ -5380,8 +5622,12 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
.wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope,
.dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1),
};
- BLI_task_parallel_range(
- 0, sData->total_points, &data, dynamic_paint_wave_step_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data, dynamic_paint_wave_step_cb,
+ &settings);
}
MEM_freeN(prevPoint);
@@ -5401,7 +5647,10 @@ typedef struct DynamicPaintDissolveDryData {
const float timescale;
} DynamicPaintDissolveDryData;
-static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
+static void dynamic_paint_surface_pre_step_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintDissolveDryData *data = userdata;
@@ -5524,7 +5773,10 @@ typedef struct DynamicPaintGenerateBakeData {
const bool new_bdata;
} DynamicPaintGenerateBakeData;
-static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index)
+static void dynamic_paint_generate_bake_data_cb(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const DynamicPaintGenerateBakeData *data = userdata;
@@ -5728,8 +5980,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Vie
.mvert = mvert, .canvas_verts = canvas_verts,
.do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
};
- BLI_task_parallel_range(
- 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_generate_bake_data_cb,
+ &settings);
MEM_freeN(canvas_verts);
@@ -5762,8 +6019,13 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene *
if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
DynamicPaintDissolveDryData data = {.surface = surface, .timescale = timescale};
- BLI_task_parallel_range(0, sData->total_points, &data,
- dynamic_paint_surface_pre_step_cb, sData->total_points > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points,
+ &data,
+ dynamic_paint_surface_pre_step_cb,
+ &settings);
}
/*
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index d6b28cfaf70..a314cc0a131 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -382,7 +382,7 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
nu2->orderv = 1;
nu2->flagu = CU_NURB_CYCLIC;
- bp = (BPoint *)MEM_callocN(4 * sizeof(BPoint), "underline_bp");
+ bp = (BPoint *)MEM_calloc_arrayN(4, sizeof(BPoint), "underline_bp");
copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
@@ -481,7 +481,7 @@ static void buildchar(Main *bmain, Curve *cu, ListBase *nubase, unsigned int cha
/* nu2->trim.last = 0; */
i = nu2->pntsu;
- bezt2 = (BezTriple *)MEM_mallocN(i * sizeof(BezTriple), "duplichar_bezt2");
+ bezt2 = (BezTriple *)MEM_malloc_arrayN(i, sizeof(BezTriple), "duplichar_bezt2");
if (bezt2 == NULL) {
MEM_freeN(nu2);
break;
@@ -635,11 +635,10 @@ struct TempLineInfo {
int wspace_nr; /* number of whitespaces of line */
};
-bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase,
+bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, Curve *cu, int mode, ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
struct CharTrans **r_chartransdata)
{
- Curve *cu = ob->data;
EditFont *ef = cu->editfont;
EditFontSelBox *selboxes = NULL;
VFont *vfont, *oldvfont;
@@ -670,7 +669,7 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
/* remark: do calculations including the trailing '\0' of a string
* because the cursor can be at that location */
- BLI_assert(ob->type == OB_FONT);
+ BLI_assert(ob == NULL || ob->type == OB_FONT);
/* Set font data */
vfont = cu->vfont;
@@ -693,28 +692,34 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
slen = cu->len_wchar;
/* Create unicode string */
- mem_tmp = MEM_mallocN(((slen + 1) * sizeof(wchar_t)), "convertedmem");
+ mem_tmp = MEM_malloc_arrayN((slen + 1), sizeof(wchar_t), "convertedmem");
+ if (!mem_tmp) {
+ return ok;
+ }
BLI_strncpy_wchar_from_utf8(mem_tmp, cu->str, slen + 1);
if (cu->strinfo == NULL) { /* old file */
- cu->strinfo = MEM_callocN((slen + 4) * sizeof(CharInfo), "strinfo compat");
+ cu->strinfo = MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat");
}
custrinfo = cu->strinfo;
+ if (!custrinfo) {
+ return ok;
+ }
mem = mem_tmp;
}
if (cu->tb == NULL)
- cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "TextBox compat");
+ cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat");
- if (ef) {
+ if (ef != NULL && ob != NULL) {
if (ef->selboxes)
MEM_freeN(ef->selboxes);
if (BKE_vfont_select_get(ob, &selstart, &selend)) {
ef->selboxes_len = (selend - selstart) + 1;
- ef->selboxes = MEM_callocN(ef->selboxes_len * sizeof(EditFontSelBox), "font selboxes");
+ ef->selboxes = MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes");
}
else {
ef->selboxes_len = 0;
@@ -725,10 +730,10 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
}
/* calc offset and rotation of each char */
- ct = chartransdata = MEM_callocN((slen + 1) * sizeof(struct CharTrans), "buildtext");
+ ct = chartransdata = MEM_calloc_arrayN((slen + 1), sizeof(struct CharTrans), "buildtext");
/* We assume the worst case: 1 character per line (is freed at end anyway) */
- lineinfo = MEM_mallocN(sizeof(*lineinfo) * (slen * 2 + 1), "lineinfo");
+ lineinfo = MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo");
linedist = cu->linedist;
@@ -1258,7 +1263,7 @@ makebreak:
cha = towupper(cha);
}
- if (info->mat_nr > (ob->totcol)) {
+ if (ob == NULL || info->mat_nr > (ob->totcol)) {
/* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */
info->mat_nr = 0;
}
@@ -1334,7 +1339,7 @@ bool BKE_vfont_to_curve_nubase(Main *bmain, Object *ob, int mode, ListBase *r_nu
{
BLI_assert(ob->type == OB_FONT);
- return BKE_vfont_to_curve_ex(bmain, ob, mode, r_nubase,
+ return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, r_nubase,
NULL, NULL, NULL, NULL);
}
@@ -1342,7 +1347,7 @@ bool BKE_vfont_to_curve(Main *bmain, Object *ob, int mode)
{
Curve *cu = ob->data;
- return BKE_vfont_to_curve_ex(bmain, ob, mode, &cu->nurb, NULL, NULL, NULL, NULL);
+ return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL);
}
@@ -1374,12 +1379,12 @@ void BKE_vfont_clipboard_set(const wchar_t *text_buf, const CharInfo *info_buf,
/* clean previous buffers*/
BKE_vfont_clipboard_free();
- text = MEM_mallocN((len + 1) * sizeof(wchar_t), __func__);
+ text = MEM_malloc_arrayN((len + 1), sizeof(wchar_t), __func__);
if (text == NULL) {
return;
}
- info = MEM_mallocN(len * sizeof(CharInfo), __func__);
+ info = MEM_malloc_arrayN(len, sizeof(CharInfo), __func__);
if (info == NULL) {
MEM_freeN(text);
return;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 686fe3bda93..b656d2cf7c0 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config)
BLI_listbase_clear(&config->linesets);
}
-void BKE_freestyle_config_free(FreestyleConfig *config)
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user)
{
FreestyleLineSet *lineset;
for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
if (lineset->group) {
- id_us_min(&lineset->group->id);
+ if (do_id_user) {
+ id_us_min(&lineset->group->id);
+ }
lineset->group = NULL;
}
if (lineset->linestyle) {
- id_us_min(&lineset->linestyle->id);
+ if (do_id_user) {
+ id_us_min(&lineset->linestyle->id);
+ }
lineset->linestyle = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 7c2eefe657c..ca6d92efa80 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -55,6 +55,8 @@
#include "BKE_object.h"
#include "BKE_scene.h"
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
/** Free (or release) any data used by this group (does not free the group itself). */
void BKE_group_free(Group *group)
{
@@ -80,17 +82,13 @@ void BKE_group_init(Group *group)
{
group->collection = MEM_callocN(sizeof(SceneCollection), __func__);
BLI_strncpy(group->collection->name, "Master Collection", sizeof(group->collection->name));
- group->view_layer = NULL; /* groups are not calloced. */
group->view_layer = BKE_view_layer_group_add(group);
/* Unlink the master collection. */
BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.first);
/* Create and link a new default collection. */
- SceneCollection *defaut_collection = BKE_collection_add(&group->id,
- NULL,
- COLLECTION_TYPE_GROUP_INTERNAL,
- "Default Collection");
+ SceneCollection *defaut_collection = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, NULL);
BKE_collection_link(group->view_layer, defaut_collection);
}
@@ -137,9 +135,10 @@ void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *gro
BKE_collection_copy_data(master_collection_dst, master_collection_src,
flag_subdata);
+ group_dst->view_layer = MEM_dupallocN(group_src->view_layer);
BKE_view_layer_copy_data(group_dst->view_layer, group_src->view_layer,
- master_collection_dst, master_collection_src,
- flag_subdata);
+ master_collection_dst, master_collection_src,
+ flag_subdata);
}
Group *BKE_group_copy(Main *bmain, const Group *group)
@@ -372,10 +371,43 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx
/* only do existing tags, as set by regular depsgraph */
FOREACH_GROUP_OBJECT(group, object)
{
- if (object->id.tag & LIB_TAG_ID_RECALC_ALL) {
+ if (object->id.recalc & ID_RECALC_ALL) {
BKE_object_handle_update(eval_ctx, scene, object);
}
}
FOREACH_GROUP_OBJECT_END
}
}
+
+/* ******** Dependency graph evaluation ******** */
+
+static void group_eval_layer_collections(
+ const struct EvaluationContext *eval_ctx,
+ Group *group,
+ ListBase *layer_collections,
+ LayerCollection *parent_layer_collection)
+{
+ BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) {
+ /* Evaluate layer collection itself. */
+ BKE_layer_eval_layer_collection(eval_ctx,
+ layer_collection,
+ parent_layer_collection);
+ /* Evaluate nested collections. */
+ group_eval_layer_collections(eval_ctx,
+ group,
+ &layer_collection->layer_collections,
+ layer_collection);
+ }
+}
+
+void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx,
+ Group *group)
+{
+ DEBUG_PRINT("%s on %s (%p)\n", __func__, group->id.name, group);
+ BKE_layer_eval_layer_collection_pre(eval_ctx, &group->id, group->view_layer);
+ group_eval_layer_collections(eval_ctx,
+ group,
+ &group->view_layer->layer_collections,
+ NULL);
+ BKE_layer_eval_layer_collection_post(eval_ctx, group->view_layer);
+}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index b00a62a1a87..33a665ba06e 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -1094,4 +1094,15 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
+void IDP_Reset(IDProperty *prop, const IDProperty *reference)
+{
+ if (prop == NULL) {
+ return;
+ }
+ IDP_ClearProperty(prop);
+ if (reference != NULL) {
+ IDP_MergeGroup(prop, reference, true);
+ }
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 59fadffe22a..d720dc41abf 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -113,9 +113,9 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
/* quick lookup: supports 1 million frames, thousand passes */
#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
#define IMA_INDEX_FRAME(index) ((index) >> 10)
-/*
+#if 0
#define IMA_INDEX_PASS(index) (index & ~1023)
-*/
+#endif
/* ******** IMAGE CACHE ************* */
@@ -1696,7 +1696,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
int digits = 1;
if (scene->r.efra > 9)
- digits = 1 + (int) log10(scene->r.efra);
+ digits = integer_digits_i(scene->r.efra);
BLI_snprintf(fmtstr, sizeof(fmtstr), do_prefix ? "Frame %%0%di" : "%%0%di", digits);
BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), fmtstr, scene->r.cfra);
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 90247441631..00cf40f06cd 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1559,7 +1559,7 @@ static void ipo_to_animdata(ID *id, Ipo *ipo, char actname[], char constname[],
BLI_snprintf(nameBuf, sizeof(nameBuf), "CDA:%s", ipo->id.name + 2);
- adt->action = add_empty_action(G.main, nameBuf);
+ adt->action = BKE_action_add(G.main, nameBuf);
if (G.debug & G_DEBUG) printf("\t\tadded new action - '%s'\n", nameBuf);
}
@@ -2107,7 +2107,7 @@ void do_versions_ipos_to_animato(Main *main)
bAction *new_act;
/* add a new action for this, and convert all data into that action */
- new_act = add_empty_action(main, id->name + 2);
+ new_act = BKE_action_add(main, id->name + 2);
ipo_to_animato(NULL, ipo, NULL, NULL, NULL, NULL, &new_act->curves, &drivers);
new_act->idroot = ipo->blocktype;
}
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index d8b9b14d755..931fc09d235 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -165,7 +165,7 @@ Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la)
return la_copy;
}
-Lamp *localize_lamp(Lamp *la)
+Lamp *BKE_lamp_localize(Lamp *la)
{
/* TODO replace with something like
* Lamp *la_copy;
@@ -181,7 +181,7 @@ Lamp *localize_lamp(Lamp *la)
for (a = 0; a < MAX_MTEX; a++) {
if (lan->mtex[a]) {
- lan->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_lamp");
+ lan->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
}
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 84eb4ee2e33..c6515d0c47a 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -42,6 +42,8 @@
#include "BKE_node.h"
#include "BKE_workspace.h"
+#include "DEG_depsgraph.h"
+
#include "DNA_group_types.h"
#include "DNA_ID.h"
#include "DNA_layer_types.h"
@@ -97,7 +99,7 @@ ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const st
/**
* This is a placeholder to know which areas of the code need to be addressed for the Workspace changes.
- * Never use this, you should either use BKE_view_layer_workspace_active or get ViewLayer explicitly.
+ * Never use this, you should either use BKE_view_layer_from_workspace_get or get ViewLayer explicitly.
*/
ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
{
@@ -161,10 +163,15 @@ ViewLayer *BKE_view_layer_group_add(Group *group)
return view_layer;
}
+void BKE_view_layer_free(ViewLayer *view_layer)
+{
+ BKE_view_layer_free_ex(view_layer, true);
+}
+
/**
* Free (or release) any data used by this ViewLayer.
*/
-void BKE_view_layer_free(ViewLayer *view_layer)
+void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
{
view_layer->basact = NULL;
@@ -203,7 +210,7 @@ void BKE_view_layer_free(ViewLayer *view_layer)
MEM_SAFE_FREE(view_layer->stats);
- BKE_freestyle_config_free(&view_layer->freestyle_config);
+ BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
if (view_layer->id_properties) {
IDP_FreeProperty(view_layer->id_properties);
@@ -1018,7 +1025,8 @@ static void layer_collection_enable(ViewLayer *view_layer, LayerCollection *lc)
/**
* Enable collection
* Add its objects bases to ViewLayer
- * Depsgraph needs to be rebuilt afterwards
+ *
+ * Only around for doversion.
*/
void BKE_collection_enable(ViewLayer *view_layer, LayerCollection *lc)
{
@@ -1030,45 +1038,16 @@ void BKE_collection_enable(ViewLayer *view_layer, LayerCollection *lc)
layer_collection_enable(view_layer, lc);
}
-/**
- * Recursively disable nested collections
- */
-static void layer_collection_disable(ViewLayer *view_layer, LayerCollection *lc)
-{
- layer_collection_objects_unpopulate(view_layer, lc);
-
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
- layer_collection_disable(view_layer, nlc);
- }
-}
-
-/**
- * Disable collection
- * Remove all its object bases from ViewLayer
- * Depsgraph needs to be rebuilt afterwards
- */
-void BKE_collection_disable(ViewLayer *view_layer, LayerCollection *lc)
-{
- if ((lc->flag & COLLECTION_DISABLED) != 0) {
- return;
- }
-
- lc->flag |= COLLECTION_DISABLED;
- layer_collection_disable(view_layer, lc);
-}
-
static void layer_collection_object_add(ViewLayer *view_layer, LayerCollection *lc, Object *ob)
{
Base *base = object_base_add(view_layer, ob);
- /* Only add an object once - prevent SceneCollection->objects and
- * SceneCollection->filter_objects to add the same object. */
-
+ /* Only add an object once. */
if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) {
return;
}
- bool is_visible = (lc->flag & COLLECTION_VISIBLE) != 0;
+ bool is_visible = ((lc->flag & COLLECTION_VIEWPORT) != 0) && ((lc->flag & COLLECTION_DISABLED) == 0);
bool is_selectable = is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0);
if (is_visible) {
@@ -1104,7 +1083,6 @@ static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollec
static void layer_collection_populate(ViewLayer *view_layer, LayerCollection *lc, SceneCollection *sc)
{
layer_collection_objects_populate(view_layer, lc, &sc->objects);
- layer_collection_objects_populate(view_layer, lc, &sc->filter_objects);
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
layer_collection_add(view_layer, lc, nsc);
@@ -1117,7 +1095,7 @@ static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollect
LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
lc->scene_collection = sc;
- lc->flag = COLLECTION_VISIBLE | COLLECTION_SELECTABLE;
+ lc->flag = COLLECTION_SELECTABLE | COLLECTION_VIEWPORT | COLLECTION_RENDER;
lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
collection_engine_settings_init(lc->properties, false);
@@ -1214,7 +1192,6 @@ void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object
/**
* Remove the equivalent object base to all layers that have this collection
- * also remove all reference to ob in the filter_objects
*/
void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob)
{
@@ -2118,7 +2095,25 @@ static const char *collection_type_lookup[] =
"Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */
};
-void BKE_layer_eval_layer_collection(const struct EvaluationContext *UNUSED(eval_ctx),
+/**
+ * \note We can't use layer_collection->flag because of 3 level nesting (where parent is visible, but not grand-parent)
+ * So layer_collection->flag_evaluated is expected to be up to date with layer_collection->flag.
+ */
+static bool layer_collection_visible_get(const EvaluationContext *eval_ctx, LayerCollection *layer_collection)
+{
+ if (layer_collection->flag_evaluated & COLLECTION_DISABLED) {
+ return false;
+ }
+
+ if (eval_ctx->mode == DAG_EVAL_VIEWPORT) {
+ return (layer_collection->flag_evaluated & COLLECTION_VIEWPORT) != 0;
+ }
+ else {
+ return (layer_collection->flag_evaluated & COLLECTION_RENDER) != 0;
+ }
+}
+
+void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx,
LayerCollection *layer_collection,
LayerCollection *parent_layer_collection)
{
@@ -2134,15 +2129,22 @@ void BKE_layer_eval_layer_collection(const struct EvaluationContext *UNUSED(eval
/* visibility */
layer_collection->flag_evaluated = layer_collection->flag;
- bool is_visible = (layer_collection->flag & COLLECTION_VISIBLE) != 0;
- bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0);
if (parent_layer_collection != NULL) {
- is_visible &= (parent_layer_collection->flag_evaluated & COLLECTION_VISIBLE) != 0;
- is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0;
- layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated;
+ if (layer_collection_visible_get(eval_ctx, parent_layer_collection) == false) {
+ layer_collection->flag_evaluated |= COLLECTION_DISABLED;
+ }
+
+ if ((parent_layer_collection->flag_evaluated & COLLECTION_DISABLED) ||
+ (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) == 0)
+ {
+ layer_collection->flag_evaluated &= ~COLLECTION_SELECTABLE;
+ }
}
+ const bool is_visible = layer_collection_visible_get(eval_ctx, layer_collection);
+ const bool is_selectable = is_visible && ((layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0);
+
/* overrides */
if (is_visible) {
if (parent_layer_collection == NULL) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 0ef1fe52994..066b3e34b0d 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -2249,8 +2249,8 @@ void BKE_library_make_local(
* was not used locally would be a nasty bug! */
if (is_local || is_lib) {
printf("Warning, made-local proxy object %s will loose its link to %s, "
- "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
- id->newid->name, ob->proxy->id.name, is_local, is_lib);
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
+ id->newid->name, ob->proxy->id.name, is_local, is_lib);
}
else {
/* we can switch the proxy'ing from the linked-in to the made-local proxy.
@@ -2306,8 +2306,8 @@ void BKE_library_make_local(
* was not used locally would be a nasty bug! */
else if (is_local || is_lib) {
printf("Warning, made-local proxy object %s will loose its link to %s, "
- "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
- id->newid->name, ob->proxy->id.name, is_local, is_lib);
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
+ id->newid->name, ob->proxy->id.name, is_local, is_lib);
}
else {
/* we can switch the proxy'ing from the linked-in to the made-local proxy.
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
index 22896cff64a..8b8658921b5 100644
--- a/source/blender/blenkernel/intern/library_override.c
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -66,16 +66,26 @@ IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id)
BLI_assert(reference_id == NULL || reference_id->lib != NULL);
BLI_assert(local_id->override_static == NULL);
- if (reference_id != NULL && reference_id->override_static != NULL && reference_id->override_static->reference == NULL) {
- /* reference ID has an override template, use it! */
- BKE_override_static_copy(local_id, reference_id);
+ ID *ancestor_id;
+ for (ancestor_id = reference_id;
+ ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL;
+ ancestor_id = ancestor_id->override_static->reference);
+
+ if (ancestor_id != NULL && ancestor_id->override_static != NULL) {
+ /* Original ID has a template, use it! */
+ BKE_override_static_copy(local_id, ancestor_id);
+ if (local_id->override_static->reference != reference_id) {
+ id_us_min(local_id->override_static->reference);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ }
return local_id->override_static;
}
/* Else, generate new empty override. */
local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
local_id->override_static->reference = reference_id;
- id_us_plus(reference_id);
+ id_us_plus(local_id->override_static->reference);
local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
/* TODO do we want to add tag or flag to referee to mark it as such? */
return local_id->override_static;
@@ -142,12 +152,8 @@ void BKE_override_static_free(struct IDOverrideStatic **override)
*override = NULL;
}
-/** Create an overriden local copy of linked reference. */
-ID *BKE_override_static_create_from(Main *bmain, ID *reference_id)
+static ID *override_static_create_from(Main *bmain, ID *reference_id)
{
- BLI_assert(reference_id != NULL);
- BLI_assert(reference_id->lib != NULL);
-
ID *local_id;
if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) {
@@ -158,12 +164,63 @@ ID *BKE_override_static_create_from(Main *bmain, ID *reference_id)
BKE_override_static_init(local_id, reference_id);
local_id->flag |= LIB_OVERRIDE_STATIC_AUTO;
+ return local_id;
+}
+
+
+/** Create an overriden local copy of linked reference. */
+ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id)
+{
+ BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id->lib != NULL);
+
+ ID *local_id = override_static_create_from(bmain, reference_id);
+
/* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */
BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
return local_id;
}
+/** Create overriden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set id->newid of overridden libs with newly created overrides, caller is responsible to clean those pointers
+ * before/after usage as needed.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
+bool BKE_override_static_create_from_tag(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool ret = true;
+
+ const int num_types = a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
+ if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */
+ a = num_types;
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) {
+ ID *local_id = reference_id->newid;
+ BKE_libblock_remap(bmain, reference_id, local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+ }
+ }
+ }
+
+ return ret;
+}
+
/**
* Find override property from given RNA path, if it exists.
*/
@@ -384,7 +441,10 @@ bool BKE_override_static_status_check_local(ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(reference, &rnaptr_reference);
- if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) {
+ if (!RNA_struct_override_matches(
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
return false;
}
@@ -428,7 +488,10 @@ bool BKE_override_static_status_check_reference(ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(reference, &rnaptr_reference);
- if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) {
+ if (!RNA_struct_override_matches(
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
return false;
}
@@ -459,8 +522,17 @@ bool BKE_override_static_operations_create(ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
- ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL);
+ eRNAOverrideMatchResult report_flags = 0;
+ RNA_struct_override_matches(
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags);
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
+ ret = true;
+ }
#ifndef NDEBUG
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
+ printf("We did restore some properties of %s from its reference.\n", local->name);
+ }
if (ret) {
printf("We did generate static override rules for %s\n", local->name);
}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index e25a354c8af..6c5931263d8 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -449,10 +449,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
for (LinkData *link = sc->objects.first; link; link = link->next) {
CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER);
}
-
- for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
- CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER);
- }
}
FOREACH_SCENE_COLLECTION_END
@@ -773,11 +769,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_GR:
{
Group *group = (Group *) id;
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_BASE(group, base)
{
- CALLBACK_INVOKE(object, IDWALK_CB_USER_ONE);
+ CALLBACK_INVOKE(base->object, IDWALK_CB_USER_ONE);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_BASE_END
break;
}
@@ -984,6 +980,8 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
bScreen *screen = BKE_workspace_layout_screen_get(layout);
+ /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
+ * However we can't acess layout->screen here since we are outside the workspace project. */
CALLBACK_INVOKE(screen, IDWALK_CB_NOP);
/* allow callback to set a different screen */
BKE_workspace_layout_screen_set(layout, screen);
@@ -1092,7 +1090,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return true;
#endif
case ID_ME:
- return ELEM(id_type_used, ID_ME, ID_KE, ID_MA);
+ return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM);
case ID_CU:
return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF);
case ID_MB:
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index fb672cb8b9f..6d4c4082810 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -205,9 +205,11 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
id->tag |= LIB_TAG_DOIT;
}
- /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
+ /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
+ * (otherwise, we follow common NEVER_NULL flags).
+ * (skipped_indirect too). */
if ((is_never_null && skip_never_null) ||
- (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
(skip_indirect && is_indirect) ||
(is_reference && skip_reference))
{
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index d5dbbe873a2..057b6aaaf65 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -52,6 +52,7 @@ void BKE_lightprobe_init(LightProbe *probe)
probe->clipend = 40.0f;
probe->vis_bias = 1.0f;
probe->vis_blur = 0.2f;
+ probe->intensity = 1.0f;
probe->data_draw_size = 1.0f;
probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 3a69eb2b86b..2fc4c81cb0b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -44,13 +44,13 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
#include "BKE_node.h"
-#include "BKE_texture.h"
#include "BKE_colortools.h"
#include "BKE_animsys.h"
@@ -296,39 +296,39 @@ LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyl
switch (type) {
case LS_MODIFIER_ALONG_STROKE:
- ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = BKE_colorband_add(true);
break;
case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = BKE_colorband_add(true);
((LineStyleColorModifier_DistanceFromCamera *)m)->range_min = 0.0f;
((LineStyleColorModifier_DistanceFromCamera *)m)->range_max = 10000.0f;
break;
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
- ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = BKE_colorband_add(true);
((LineStyleColorModifier_DistanceFromObject *)m)->range_min = 0.0f;
((LineStyleColorModifier_DistanceFromObject *)m)->range_max = 10000.0f;
break;
case LS_MODIFIER_MATERIAL:
- ((LineStyleColorModifier_Material *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_Material *)m)->color_ramp = BKE_colorband_add(true);
((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_LINE;
break;
case LS_MODIFIER_TANGENT:
- ((LineStyleColorModifier_Tangent *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_Tangent *)m)->color_ramp = BKE_colorband_add(true);
break;
case LS_MODIFIER_NOISE:
- ((LineStyleColorModifier_Noise *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_Noise *)m)->color_ramp = BKE_colorband_add(true);
((LineStyleColorModifier_Noise *)m)->amplitude = 10.0f;
((LineStyleColorModifier_Noise *)m)->period = 10.0f;
((LineStyleColorModifier_Noise *)m)->seed = 512;
break;
case LS_MODIFIER_CREASE_ANGLE:
- ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp = BKE_colorband_add(true);
((LineStyleColorModifier_CreaseAngle *)m)->min_angle = 0.0f;
((LineStyleColorModifier_CreaseAngle *)m)->max_angle = DEG2RADF(180.0f);
break;
case LS_MODIFIER_CURVATURE_3D:
- ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp = BKE_colorband_add(true);
((LineStyleColorModifier_Curvature_3D *)m)->min_curvature = 0.0f;
((LineStyleColorModifier_Curvature_3D *)m)->max_curvature = 0.5f;
break;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index eaa2f89ab82..3256c16e2f6 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -1459,18 +1459,6 @@ void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newfram
}
}
-void BKE_mask_update_scene(Main *bmain, Scene *scene)
-{
- Mask *mask;
-
- for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- if (mask->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
- bool do_new_frame = (mask->id.tag & LIB_TAG_ID_RECALC_DATA) != 0;
- BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame);
- }
- }
-}
-
void BKE_mask_parent_init(MaskParent *parent)
{
parent->id_type = ID_MC;
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 104bb0c07a6..76d16334630 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1434,7 +1434,10 @@ typedef struct MaskRasterizeBufferData {
float *buffer;
} MaskRasterizeBufferData;
-static void maskrasterize_buffer_cb(void *userdata, int y)
+static void maskrasterize_buffer_cb(
+ void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
MaskRasterizeBufferData *data = userdata;
@@ -1474,5 +1477,11 @@ void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
.width = width,
.buffer = buffer
};
- BLI_task_parallel_range(0, (int)height, &data, maskrasterize_buffer_cb, height * width > 10000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((size_t)height * width > 10000);
+ BLI_task_parallel_range(0, (int)height,
+ &data,
+ maskrasterize_buffer_cb,
+ &settings);
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 585567b6665..7235aa0aaf6 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -272,7 +272,7 @@ Material *BKE_material_copy(Main *bmain, const Material *ma)
}
/* XXX (see above) material copy without adding to main dbase */
-Material *localize_material(Material *ma)
+Material *BKE_material_localize(Material *ma)
{
/* TODO replace with something like
* Material *ma_copy;
@@ -1159,7 +1159,6 @@ bool material_in_material(Material *parmat, Material *mat)
bool BKE_object_material_slot_remove(Object *ob)
{
Material *mao, ***matarar;
- Object *obt;
short *totcolp;
short a, actcol;
@@ -1207,11 +1206,13 @@ bool BKE_object_material_slot_remove(Object *ob)
}
actcol = ob->actcol;
- obt = G.main->object.first;
- while (obt) {
-
+
+ for (Object *obt = G.main->object.first; obt; obt = obt->id.next) {
if (obt->data == ob->data) {
-
+ /* Can happen when object material lists are used, see: T52953 */
+ if (actcol > obt->totcol) {
+ continue;
+ }
/* WATCH IT: do not use actcol from ob or from obt (can become zero) */
mao = obt->mat[actcol - 1];
if (mao)
@@ -1231,7 +1232,6 @@ bool BKE_object_material_slot_remove(Object *ob)
obt->matbits = NULL;
}
}
- obt = obt->id.next;
}
/* check indices from mesh */
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 8f41f0611d4..3217c234718 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -823,7 +823,7 @@ float (*BKE_mesh_orco_verts_get(Object *ob))[3]
float (*vcos)[3] = NULL;
/* Get appropriate vertex coordinates */
- vcos = MEM_callocN(sizeof(*vcos) * me->totvert, "orco mesh");
+ vcos = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
mvert = tme->mvert;
totvert = min_ii(tme->totvert, me->totvert);
@@ -1062,7 +1062,7 @@ static void make_edges_mdata_extend(MEdge **r_alledge, int *r_totedge,
unsigned int e_index = totedge;
*r_alledge = medge = (*r_alledge ? MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) :
- MEM_callocN(sizeof(MEdge) * totedge_new, __func__));
+ MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__));
medge += totedge;
totedge += totedge_new;
@@ -1182,13 +1182,13 @@ int BKE_mesh_nurbs_displist_to_mdata(
return -1;
}
- *r_allvert = mvert = MEM_callocN(sizeof(MVert) * totvert, "nurbs_init mvert");
- *r_alledge = medge = MEM_callocN(sizeof(MEdge) * totedge, "nurbs_init medge");
- *r_allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop"); // totloop
- *r_allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak, "nurbs_init mloop");
+ *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert");
+ *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge");
+ *r_allloop = mloop = MEM_calloc_arrayN(totvlak, 4 * sizeof(MLoop), "nurbs_init mloop"); // totloop
+ *r_allpoly = mpoly = MEM_calloc_arrayN(totvlak, sizeof(MPoly), "nurbs_init mloop");
if (r_alluv)
- *r_alluv = mloopuv = MEM_callocN(sizeof(MLoopUV) * totvlak * 4, "nurbs_init mloopuv");
+ *r_alluv = mloopuv = MEM_calloc_arrayN(totvlak, 4 * sizeof(MLoopUV), "nurbs_init mloopuv");
/* verts and faces */
vertcount = 0;
@@ -1436,6 +1436,17 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
me->totcol = cu->totcol;
me->mat = cu->mat;
+ /* Copy evaluated texture space from curve to mesh.
+ *
+ * Note that we disable auto texture space feature since that will cause
+ * texture space to evaluate differently for curve and mesh, since curve
+ * uses CV to calculate bounding box, and mesh uses what is coming from
+ * tessellated curve.
+ */
+ me->texflag = cu->texflag & ~CU_AUTOSPACE;
+ copy_v3_v3(me->loc, cu->loc);
+ copy_v3_v3(me->size, cu->size);
+ copy_v3_v3(me->rot, cu->rot);
BKE_mesh_texspace_calc(me);
cu->mat = NULL;
@@ -1516,7 +1527,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
ListBase edges = {NULL, NULL};
/* get boundary edges */
- edge_users = MEM_callocN(sizeof(int) * dm_totedge, __func__);
+ edge_users = MEM_calloc_arrayN(dm_totedge, sizeof(int), __func__);
for (i = 0, mp = mpoly; i < dm_totpoly; i++, mp++) {
MLoop *ml = &mloop[mp->loopstart];
int j;
@@ -1612,7 +1623,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */
nu->resolu = 12;
- nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * totpoly, "bpoints");
+ nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints");
/* add points */
vl = polyline.first;
@@ -1768,7 +1779,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
{
int i, numVerts = me->totvert;
- float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1");
+ float (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "vertexcos1");
if (r_numVerts) *r_numVerts = numVerts;
for (i = 0; i < numVerts; i++)
@@ -1904,7 +1915,7 @@ void BKE_mesh_ensure_navmesh(Mesh *me)
int i;
int numFaces = me->totpoly;
int *recastData;
- recastData = (int *)MEM_mallocN(numFaces * sizeof(int), __func__);
+ recastData = (int *)MEM_malloc_arrayN(numFaces, sizeof(int), __func__);
for (i = 0; i < numFaces; i++) {
recastData[i] = i + 1;
}
@@ -1992,7 +2003,7 @@ void BKE_mesh_mselect_validate(Mesh *me)
return;
mselect_src = me->mselect;
- mselect_dst = MEM_mallocN(sizeof(MSelect) * (me->totselect), "Mesh selection history");
+ mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history");
for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) {
int index = mselect_src[i_src].index;
@@ -2135,7 +2146,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
free_polynors = false;
}
else {
- polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
+ polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
BKE_mesh_calc_normals_poly(
mesh->mvert, NULL, mesh->totvert,
mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
@@ -2460,6 +2471,11 @@ Mesh *BKE_mesh_new_from_object(
/* copies the data */
copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
+ /* make sure texture space is calculated for a copy of curve,
+ * it will be used for the final result.
+ */
+ BKE_curve_texspace_calc(copycu);
+
/* temporarily set edit so we get updates from edit mode, but
* also because for text datablocks copying it while in edit
* mode gives invalid data structures */
@@ -2490,8 +2506,6 @@ Mesh *BKE_mesh_new_from_object(
return NULL;
}
- BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
-
BKE_libblock_free_us(bmain, tmpobj);
/* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index c21c16adc85..00d1b29caf8 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -127,8 +127,8 @@ void BKE_mesh_calc_normals_mapping_ex(
return;
}
- if (!pnors) pnors = MEM_callocN(sizeof(float[3]) * (size_t)numPolys, __func__);
- /* if (!fnors) fnors = MEM_callocN(sizeof(float[3]) * numFaces, "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
+ if (!pnors) pnors = MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__);
+ /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
if (only_face_normals == false) {
@@ -173,10 +173,14 @@ typedef struct MeshCalcNormalsData {
const MLoop *mloop;
MVert *mverts;
float (*pnors)[3];
+ float (*lnors_weighted)[3];
float (*vnors)[3];
} MeshCalcNormalsData;
-static void mesh_calc_normals_poly_task_cb(void *userdata, const int pidx)
+static void mesh_calc_normals_poly_cb(
+ void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
MeshCalcNormalsData *data = userdata;
const MPoly *mp = &data->mpolys[pidx];
@@ -184,7 +188,10 @@ static void mesh_calc_normals_poly_task_cb(void *userdata, const int pidx)
BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
}
-static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
+static void mesh_calc_normals_poly_prepare_cb(
+ void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
MeshCalcNormalsData *data = userdata;
const MPoly *mp = &data->mpolys[pidx];
@@ -193,7 +200,7 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
float pnor_temp[3];
float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
- float (*vnors)[3] = data->vnors;
+ float (*lnors_weighted)[3] = data->lnors_weighted;
const int nverts = mp->totloop;
float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts);
@@ -220,42 +227,71 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
v_prev = v_curr;
}
if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
- pnor[2] = 1.0f; /* other axis set to 0.0 */
+ pnor[2] = 1.0f; /* other axes set to 0.0 */
}
}
/* accumulate angle weighted face normal */
- /* inline version of #accumulate_vertex_normals_poly_v3 */
+ /* inline version of #accumulate_vertex_normals_poly_v3,
+ * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */
{
const float *prev_edge = edgevecbuf[nverts - 1];
for (i = 0; i < nverts; i++) {
+ const int lidx = mp->loopstart + i;
const float *cur_edge = edgevecbuf[i];
/* calculate angle between the two poly edges incident on
* this vertex */
const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
- /* accumulate */
- for (int k = 3; k--; ) {
- atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac);
- }
+ /* Store for later accumulation */
+ mul_v3_v3fl(lnors_weighted[lidx], pnor, fac);
+
prev_edge = cur_edge;
}
}
+}
+static void mesh_calc_normals_poly_accum_cb(
+ void *__restrict userdata,
+ const int lidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MeshCalcNormalsData *data = userdata;
+
+ add_v3_v3(data->vnors[data->mloop[lidx].v], data->lnors_weighted[lidx]);
+}
+
+static void mesh_calc_normals_poly_finalize_cb(
+ void *__restrict userdata,
+ const int vidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MeshCalcNormalsData *data = userdata;
+
+ MVert *mv = &data->mverts[vidx];
+ float *no = data->vnors[vidx];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
}
void BKE_mesh_calc_normals_poly(
MVert *mverts, float (*r_vertnors)[3], int numVerts,
const MLoop *mloop, const MPoly *mpolys,
- int UNUSED(numLoops), int numPolys, float (*r_polynors)[3],
+ int numLoops, int numPolys, float (*r_polynors)[3],
const bool only_face_normals)
{
float (*pnors)[3] = r_polynors;
- float (*vnors)[3] = r_vertnors;
- bool free_vnors = false;
- int i;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
if (only_face_normals) {
BLI_assert((pnors != NULL) || (numPolys == 0));
@@ -265,13 +301,17 @@ void BKE_mesh_calc_normals_poly(
.mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors,
};
- BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_task_cb, (numPolys > BKE_MESH_OMP_LIMIT));
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
return;
}
+ float (*vnors)[3] = r_vertnors;
+ float (*lnors_weighted)[3] = MEM_malloc_arrayN((size_t)numLoops, sizeof(*lnors_weighted), __func__);
+ bool free_vnors = false;
+
/* first go through and calculate normals for all the polys */
if (vnors == NULL) {
- vnors = MEM_callocN(sizeof(*vnors) * (size_t)numVerts, __func__);
+ vnors = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
free_vnors = true;
}
else {
@@ -279,26 +319,23 @@ void BKE_mesh_calc_normals_poly(
}
MeshCalcNormalsData data = {
- .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors, .vnors = vnors,
+ .mpolys = mpolys, .mloop = mloop, .mverts = mverts,
+ .pnors = pnors, .lnors_weighted = lnors_weighted, .vnors = vnors
};
- BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_accum_task_cb, (numPolys > BKE_MESH_OMP_LIMIT));
+ /* Compute poly normals, and prepare weighted loop normals. */
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings);
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float *no = vnors[i];
+ /* Actually accumulate weighted loop normals into vertex ones. */
+ BLI_task_parallel_range(0, numLoops, &data, mesh_calc_normals_poly_accum_cb, &settings);
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- normalize_v3_v3(no, mv->co);
- }
-
- normal_float_to_short_v3(mv->no, no);
- }
+ /* Normalize and validate computed vertex normals. */
+ BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
if (free_vnors) {
MEM_freeN(vnors);
}
+ MEM_freeN(lnors_weighted);
}
void BKE_mesh_calc_normals(Mesh *mesh)
@@ -319,10 +356,14 @@ void BKE_mesh_calc_normals_tessface(
const MFace *mfaces, int numFaces,
float (*r_faceNors)[3])
{
- float (*tnorms)[3] = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, "tnorms");
- float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_callocN(sizeof(*fnors) * (size_t)numFaces, "meshnormals");
+ float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
+ float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_calloc_arrayN((size_t)numFaces, sizeof(*fnors), "meshnormals");
int i;
+ if (!tnorms || !fnors) {
+ goto cleanup;
+ }
+
for (i = 0; i < numFaces; i++) {
const MFace *mf = &mfaces[i];
float *f_no = fnors[i];
@@ -351,6 +392,7 @@ void BKE_mesh_calc_normals_tessface(
normal_float_to_short_v3(mv->no, no);
}
+cleanup:
MEM_freeN(tnorms);
if (fnors != r_faceNors)
@@ -363,10 +405,14 @@ void BKE_mesh_calc_normals_looptri(
const MLoopTri *looptri, int looptri_num,
float (*r_tri_nors)[3])
{
- float (*tnorms)[3] = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, "tnorms");
- float (*fnors)[3] = (r_tri_nors) ? r_tri_nors : MEM_callocN(sizeof(*fnors) * (size_t)looptri_num, "meshnormals");
+ float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
+ float (*fnors)[3] = (r_tri_nors) ? r_tri_nors : MEM_calloc_arrayN((size_t)looptri_num, sizeof(*fnors), "meshnormals");
int i;
+ if (!tnorms || !fnors) {
+ goto cleanup;
+ }
+
for (i = 0; i < looptri_num; i++) {
const MLoopTri *lt = &looptri[i];
float *f_no = fnors[i];
@@ -397,6 +443,7 @@ void BKE_mesh_calc_normals_looptri(
normal_float_to_short_v3(mv->no, no);
}
+cleanup:
MEM_freeN(tnorms);
if (fnors != r_tri_nors)
@@ -1137,7 +1184,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
if (pool) {
if (data_idx == 0) {
- data_buff = MEM_callocN(sizeof(*data_buff) * LOOP_SPLIT_TASK_BLOCK_SIZE, __func__);
+ data_buff = MEM_calloc_arrayN(LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
}
data = &data_buff[data_idx];
}
@@ -1267,10 +1314,10 @@ void BKE_mesh_normals_loop_split(
* store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
* Note also that lose edges always have both values set to 0!
*/
- int (*edge_to_loops)[2] = MEM_callocN(sizeof(*edge_to_loops) * (size_t)numEdges, __func__);
+ int (*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(*loop_to_poly) * (size_t)numLoops, __func__);
+ int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
MPoly *mp;
int mp_index;
@@ -1424,8 +1471,8 @@ static void mesh_normals_loop_custom_set(
*/
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__);
+ float (*lnors)[3] = MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__);
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __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;
@@ -1640,7 +1687,7 @@ void BKE_mesh_normals_loop_to_vertex(
const MLoop *ml;
int i;
- int *vert_loops_nbr = MEM_callocN(sizeof(*vert_loops_nbr) * (size_t)numVerts, __func__);
+ int *vert_loops_nbr = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vert_loops_nbr), __func__);
copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f);
@@ -2479,9 +2526,9 @@ int BKE_mesh_recalc_tessellation(
/* allocate the length of totfaces, avoid many small reallocs,
* if all faces are tri's it will be correct, quads == 2x allocs */
/* take care. we are _not_ calloc'ing so be sure to initialize each field */
- mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * (size_t)looptri_num, __func__);
- mface = MEM_mallocN(sizeof(*mface) * (size_t)looptri_num, __func__);
- lindices = MEM_mallocN(sizeof(*lindices) * (size_t)looptri_num, __func__);
+ mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
+ mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
+ lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
mface_index = 0;
mp = mpoly;
@@ -2861,7 +2908,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
const bool hasLNor = CustomData_has_layer(ldata, CD_NORMAL);
/* over-alloc, ngons will be skipped */
- mface = MEM_mallocN(sizeof(*mface) * (size_t)totpoly, __func__);
+ mface = MEM_malloc_arrayN((size_t)totpoly, sizeof(*mface), __func__);
mpoly = CustomData_get_layer(pdata, CD_MPOLY);
mloop = CustomData_get_layer(ldata, CD_MLOOP);
@@ -3028,7 +3075,6 @@ static void bm_corners_to_loops_ex(
else {
const int side = (int)sqrtf((float)(fd->totdisp / corners));
const int side_sq = side * side;
- const size_t disps_size = sizeof(float[3]) * (size_t)side_sq;
for (i = 0; i < tot; i++, disps += side_sq, ld++) {
ld->totdisp = side_sq;
@@ -3037,12 +3083,12 @@ static void bm_corners_to_loops_ex(
if (ld->disps)
MEM_freeN(ld->disps);
- ld->disps = MEM_mallocN(disps_size, "converted loop mdisps");
+ ld->disps = MEM_malloc_arrayN((size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
if (fd->disps) {
- memcpy(ld->disps, disps, disps_size);
+ memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
}
else {
- memset(ld->disps, 0, disps_size);
+ memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
}
}
}
@@ -3104,7 +3150,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
CustomData_free(pdata, totpoly_i);
totpoly = totface_i;
- mpoly = MEM_callocN(sizeof(MPoly) * (size_t)totpoly, "mpoly converted");
+ mpoly = MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
@@ -3116,7 +3162,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
totloop += mf->v4 ? 4 : 3;
}
- mloop = MEM_callocN(sizeof(MLoop) * (size_t)totloop, "mloop converted");
+ mloop = MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
@@ -3515,7 +3561,7 @@ void BKE_mesh_calc_relative_deform(
const MPoly *mp;
int i;
- int *vert_accum = MEM_callocN(sizeof(*vert_accum) * (size_t)totvert, __func__);
+ int *vert_accum = MEM_calloc_arrayN((size_t)totvert, sizeof(*vert_accum), __func__);
memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert);
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 8eb1a7733c1..8bfeacd256c 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -434,6 +434,11 @@ bool modifiers_isParticleEnabled(Object *ob)
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
+/**
+ * Check whether is enabled.
+ *
+ * \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called.
+ */
bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -441,7 +446,7 @@ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode
md->scene = scene;
if ((md->mode & required_mode) != required_mode) return false;
- if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
+ if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
if (md->mode & eModifierMode_DisableTemporary) return false;
if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index db05939b1cc..08df976941b 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1524,12 +1524,12 @@ void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local
BKE_id_make_local_generic(bmain, &clip->id, true, lib_local);
}
-float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
+float BKE_movieclip_remap_scene_to_clip_frame(const MovieClip *clip, float framenr)
{
return framenr - (float) clip->start_frame + 1.0f;
}
-float BKE_movieclip_remap_clip_to_scene_frame(MovieClip *clip, float framenr)
+float BKE_movieclip_remap_clip_to_scene_frame(const MovieClip *clip, float framenr)
{
return framenr + (float) clip->start_frame - 1.0f;
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 7ef4b588dcd..55f11604710 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -44,6 +44,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
@@ -439,7 +440,7 @@ int multiresModifier_reshapeFromDeformMod(const struct EvaluationContext *eval_c
/* Create DerivedMesh for deformation modifier */
dm = get_multires_dm(eval_ctx, scene, mmd, ob);
numVerts = dm->getNumVerts(dm);
- deformedVerts = MEM_mallocN(sizeof(float[3]) * numVerts, "multiresReshape_deformVerts");
+ deformedVerts = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "multiresReshape_deformVerts");
dm->getVertCos(dm, deformedVerts);
mti->deformVerts(md, eval_ctx, ob, dm, deformedVerts, numVerts, 0);
@@ -532,7 +533,7 @@ static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl)
/* reallocate displacements to be filled in */
for (i = 0; i < totloop; ++i) {
int totdisp = multires_grid_tot[lvl];
- float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+ float (*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
if (mdisps[i].disps)
MEM_freeN(mdisps[i].disps);
@@ -596,7 +597,7 @@ static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level)
{
if (level < gpm->level) {
int gridsize = BKE_ccg_gridsize(level);
- float *data = MEM_callocN(sizeof(float) * SQUARE(gridsize),
+ float *data = MEM_calloc_arrayN(SQUARE(gridsize), sizeof(float),
"multires_grid_paint_mask_downsample");
int x, y;
@@ -641,7 +642,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
int totdisp = multires_grid_tot[lvl];
- disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+ disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
ndisps = disps;
hdisps = mdisp->disps;
@@ -784,7 +785,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
cddm = CDDM_from_mesh(me);
pmap = cddm->getPolyMap(ob, cddm);
- origco = MEM_callocN(sizeof(float) * 3 * me->totvert, "multires apply base origco");
+ origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco");
for (i = 0; i < me->totvert; ++i)
copy_v3_v3(origco[i], me->mvert[i].co);
@@ -824,8 +825,8 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
* BKE_mesh_calc_poly_normal_coords() */
fake_poly.totloop = p->totloop;
fake_poly.loopstart = 0;
- fake_loops = MEM_mallocN(sizeof(MLoop) * p->totloop, "fake_loops");
- fake_co = MEM_mallocN(sizeof(float) * 3 * p->totloop, "fake_co");
+ fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops");
+ fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co");
for (k = 0; k < p->totloop; ++k) {
int vndx = me->mloop[p->loopstart + k].v;
@@ -922,11 +923,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
lowGridData = lowdm->getGridData(lowdm);
lowdm->getGridKey(lowdm, &lowGridKey);
- subGridData = MEM_callocN(sizeof(float *) * numGrids, "subGridData*");
+ subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*");
for (i = 0; i < numGrids; ++i) {
/* backup subsurf grids */
- subGridData[i] = MEM_callocN(highGridKey.elem_size * highGridSize * highGridSize, "subGridData");
+ subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
/* overwrite with current displaced grids */
@@ -1002,6 +1003,117 @@ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key,
copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y));
}
+
+typedef struct MultiresThreadedData {
+ DispOp op;
+ CCGElem **gridData, **subGridData;
+ CCGKey *key;
+ CCGKey *sub_key;
+ MPoly *mpoly;
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+ int *gridOffset;
+ int gridSize, dGridSize, dSkip;
+ float (*smat)[3];
+} MultiresThreadedData;
+
+static void multires_disp_run_cb(
+ void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MultiresThreadedData *tdata = userdata;
+
+ DispOp op = tdata->op;
+ CCGElem **gridData = tdata->gridData;
+ CCGElem **subGridData = tdata->subGridData;
+ CCGKey *key = tdata->key;
+ MPoly *mpoly = tdata->mpoly;
+ MDisps *mdisps = tdata->mdisps;
+ GridPaintMask *grid_paint_mask = tdata->grid_paint_mask;
+ int *gridOffset = tdata->gridOffset;
+ int gridSize = tdata->gridSize;
+ int dGridSize = tdata->dGridSize;
+ int dSkip = tdata->dSkip;
+
+ const int numVerts = mpoly[pidx].totloop;
+ int S, x, y, gIndex = gridOffset[pidx];
+
+ for (S = 0; S < numVerts; ++S, ++gIndex) {
+ GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
+ MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S];
+ CCGElem *grid = gridData[gIndex];
+ CCGElem *subgrid = subGridData[gIndex];
+ float (*dispgrid)[3] = NULL;
+
+ dispgrid = mdisp->disps;
+
+ /* if needed, reallocate multires paint mask */
+ if (gpm && gpm->level < key->level) {
+ gpm->level = key->level;
+ if (gpm->data) {
+ MEM_freeN(gpm->data);
+ }
+ gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data");
+ }
+
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ float *co = CCG_grid_elem_co(key, grid, x, y);
+ float *sco = CCG_grid_elem_co(key, subgrid, x, y);
+ float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
+ float mat[3][3], disp[3], d[3], mask;
+
+ /* construct tangent space matrix */
+ grid_tangent_matrix(mat, key, x, y, subgrid);
+
+ switch (op) {
+ case APPLY_DISPLACEMENTS:
+ /* Convert displacement to object space
+ * and add to grid points */
+ mul_v3_m3v3(disp, mat, data);
+ add_v3_v3v3(co, sco, disp);
+ break;
+ case CALC_DISPLACEMENTS:
+ /* Calculate displacement between new and old
+ * grid points and convert to tangent space */
+ sub_v3_v3v3(disp, co, sco);
+ invert_m3(mat);
+ mul_v3_m3v3(data, mat, disp);
+ break;
+ case ADD_DISPLACEMENTS:
+ /* Convert subdivided displacements to tangent
+ * space and add to the original displacements */
+ invert_m3(mat);
+ mul_v3_m3v3(d, mat, co);
+ add_v3_v3(data, d);
+ break;
+ }
+
+ if (gpm) {
+ switch (op) {
+ case APPLY_DISPLACEMENTS:
+ /* Copy mask from gpm to DM */
+ *CCG_grid_elem_mask(key, grid, x, y) =
+ paint_grid_paint_mask(gpm, key->level, x, y);
+ break;
+ case CALC_DISPLACEMENTS:
+ /* Copy mask from DM to gpm */
+ mask = *CCG_grid_elem_mask(key, grid, x, y);
+ gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1);
+ break;
+ case ADD_DISPLACEMENTS:
+ /* Add mask displacement to gpm */
+ gpm->data[y * gridSize + x] +=
+ *CCG_grid_elem_mask(key, grid, x, y);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
/* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size),
* because this code uses CCGKey's info from dm to access oldGridData's normals
* (through the call to grid_tangent_matrix())! */
@@ -1014,7 +1126,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
GridPaintMask *grid_paint_mask = NULL;
int *gridOffset;
- int i, k, /*numGrids, */ gridSize, dGridSize, dSkip;
+ int i, gridSize, dGridSize, dSkip;
int totloop, totpoly;
/* this happens in the dm made by bmesh_mdisps_space_set */
@@ -1050,98 +1162,34 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
if (key.has_mask)
grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
- k = 0; /*current loop/mdisp index within the mloop array*/
-
-#pragma omp parallel for private(i) if (totloop * gridSize * gridSize >= CCG_OMP_LIMIT)
-
- for (i = 0; i < totpoly; ++i) {
- const int numVerts = mpoly[i].totloop;
- int S, x, y, gIndex = gridOffset[i];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, ++k) {
- GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
- MDisps *mdisp = &mdisps[mpoly[i].loopstart + S];
- CCGElem *grid = gridData[gIndex];
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = NULL;
-
- /* when adding new faces in edit mode, need to allocate disps */
- if (!mdisp->disps)
-#pragma omp critical
- {
- multires_reallocate_mdisps(totloop, mdisps, totlvl);
- }
-
- dispgrid = mdisp->disps;
-
- /* if needed, reallocate multires paint mask */
- if (gpm && gpm->level < key.level) {
- gpm->level = key.level;
-#pragma omp critical
- {
- if (gpm->data)
- MEM_freeN(gpm->data);
- gpm->data = MEM_callocN(sizeof(float) * key.grid_area, "gpm.data");
- }
- }
+ /* when adding new faces in edit mode, need to allocate disps */
+ for (i = 0; i < totloop; ++i) {
+ if (mdisps[i].disps == NULL) {
+ multires_reallocate_mdisps(totloop, mdisps, totlvl);
+ break;
+ }
+ }
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *co = CCG_grid_elem_co(&key, grid, x, y);
- float *sco = CCG_grid_elem_co(&key, subgrid, x, y);
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float mat[3][3], disp[3], d[3], mask;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, &key, x, y, subgrid);
+ MultiresThreadedData data = {
+ .op = op,
+ .gridData = gridData,
+ .subGridData = subGridData,
+ .key = &key,
+ .mpoly = mpoly,
+ .mdisps = mdisps,
+ .grid_paint_mask = grid_paint_mask,
+ .gridOffset = gridOffset,
+ .gridSize = gridSize,
+ .dGridSize = dGridSize,
+ .dSkip = dSkip
+ };
- switch (op) {
- case APPLY_DISPLACEMENTS:
- /* Convert displacement to object space
- * and add to grid points */
- mul_v3_m3v3(disp, mat, data);
- add_v3_v3v3(co, sco, disp);
- break;
- case CALC_DISPLACEMENTS:
- /* Calculate displacement between new and old
- * grid points and convert to tangent space */
- sub_v3_v3v3(disp, co, sco);
- invert_m3(mat);
- mul_v3_m3v3(data, mat, disp);
- break;
- case ADD_DISPLACEMENTS:
- /* Convert subdivided displacements to tangent
- * space and add to the original displacements */
- invert_m3(mat);
- mul_v3_m3v3(d, mat, co);
- add_v3_v3(data, d);
- break;
- }
+ BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings);
- if (gpm) {
- switch (op) {
- case APPLY_DISPLACEMENTS:
- /* Copy mask from gpm to DM */
- *CCG_grid_elem_mask(&key, grid, x, y) =
- paint_grid_paint_mask(gpm, key.level, x, y);
- break;
- case CALC_DISPLACEMENTS:
- /* Copy mask from DM to gpm */
- mask = *CCG_grid_elem_mask(&key, grid, x, y);
- gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1);
- break;
- case ADD_DISPLACEMENTS:
- /* Add mask displacement to gpm */
- gpm->data[y * gridSize + x] +=
- *CCG_grid_elem_mask(&key, grid, x, y);
- break;
- }
- }
- }
- }
- }
- }
-
if (op == APPLY_DISPLACEMENTS) {
ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
@@ -1199,12 +1247,12 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
BLI_assert(highGridKey.elem_size == lowGridKey.elem_size);
- subGridData = MEM_callocN(sizeof(CCGElem *) * numGrids, "subGridData*");
- diffGrid = MEM_callocN(lowGridKey.elem_size * lowGridSize * lowGridSize, "diff");
+ subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
+ diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff");
for (i = 0; i < numGrids; ++i) {
/* backup subsurf grids */
- subGridData[i] = MEM_callocN(highGridKey.elem_size * highGridSize * highGridSize, "subGridData");
+ subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
/* write difference of subsurf and displaced low level into high subsurf */
@@ -1315,10 +1363,10 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
gridData = subsurf->getGridData(subsurf);
subsurf->getGridKey(subsurf, &key);
- subGridData = MEM_callocN(sizeof(CCGElem *) * numGrids, "subGridData*");
+ subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_callocN(key.elem_size * gridSize * gridSize, "subGridData");
+ subGridData[i] = MEM_calloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
}
@@ -1332,8 +1380,7 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
k = 0; /*current loop/mdisp index within the mloop array*/
- //#pragma omp parallel for private(i) if (dm->numLoopData * gridSize * gridSize >= CCG_OMP_LIMIT)
-
+ /* TODO: Use BLI_task parallel range for that one too? */
for (i = 0; i < dm->numPolyData; ++i) {
const int numVerts = mpoly[i].totloop;
int S, x, y, gIndex = gridOffset[i];
@@ -1348,7 +1395,7 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
if (!mdisp->disps) {
mdisp->totdisp = gridSize * gridSize;
mdisp->level = totlvl;
- mdisp->disps = MEM_callocN(sizeof(float) * 3 * mdisp->totdisp, "disp in multires_set_space");
+ mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, 3 * sizeof(float), "disp in multires_set_space");
}
dispgrid = mdisp->disps;
@@ -1463,10 +1510,10 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
gridData = result->getGridData(result);
result->getGridKey(result, &key);
- subGridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "subGridData*");
+ subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_mallocN(key.elem_size * gridSize * gridSize, "subGridData");
+ subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
}
@@ -1556,7 +1603,7 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
int x, y, S;
float (*disps)[3], (*out)[3], u = 0.0f, v = 0.0f; /* Quite gcc barking. */
- disps = MEM_callocN(sizeof(float) * 3 * newtotdisp, "multires disps");
+ disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "multires disps");
out = disps;
for (S = 0; S < nvert; S++) {
@@ -1603,7 +1650,7 @@ void multires_load_old_250(Mesh *me)
int totdisp = mdisps[i].totdisp / nvert;
for (j = 0; j < nvert; j++, k++) {
- mdisps2[k].disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disp in conversion");
+ mdisps2[k].disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disp in conversion");
mdisps2[k].totdisp = totdisp;
mdisps2[k].level = mdisps[i].level;
memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp);
@@ -1663,8 +1710,8 @@ static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const Mult
int i, j;
IndexNode *node = NULL;
- (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
- (*mem) = MEM_callocN(sizeof(IndexNode) * totface * 4, "vert face map mem");
+ (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map");
+ (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem");
node = *mem;
/* Find the users */
@@ -1682,8 +1729,8 @@ static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const Mult
int i, j;
IndexNode *node = NULL;
- (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map");
- (*mem) = MEM_callocN(sizeof(IndexNode) * totedge * 2, "vert edge map mem");
+ (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map");
+ (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem");
node = *mem;
/* Find the users */
@@ -1865,7 +1912,11 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
vsrc = mr->verts;
vdst = dm->getVertArray(dm);
totvert = (unsigned int)dm->getNumVerts(dm);
- vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap");
+ vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap");
+
+ if (!vvmap) {
+ return;
+ }
lvl1 = mr->levels.first;
/* Load base verts */
@@ -1950,10 +2001,10 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
}
/* calculate vert to edge/face maps for each level (except the last) */
- fmap = MEM_callocN(sizeof(ListBase *) * (mr->level_count - 1), "multires fmap");
- emap = MEM_callocN(sizeof(ListBase *) * (mr->level_count - 1), "multires emap");
- fmem = MEM_callocN(sizeof(IndexNode *) * (mr->level_count - 1), "multires fmem");
- emem = MEM_callocN(sizeof(IndexNode *) * (mr->level_count - 1), "multires emem");
+ fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap");
+ emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap");
+ fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem");
+ emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem");
lvl = lvl1;
for (i = 0; i < (unsigned int)mr->level_count - 1; ++i) {
create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
@@ -2174,6 +2225,56 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
}
}
+static void multires_apply_smat_cb(
+ void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MultiresThreadedData *tdata = userdata;
+
+ CCGElem **gridData = tdata->gridData;
+ CCGElem **subGridData = tdata->subGridData;
+ CCGKey *dm_key = tdata->key;
+ CCGKey *subdm_key = tdata->sub_key;
+ MPoly *mpoly = tdata->mpoly;
+ MDisps *mdisps = tdata->mdisps;
+ int *gridOffset = tdata->gridOffset;
+ int gridSize = tdata->gridSize;
+ int dGridSize = tdata->dGridSize;
+ int dSkip = tdata->dSkip;
+ float (*smat)[3] = tdata->smat;
+
+ const int numVerts = mpoly[pidx].totloop;
+ MDisps *mdisp = &mdisps[mpoly[pidx].loopstart];
+ int S, x, y, gIndex = gridOffset[pidx];
+
+ for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
+ CCGElem *grid = gridData[gIndex];
+ CCGElem *subgrid = subGridData[gIndex];
+ float (*dispgrid)[3] = mdisp->disps;
+
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ float *co = CCG_grid_elem_co(dm_key, grid, x, y);
+ float *sco = CCG_grid_elem_co(subdm_key, subgrid, x, y);
+ float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
+ float mat[3][3], disp[3];
+
+ /* construct tangent space matrix */
+ grid_tangent_matrix(mat, dm_key, x, y, grid);
+
+ /* scale subgrid coord and calculate displacement */
+ mul_m3_v3(smat, sco);
+ sub_v3_v3v3(disp, sco, co);
+
+ /* convert difference to tangent space */
+ invert_m3(mat);
+ mul_v3_m3v3(data, mat, disp);
+ }
+ }
+ }
+}
+
static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, float smat[3][3])
{
DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL;
@@ -2205,7 +2306,7 @@ static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene
cddm = mesh_get_derived_deform(eval_ctx, scene, ob, CD_MASK_BAREMESH);
totvert = cddm->getNumVerts(cddm);
- vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "multiresScale vertCos");
+ vertCos = MEM_malloc_arrayN(totvert, sizeof(*vertCos), "multiresScale vertCos");
cddm->getVertCos(cddm, vertCos);
for (i = 0; i < totvert; i++)
mul_m3_v3(smat, vertCos[i]);
@@ -2226,38 +2327,25 @@ static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene
dGridSize = multires_side_tot[high_mmd.totlvl];
dSkip = (dGridSize - 1) / (gridSize - 1);
-#pragma omp parallel for private(i) if (me->totloop * gridSize * gridSize >= CCG_OMP_LIMIT)
- for (i = 0; i < me->totpoly; ++i) {
- const int numVerts = mpoly[i].totloop;
- MDisps *mdisp = &mdisps[mpoly[i].loopstart];
- int S, x, y, gIndex = gridOffset[i];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
- CCGElem *grid = gridData[gIndex];
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = mdisp->disps;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *co = CCG_grid_elem_co(&dm_key, grid, x, y);
- float *sco = CCG_grid_elem_co(&subdm_key, subgrid, x, y);
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float mat[3][3], disp[3];
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, &dm_key, x, y, grid);
-
- /* scale subgrid coord and calculate displacement */
- mul_m3_v3(smat, sco);
- sub_v3_v3v3(disp, sco, co);
-
- /* convert difference to tangent space */
- invert_m3(mat);
- mul_v3_m3v3(data, mat, disp);
- }
- }
- }
- }
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+
+ MultiresThreadedData data = {
+ .gridData = gridData,
+ .subGridData = subGridData,
+ .key = &dm_key,
+ .sub_key = &subdm_key,
+ .mpoly = mpoly,
+ .mdisps = mdisps,
+ .gridOffset = gridOffset,
+ .gridSize = gridSize,
+ .dGridSize = dGridSize,
+ .dSkip = dSkip,
+ .smat = smat
+ };
+
+ BLI_task_parallel_range(0, me->totpoly, &data, multires_apply_smat_cb, &settings);
dm->release(dm);
subdm->release(subdm);
@@ -2326,7 +2414,7 @@ void multires_topology_changed(Mesh *me)
if (!mdisp->totdisp || !mdisp->disps) {
if (grid) {
mdisp->totdisp = grid;
- mdisp->disps = MEM_callocN(3 * mdisp->totdisp * sizeof(float), "mdisp topology");
+ mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology");
}
continue;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index b76fd49fc9c..cac2aab26dd 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -506,6 +506,26 @@ static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_ou
return sock;
}
+void nodeModifySocketType(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock,
+ int type, int subtype)
+{
+ const char *idname = nodeStaticSocketType(type, subtype);
+
+ if (!idname) {
+ printf("Error: static node socket type %d undefined\n", type);
+ return;
+ }
+
+ if (sock->default_value) {
+ MEM_freeN(sock->default_value);
+ sock->default_value = NULL;
+ }
+
+ sock->type = type;
+ BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname));
+}
+
bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname,
const char *identifier, const char *name)
{
@@ -3173,13 +3193,17 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id)
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
{
+ label[0] = '\0';
+
if (node->label[0] != '\0') {
BLI_strncpy(label, node->label, maxlen);
}
else if (node->typeinfo->labelfunc) {
node->typeinfo->labelfunc(ntree, node, label, maxlen);
}
- else {
+
+ /* The previous methods (labelfunc) could not provide an adequate label for the node. */
+ if (label[0] == '\0') {
/* Kind of hacky and weak... Ideally would be better to use RNA here. :| */
const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name);
if (tmp == node->typeinfo->ui_name) {
@@ -3565,6 +3589,7 @@ static void registerShaderNodes(void)
register_node_type_sh_attribute();
register_node_type_sh_bevel();
+ register_node_type_sh_displacement();
register_node_type_sh_geometry();
register_node_type_sh_light_path();
register_node_type_sh_light_falloff();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index bea9e3bdcac..8c85a0413b8 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -356,7 +356,7 @@ void BKE_object_free_derived_caches(Object *ob)
if (ob->mesh_evaluated != NULL) {
/* Restore initial pointer. */
- ob->data = ob->mesh_evaluated->id.newid;
+ ob->data = ob->mesh_evaluated->id.orig_id;
/* Evaluated mesh points to edit mesh, but does not own it. */
ob->mesh_evaluated->edit_btmesh = NULL;
BKE_mesh_free(ob->mesh_evaluated);
@@ -458,11 +458,8 @@ void BKE_object_free(Object *ob)
GPU_lamp_free(ob);
for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
- if (oed->storage) {
- if (oed->free) {
- oed->free(oed->storage);
- }
- MEM_freeN(oed->storage);
+ if (oed->free != NULL) {
+ oed->free(oed);
}
}
BLI_freelistN(&ob->drawdata);
@@ -552,11 +549,32 @@ bool BKE_object_is_in_wpaint_select_vert(Object *ob)
/**
* Return if the object is visible, as evaluated by depsgraph
- * Keep in sync with rna_object.c (object.is_visible).
*/
-bool BKE_object_is_visible(Object *ob)
+bool BKE_object_is_visible(Object *ob, const eObjectVisibilityCheck mode)
{
- return (ob->base_flag & BASE_VISIBLED) != 0;
+ if ((ob->base_flag & BASE_VISIBLED) == 0) {
+ return false;
+ }
+
+ if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) {
+ return true;
+ }
+
+ if (((ob->transflag & OB_DUPLI) == 0) &&
+ (ob->particlesystem.first == NULL))
+ {
+ return true;
+ }
+
+ switch (mode) {
+ case OB_VISIBILITY_CHECK_FOR_VIEWPORT:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0);
+ case OB_VISIBILITY_CHECK_FOR_RENDER:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0);
+ default:
+ BLI_assert(!"Object visible test mode not supported.");
+ return false;
+ }
}
bool BKE_object_exists_check(Object *obtest)
@@ -684,6 +702,7 @@ void BKE_object_init(Object *ob)
ob->col_group = 0x01;
ob->col_mask = 0xffff;
ob->preview = NULL;
+ ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;
@@ -2699,8 +2718,11 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- const bool recalc_object = (ob->id.tag & LIB_TAG_ID_RECALC) != 0;
- const bool recalc_data = (ob->id.tag & LIB_TAG_ID_RECALC_DATA) != 0;
+ const ID *object_data = ob->data;
+ const bool recalc_object = (ob->id.recalc & ID_RECALC) != 0;
+ const bool recalc_data =
+ (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0)
+ : 0;
if (!recalc_object && ! recalc_data) {
object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update);
return;
@@ -2739,7 +2761,7 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx,
BKE_object_handle_data_update(eval_ctx, scene, ob);
}
- ob->id.tag &= ~LIB_TAG_ID_RECALC_ALL;
+ ob->id.recalc &= ID_RECALC_ALL;
object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update);
}
@@ -3722,7 +3744,7 @@ bool BKE_object_modifier_update_subframe(
/* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
/* TODO(sergey): What about animation? */
- ob->id.tag |= LIB_TAG_ID_RECALC_ALL;
+ ob->id.recalc |= ID_RECALC_ALL;
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
if (update_mesh) {
/* ignore cache clear during subframe updates
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index a16acd9d564..13589866e48 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -364,10 +364,6 @@ static void make_duplis_frames(const DupliContext *ctx)
/* duplicate over the required range */
if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0;
- /* special flag to avoid setting recalc flags to notify the depsgraph of
- * updates, as this is not a permanent change to the object */
- ob->id.tag |= LIB_TAG_ANIM_NO_RECALC;
-
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
int ok = 1;
@@ -617,7 +613,7 @@ static void make_duplis_font(const DupliContext *ctx)
/* in par the family name is stored, use this to find the other objects */
- BKE_vfont_to_curve_ex(G.main, par, FO_DUPLI, NULL,
+ BKE_vfont_to_curve_ex(G.main, par, par->data, FO_DUPLI, NULL,
&text, &text_len, &text_free, &chartransdata);
if (text == NULL || chartransdata == NULL) {
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 71d8c1981af..bc183ba95a6 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -361,7 +361,7 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx,
* This way we can restore original object data when we are freeing
* evaluated mesh.
*/
- new_mesh->id.newid = &mesh->id;
+ new_mesh->id.orig_id = &mesh->id;
}
#if 0
if (ob->derivedFinal != NULL) {
@@ -438,10 +438,14 @@ void BKE_object_eval_flush_base_flags(const EvaluationContext *UNUSED(eval_ctx),
Object *object, Base *base, bool is_from_set)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object);
+
/* Make sure we have the base collection settings is already populated.
- * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet
- * Which usually means a missing call to DEG_id_tag_update(). */
+ * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet.
+ *
+ * Which usually means a missing call to DEG_id_tag_update(id, DEG_TAG_BASE_FLAGS_UPDATE).
+ * Either of the entire scene, or of the newly added objects.*/
BLI_assert(!BLI_listbase_is_empty(&base->collection_properties->data.group));
+
/* Copy flags and settings from base. */
object->base_flag = base->flag;
if (is_from_set) {
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 537c8926a5b..0b4bc39627e 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -502,7 +502,10 @@ typedef struct OceanSimulateData {
float chop_amount;
} OceanSimulateData;
-static void ocean_compute_htilda(void *userdata, const int i)
+static void ocean_compute_htilda(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
OceanSimulateData *osd = userdata;
const Ocean *o = osd->o;
@@ -748,7 +751,10 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
* This is not optimal in all cases, but remains reasonably simple and should be OK most of the time. */
/* compute a new htilda */
- BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, o->_M > 16);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (o->_M > 16);
+ BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings);
if (o->_do_disp_y) {
BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index c88642a8164..152a882de97 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -532,8 +532,10 @@ void BKE_paint_init(Scene *sce, ePaintMode mode, const char col[3])
short ob_mode = BKE_paint_object_mode_from_paint_mode(mode);
brush = BKE_brush_first_search(G.main, ob_mode);
- if (!brush)
+ if (!brush) {
brush = BKE_brush_add(G.main, "Brush", ob_mode);
+ id_us_min(&brush->id); /* fake user only */
+ }
BKE_paint_brush_set(paint, brush);
}
@@ -641,8 +643,9 @@ void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, f
ups->brush_rotation_sec = 0.0f;
}
-void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2])
+bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2])
{
+ bool ok = false;
if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
const float r = RAKE_THRESHHOLD;
float rotation;
@@ -658,16 +661,20 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
ups->last_rake_angle = rotation;
paint_update_brush_rake_rotation(ups, brush, rotation);
+ ok = true;
}
/* make sure we reset here to the last rotation to avoid accumulating
* values in case a random rotation is also added */
else {
paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
+ ok = false;
}
}
else {
ups->brush_rotation = ups->brush_rotation_sec = 0.0f;
+ ok = true;
}
+ return ok;
}
void BKE_sculptsession_free_deformMats(SculptSession *ss)
@@ -881,6 +888,7 @@ void BKE_sculpt_update_mesh_elements(
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0;
+ ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
ss->building_vp_handle = false;
@@ -935,6 +943,7 @@ void BKE_sculpt_update_mesh_elements(
ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL;
pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
+ pbvh_show_mask_set(ss->pbvh, ss->show_mask);
if (ss->modifiers_active) {
if (!ss->orig_cos) {
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 7d1c80dca41..5e2cd89a750 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -555,7 +555,8 @@ void psys_free_pdd(ParticleSystem *psys)
psys->pdd->vedata = NULL;
psys->pdd->totpoint = 0;
- psys->pdd->tot_vec_size = 0;
+ psys->pdd->totpart = 0;
+ psys->pdd->partsize = 0;
}
}
/* free everything */
@@ -672,8 +673,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa
psys->renderdata = data;
/* Hair can and has to be recalculated if everything isn't displayed. */
- if (psys->part->disp != 100 && psys->part->type == PART_HAIR)
+ if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
psys->recalc |= PSYS_RECALC_RESET;
+ }
}
void psys_render_restore(Object *ob, ParticleSystem *psys)
@@ -746,7 +748,7 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
if (disp != render_disp) {
/* Hair can and has to be recalculated if everything isn't displayed. */
- if (psys->part->type == PART_HAIR) {
+ if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
psys->recalc |= PSYS_RECALC_RESET;
}
else {
@@ -2801,7 +2803,9 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje
/* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
- if (pset->brushtype == PE_BRUSH_WEIGHT) {
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+
+ if (use_weight) {
; /* use weight painting colors now... */
}
else {
@@ -2831,10 +2835,11 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje
/* should init_particle_interpolation set this ? */
- if (pset->brushtype == PE_BRUSH_WEIGHT) {
+ if (use_weight) {
pind.hkey[0] = NULL;
/* pa != NULL since the weight brush is only available for hair */
- pind.hkey[1] = pa->hair;
+ pind.hkey[0] = pa->hair;
+ pind.hkey[1] = pa->hair + 1;
}
@@ -2891,13 +2896,27 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje
}
/* selection coloring in edit mode */
- if (pset->brushtype == PE_BRUSH_WEIGHT) {
- float t2;
-
+ if (use_weight) {
if (k == 0) {
weight_to_rgb(ca->col, pind.hkey[1]->weight);
}
else {
+ /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
+ float real_t;
+ if (result.time < 0.0f) {
+ real_t = -result.time;
+ }
+ else {
+ real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
+ }
+
+ while (pind.hkey[1]->time < real_t) {
+ pind.hkey[1]++;
+ }
+ pind.hkey[0] = pind.hkey[1] - 1;
+ /* end copy */
+
+
float w1[3], w2[3];
keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
@@ -2906,13 +2925,6 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje
interp_v3_v3v3(ca->col, w1, w2, keytime);
}
-
- /* 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)segments) * (dietime - birthtime);
-
- while (pind.hkey[1]->time < t2) pind.hkey[1]++;
- pind.hkey[0] = pind.hkey[1] - 1;
}
else {
if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
@@ -3145,7 +3157,7 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n
psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
BLI_addtail(&ob->particlesystem, psys);
- psys->part = psys_new_settings(DATA_("ParticleSettings"), NULL);
+ psys->part = BKE_particlesettings_add(NULL, DATA_("ParticleSettings"));
if (BLI_listbase_count_ex(&ob->particlesystem, 2) > 1)
BLI_snprintf(psys->name, sizeof(psys->name), DATA_("ParticleSystem %i"), BLI_listbase_count(&ob->particlesystem));
@@ -3278,7 +3290,7 @@ static void default_particle_settings(ParticleSettings *part)
part->clength = 1.0f;
part->clength_thres = 0.0f;
- part->draw = PART_DRAW_EMITTER;
+ part->draw = 0;
part->draw_line[0] = 0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;
@@ -3304,7 +3316,7 @@ static void default_particle_settings(ParticleSettings *part)
}
-ParticleSettings *psys_new_settings(const char *name, Main *main)
+ParticleSettings *BKE_particlesettings_add(Main *main, const char *name)
{
ParticleSettings *part;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index da227514512..ac10ad44bf1 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -3375,14 +3375,16 @@ typedef struct DynamicStepSolverTaskData {
} DynamicStepSolverTaskData;
static void dynamics_step_sph_ddr_task_cb_ex(
- void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int p,
+ const ParallelRangeTLS *__restrict tls)
{
DynamicStepSolverTaskData *data = userdata;
ParticleSimulationData *sim = data->sim;
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
- SPHData *sphdata = userdata_chunk;
+ SPHData *sphdata = tls->userdata_chunk;
ParticleData *pa;
@@ -3409,7 +3411,9 @@ static void dynamics_step_sph_ddr_task_cb_ex(
}
static void dynamics_step_sph_classical_basic_integrate_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int p, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int p,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
DynamicStepSolverTaskData *data = userdata;
ParticleSimulationData *sim = data->sim;
@@ -3425,13 +3429,15 @@ static void dynamics_step_sph_classical_basic_integrate_task_cb_ex(
}
static void dynamics_step_sph_classical_calc_density_task_cb_ex(
- void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int p,
+ const ParallelRangeTLS *__restrict tls)
{
DynamicStepSolverTaskData *data = userdata;
ParticleSimulationData *sim = data->sim;
ParticleSystem *psys = sim->psys;
- SPHData *sphdata = userdata_chunk;
+ SPHData *sphdata = tls->userdata_chunk;
ParticleData *pa;
@@ -3443,14 +3449,16 @@ static void dynamics_step_sph_classical_calc_density_task_cb_ex(
}
static void dynamics_step_sph_classical_integrate_task_cb_ex(
- void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int p,
+ const ParallelRangeTLS *__restrict tls)
{
DynamicStepSolverTaskData *data = userdata;
ParticleSimulationData *sim = data->sim;
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
- SPHData *sphdata = userdata_chunk;
+ SPHData *sphdata = tls->userdata_chunk;
ParticleData *pa;
@@ -3641,9 +3649,16 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
/* Apply SPH forces using double-density relaxation algorithm
* (Clavat et. al.) */
- BLI_task_parallel_range_ex(
- 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata),
- dynamics_step_sph_ddr_task_cb_ex, psys->totpart > 100, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ settings.userdata_chunk = &sphdata;
+ settings.userdata_chunk_size = sizeof(sphdata);
+ BLI_task_parallel_range(
+ 0, psys->totpart,
+ &task_data,
+ dynamics_step_sph_ddr_task_cb_ex,
+ &settings);
sph_springs_modify(psys, timestep);
}
@@ -3653,21 +3668,46 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
* and Monaghan). Note that, unlike double-density relaxation,
* this algorithm is separated into distinct loops. */
- BLI_task_parallel_range_ex(
- 0, psys->totpart, &task_data, NULL, 0,
- dynamics_step_sph_classical_basic_integrate_task_cb_ex, psys->totpart > 100, true);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ BLI_task_parallel_range(
+ 0, psys->totpart,
+ &task_data,
+ dynamics_step_sph_classical_basic_integrate_task_cb_ex,
+ &settings);
+ }
/* calculate summation density */
/* Note that we could avoid copying sphdata for each thread here (it's only read here),
* but doubt this would gain us anything except confusion... */
- BLI_task_parallel_range_ex(
- 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata),
- dynamics_step_sph_classical_calc_density_task_cb_ex, psys->totpart > 100, true);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ settings.userdata_chunk = &sphdata;
+ settings.userdata_chunk_size = sizeof(sphdata);
+ BLI_task_parallel_range(
+ 0, psys->totpart,
+ &task_data,
+ dynamics_step_sph_classical_calc_density_task_cb_ex,
+ &settings);
+ }
/* do global forces & effectors */
- BLI_task_parallel_range_ex(
- 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata),
- dynamics_step_sph_classical_integrate_task_cb_ex, psys->totpart > 100, true);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ settings.userdata_chunk = &sphdata;
+ settings.userdata_chunk_size = sizeof(sphdata);
+ BLI_task_parallel_range(
+ 0, psys->totpart,
+ &task_data,
+ dynamics_step_sph_classical_integrate_task_cb_ex,
+ &settings);
+ }
}
BLI_spin_end(&task_data.spin);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 585a18cdad5..63f2c7e5452 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -939,7 +939,10 @@ typedef struct PBVHUpdateData {
int flag;
} PBVHUpdateData;
-static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
+static void pbvh_update_normals_accum_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
@@ -992,7 +995,10 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
}
}
-static void pbvh_update_normals_store_task_cb(void *userdata, const int n)
+static void pbvh_update_normals_store_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
PBVH *bvh = data->bvh;
@@ -1051,14 +1057,21 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
.fnors = fnors, .vnors = vnors,
};
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, totnode > PBVH_THREADED_LIMIT);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, totnode > PBVH_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
+
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
MEM_freeN(vnors);
}
-static void pbvh_update_BB_redraw_task_cb(void *userdata, const int n)
+static void pbvh_update_BB_redraw_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
PBVH *bvh = data->bvh;
@@ -1085,7 +1098,18 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
.flag = flag,
};
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, totnode > PBVH_THREADED_LIMIT);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
+}
+
+static int pbvh_get_buffers_update_flags(PBVH *bvh)
+{
+ int update_flags = 0;
+ update_flags |= bvh->show_diffuse_color ? GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR : 0;
+ update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
+ return update_flags;
}
static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
@@ -1123,6 +1147,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
}
if (node->flag & PBVH_UpdateDrawBuffers) {
+ const int update_flags = pbvh_get_buffers_update_flags(bvh);
switch (bvh->type) {
case PBVH_GRIDS:
GPU_pbvh_grid_buffers_update(
@@ -1132,7 +1157,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->prim_indices,
node->totprim,
&bvh->gridkey,
- bvh->show_diffuse_color);
+ update_flags);
break;
case PBVH_FACES:
GPU_pbvh_mesh_buffers_update(
@@ -1143,7 +1168,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->face_verts,
CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
node->face_vert_indices,
- bvh->show_diffuse_color);
+ update_flags);
break;
case PBVH_BMESH:
GPU_pbvh_bmesh_buffers_update(
@@ -1152,7 +1177,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts,
- bvh->show_diffuse_color);
+ update_flags);
break;
}
@@ -2069,6 +2094,16 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node)
node->flag |= PBVH_UpdateDrawBuffers;
}
+static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node)
+{
+ if (!node->draw_buffers) {
+ return;
+ }
+ if (GPU_pbvh_buffers_mask_changed(node->draw_buffers, bvh->show_mask)) {
+ node->flag |= PBVH_UpdateDrawBuffers;
+ }
+}
+
void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
DMSetMaterial setMaterial, bool wireframe, bool fast)
{
@@ -2076,8 +2111,10 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
PBVHNode **nodes;
int totnode;
- for (int a = 0; a < bvh->totnode; a++)
+ for (int a = 0; a < bvh->totnode; a++) {
pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]);
+ pbvh_node_check_mask_changed(bvh, &bvh->nodes[a]);
+ }
BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
&nodes, &totnode);
@@ -2388,3 +2425,8 @@ void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
{
bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color;
}
+
+void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
+{
+ bvh->show_mask = show_mask;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index e05a3068682..afd539b2273 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -164,6 +164,7 @@ struct PBVH {
bool deformed;
bool show_diffuse_color;
+ bool show_mask;
/* Dynamic topology */
BMesh *bm;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index c095236733f..16e9844241d 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -540,7 +540,7 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
view_layer_next = view_layer->next;
BLI_remlink(&sce->view_layers, view_layer);
- BKE_view_layer_free(view_layer);
+ BKE_view_layer_free_ex(view_layer, do_id_user);
}
/* Master Collection */
@@ -756,7 +756,8 @@ void BKE_scene_init(Scene *sce)
pset->draw_step = 2;
pset->fade_frames = 2;
pset->selectmode = SCE_SELECT_PATH;
- for (a = 0; a < PE_TOT_BRUSH; a++) {
+
+ for (a = 0; a < ARRAY_SIZE(pset->brush); a++) {
pset->brush[a].strength = 0.5f;
pset->brush[a].size = 50;
pset->brush[a].step = 10;
@@ -1171,6 +1172,10 @@ Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection *
#ifdef DURIAN_CAMERA_SWITCH
Object *BKE_scene_camera_switch_find(Scene *scene)
{
+ if (scene->r.mode & R_NO_CAMERA_SWITCH) {
+ return NULL;
+ }
+
TimeMarker *m;
int cfra = scene->r.cfra;
int frame = -(MAXFRAME + 1);
@@ -1391,8 +1396,8 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
if (obedit) {
Mesh *mesh = obedit->data;
if ((obedit->type == OB_MESH) &&
- ((obedit->id.tag & LIB_TAG_ID_RECALC_ALL) ||
- (mesh->id.tag & LIB_TAG_ID_RECALC_ALL)))
+ ((obedit->id.recalc & ID_RECALC_ALL) ||
+ (mesh->id.recalc & ID_RECALC_ALL)))
{
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_btmesh->bm;
@@ -1435,7 +1440,7 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx,
/* Update sound system animation (TODO, move to depsgraph). */
BKE_sound_update_scene(bmain, scene);
/* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, scene, view_layer, false);
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
/* Clear recalc flags. */
DEG_ids_clear_recalc(bmain);
}
@@ -1482,7 +1487,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx,
/* Notify editors and python about recalc. */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, scene, view_layer, true);
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
/* clear recalc flags */
DEG_ids_clear_recalc(bmain);
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 50d397cc150..ef9c22f1661 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -429,6 +429,9 @@ void BKE_screen_free(bScreen *sc)
BLI_freelistN(&sc->areabase);
BKE_previewimg_free(&sc->preview);
+
+ /* Region and timer are freed by the window manager. */
+ MEM_SAFE_FREE(sc->tool_tip);
}
/* for depsgraph */
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 2319d36ab16..424f4269f3c 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3203,11 +3203,12 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
int scemode;
int cfra;
float subframe;
+
#ifdef DURIAN_CAMERA_SWITCH
- ListBase markers;
+ int mode;
#endif
} orig_data;
-
+
/* Old info:
* Hack! This function can be called from do_render_seq(), in that case
* the seq->scene can already have a Render initialized with same name,
@@ -3271,7 +3272,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
orig_data.cfra = scene->r.cfra;
orig_data.subframe = scene->r.subframe;
#ifdef DURIAN_CAMERA_SWITCH
- orig_data.markers = scene->markers;
+ orig_data.mode = scene->r.mode;
#endif
BKE_scene_frame_set(scene, frame);
@@ -3294,10 +3295,10 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
/* prevent eternal loop */
scene->r.scemode &= ~R_DOSEQ;
-
+
#ifdef DURIAN_CAMERA_SWITCH
/* stooping to new low's in hackyness :( */
- BLI_listbase_clear(&scene->markers);
+ scene->r.mode |= R_NO_CAMERA_SWITCH;
#endif
is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
@@ -3426,7 +3427,7 @@ finally:
#ifdef DURIAN_CAMERA_SWITCH
/* stooping to new low's in hackyness :( */
- scene->markers = orig_data.markers;
+ scene->r.mode &= ~(orig_data.mode & R_NO_CAMERA_SWITCH);
#endif
return ibuf;
@@ -4501,8 +4502,11 @@ Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame)
continue;
- /* only use elements you can see - not */
- if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) {
+ /* Only use strips that generate an image, not ones that combine
+ * other strips or apply some effect. */
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE,
+ SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR, SEQ_TYPE_TEXT))
+ {
if (seq->machine > best_machine) {
best_seq = seq;
best_machine = seq->machine;
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index f9d1793d7cb..618f495dbf1 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -88,13 +88,15 @@ typedef struct ShrinkwrapCalcCBData {
* for each vertex performs a nearest vertex search on the tree
*/
static void shrinkwrap_calc_nearest_vertex_cb_ex(
- void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
BVHTreeFromMesh *treeData = data->treeData;
- BVHTreeNearest *nearest = userdata_chunk;
+ BVHTreeNearest *nearest = tls->userdata_chunk;
float *co = calc->vertexCos[i];
float tmp_co[3];
@@ -167,9 +169,14 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
nearest.dist_sq = FLT_MAX;
ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
- BLI_task_parallel_range_ex(
- 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_vertex_cb_ex,
- calc->numVerts > BKE_MESH_OMP_LIMIT, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &nearest;
+ settings.userdata_chunk_size = sizeof(nearest);
+ BLI_task_parallel_range(0, calc->numVerts,
+ &data, shrinkwrap_calc_nearest_vertex_cb_ex,
+ &settings);
free_bvhtree_from_mesh(&treeData);
}
@@ -257,7 +264,9 @@ bool BKE_shrinkwrap_project_normal(
}
static void shrinkwrap_calc_normal_projection_cb_ex(
- void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
ShrinkwrapCalcCBData *data = userdata;
@@ -272,7 +281,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
float *proj_axis = data->proj_axis;
SpaceTransform *local2aux = data->local2aux;
- BVHTreeRayHit *hit = userdata_chunk;
+ BVHTreeRayHit *hit = tls->userdata_chunk;
const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
float *co = calc->vertexCos[i];
@@ -463,9 +472,15 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
.auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback,
.proj_axis = proj_axis, .local2aux = &local2aux,
};
- BLI_task_parallel_range_ex(
- 0, calc->numVerts, &data, &hit, sizeof(hit), shrinkwrap_calc_normal_projection_cb_ex,
- calc->numVerts > BKE_MESH_OMP_LIMIT, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &hit;
+ settings.userdata_chunk_size = sizeof(hit);
+ BLI_task_parallel_range(0, calc->numVerts,
+ &data,
+ shrinkwrap_calc_normal_projection_cb_ex,
+ &settings);
}
/* free data structures */
@@ -495,13 +510,15 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* NN matches for each vertex
*/
static void shrinkwrap_calc_nearest_surface_point_cb_ex(
- void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
BVHTreeFromMesh *treeData = data->treeData;
- BVHTreeNearest *nearest = userdata_chunk;
+ BVHTreeNearest *nearest = tls->userdata_chunk;
float *co = calc->vertexCos[i];
float tmp_co[3];
@@ -583,9 +600,15 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
/* Find the nearest vertex */
ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
- BLI_task_parallel_range_ex(
- 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_surface_point_cb_ex,
- calc->numVerts > BKE_MESH_OMP_LIMIT, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &nearest;
+ settings.userdata_chunk_size = sizeof(nearest);
+ BLI_task_parallel_range(0, calc->numVerts,
+ &data,
+ shrinkwrap_calc_nearest_surface_point_cb_ex,
+ &settings);
free_bvhtree_from_mesh(&treeData);
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index b5eed6c78de..9f9818127bc 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -740,7 +740,10 @@ typedef struct ObstaclesFromDMData {
int *num_obstacles;
} ObstaclesFromDMData;
-static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
+static void obstacles_from_derivedmesh_task_cb(
+ void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
ObstaclesFromDMData *data = userdata;
SmokeDomainSettings *sds = data->sds;
@@ -870,8 +873,13 @@ static void obstacles_from_derivedmesh(
.velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ,
.num_obstacles = num_obstacles
};
- BLI_task_parallel_range(
- sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(sds->res_min[2], sds->res_max[2],
+ &data,
+ obstacles_from_derivedmesh_task_cb,
+ &settings);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
@@ -1186,7 +1194,10 @@ typedef struct EmitFromParticlesData {
float hr_smooth;
} EmitFromParticlesData;
-static void emit_from_particles_task_cb(void *userdata, const int z)
+static void emit_from_particles_task_cb(
+ void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
EmitFromParticlesData *data = userdata;
SmokeFlowSettings *sfs = data->sfs;
@@ -1397,7 +1408,13 @@ static void emit_from_particles(
.solid = solid, .smooth = smooth, .hr_smooth = hr_smooth,
};
- BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2],
+ &data,
+ emit_from_particles_task_cb,
+ &settings);
}
if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
@@ -1569,7 +1586,10 @@ typedef struct EmitFromDMData {
int *min, *max, *res;
} EmitFromDMData;
-static void emit_from_derivedmesh_task_cb(void *userdata, const int z)
+static void emit_from_derivedmesh_task_cb(
+ void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
EmitFromDMData *data = userdata;
EmissionMap *em = data->em;
@@ -1722,7 +1742,13 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
.flow_center = flow_center, .min = min, .max = max, .res = res,
};
- BLI_task_parallel_range(min[2], max[2], &data, emit_from_derivedmesh_task_cb, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2],
+ &data,
+ emit_from_derivedmesh_task_cb,
+ &settings);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
@@ -2438,7 +2464,10 @@ typedef struct UpdateEffectorsData {
unsigned char *obstacle;
} UpdateEffectorsData;
-static void update_effectors_task_cb(void *userdata, const int x)
+static void update_effectors_task_cb(
+ void *__restrict userdata,
+ const int x,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
UpdateEffectorsData *data = userdata;
SmokeDomainSettings *sds = data->sds;
@@ -2512,7 +2541,13 @@ static void update_effectors(const struct EvaluationContext *eval_ctx, Scene *sc
data.velocity_z = smoke_get_velocity_z(sds->fluid);
data.obstacle = smoke_get_obstacle(sds->fluid);
- BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, sds->res[0],
+ &data,
+ update_effectors_task_cb,
+ &settings);
}
pdEndEffectors(&effectors);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index e3af77166a9..3cfa8787f4b 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1991,7 +1991,8 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
float compare;
float bstune = sb->ballstiff;
- for (c=sb->totpoint, obp= sb->bpoint; c>=ifirst+bb; c--, obp++) {
+ /* running in a slice we must not assume anything done with obp neither alter the data of obp */
+ for (c=sb->totpoint, obp= sb->bpoint; c>0; c--, obp++) {
compare = (obp->colball + bp->colball);
sub_v3_v3v3(def, bp->pos, obp->pos);
/* rather check the AABBoxes before ever calulating the real distance */
@@ -2016,13 +2017,6 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
madd_v3_v3fl(bp->force, def, f * (1.0f - sb->balldamp));
madd_v3_v3fl(bp->force, dvel, sb->balldamp);
-
- /* exploit force(a, b) == -force(b, a) part2/2 */
- sub_v3_v3v3(dvel, velcenter, obp->vec);
- mul_v3_fl(dvel, _final_mass(ob, bp));
-
- madd_v3_v3fl(obp->force, dvel, sb->balldamp);
- madd_v3_v3fl(obp->force, def, -f * (1.0f - sb->balldamp));
}
}
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 2f9a7090caf..1c3ff352126 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -58,6 +58,7 @@
#include "BLI_edgehash.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BKE_pbvh.h"
@@ -66,6 +67,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
@@ -90,9 +92,6 @@
/* assumes MLoop's are layed out 4 for each poly, in order */
#define USE_LOOP_LAYOUT_FAST
-static ThreadRWMutex loops_cache_rwlock = BLI_RWLOCK_INITIALIZER;
-static ThreadRWMutex origindex_cache_rwlock = BLI_RWLOCK_INITIALIZER;
-
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
@@ -1479,77 +1478,107 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
}
}
+typedef struct CopyFinalLoopArrayData {
+ CCGDerivedMesh *ccgdm;
+ MLoop *mloop;
+ int grid_size;
+ int *grid_offset;
+ int edge_size;
+ size_t mloop_index;
+} CopyFinalLoopArrayData;
+
+static void copyFinalLoopArray_task_cb(
+ void *__restrict userdata,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CopyFinalLoopArrayData *data = userdata;
+ CCGDerivedMesh *ccgdm = data->ccgdm;
+ CCGSubSurf *ss = ccgdm->ss;
+ const int grid_size = data->grid_size;
+ const int edge_size = data->edge_size;
+ CCGFace *f = ccgdm->faceMap[iter].face;
+ const int num_verts = ccgSubSurf_getFaceNumVerts(f);
+ const int grid_index = data->grid_offset[iter];
+ const size_t loop_index = 4 * (size_t)grid_index * (grid_size - 1) * (grid_size - 1);
+ MLoop *ml = &data->mloop[loop_index];
+ for (int S = 0; S < num_verts; S++) {
+ for (int y = 0; y < grid_size - 1; y++) {
+ for (int x = 0; x < grid_size - 1; x++) {
+
+ uint v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+ edge_size, grid_size);
+ uint v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+ edge_size, grid_size);
+ uint v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+ edge_size, grid_size);
+ uint v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+ edge_size, grid_size);
+
+ ml->v = v1;
+ ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
+ ml++;
+
+ ml->v = v2;
+ ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
+ ml++;
+
+ ml->v = v3;
+ ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
+ ml++;
+
+ ml->v = v4;
+ ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
+ ml++;
+ }
+ }
+ }
+}
+
static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
- int index;
- int totface;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int i = 0;
- MLoop *mv;
- /* DMFlagMat *faceFlags = ccgdm->faceFlags; */ /* UNUSED */
if (!ccgdm->ehash) {
- BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
+ BLI_mutex_lock(&ccgdm->loops_cache_lock);
if (!ccgdm->ehash) {
MEdge *medge;
+ EdgeHash *ehash;
- ccgdm->ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData);
+ ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData);
medge = ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm);
- for (i = 0; i < ccgdm->dm.numEdgeData; i++) {
- BLI_edgehash_insert(ccgdm->ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i));
+ for (int i = 0; i < ccgdm->dm.numEdgeData; i++) {
+ BLI_edgehash_insert(ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i));
}
+
+ atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash);
}
- BLI_rw_mutex_unlock(&loops_cache_rwlock);
+ BLI_mutex_unlock(&ccgdm->loops_cache_lock);
}
- BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_READ);
- totface = ccgSubSurf_getNumFaces(ss);
- mv = mloop;
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
- /* int flag = (faceFlags) ? faceFlags[index * 2]: ME_SMOOTH; */ /* UNUSED */
- /* int mat_nr = (faceFlags) ? faceFlags[index * 2 + 1]: 0; */ /* UNUSED */
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- unsigned int v1, v2, v3, v4;
+ CopyFinalLoopArrayData data;
+ data.ccgdm = ccgdm;
+ data.mloop = mloop;
+ data.grid_size = ccgSubSurf_getGridSize(ss);
+ data.grid_offset = dm->getGridOffset(dm);
+ data.edge_size = ccgSubSurf_getEdgeSize(ss);
- v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
- edgeSize, gridSize);
-
- v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
- edgeSize, gridSize);
- v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
- edgeSize, gridSize);
- v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
- edgeSize, gridSize);
-
- mv->v = v1;
- mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
- mv++; i++;
-
- mv->v = v2;
- mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
- mv++; i++;
+ /* NOTE: For a dense subdivision we've got enough work for each face and
+ * hence can dedicate whole thread to single face. For less dense
+ * subdivision we handle multiple faces per thread.
+ */
+ data.mloop_index = data.grid_size >= 5 ? 1 : 8;
- mv->v = v3;
- mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
- mv++; i++;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1;
- mv->v = v4;
- mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
- mv++; i++;
- }
- }
- }
- }
- BLI_rw_mutex_unlock(&loops_cache_rwlock);
+ BLI_task_parallel_range(0, ccgSubSurf_getNumFaces(ss),
+ &data,
+ copyFinalLoopArray_task_cb,
+ &settings);
}
static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly)
@@ -3796,6 +3825,10 @@ static void ccgDM_release(DerivedMesh *dm)
MEM_freeN(ccgdm->edgeMap);
MEM_freeN(ccgdm->faceMap);
}
+
+ BLI_mutex_end(&ccgdm->loops_cache_lock);
+ BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
+
MEM_freeN(ccgdm);
}
}
@@ -3810,14 +3843,14 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
int a, index, totnone, totorig;
/* Avoid re-creation if the layer exists already */
- BLI_rw_mutex_lock(&origindex_cache_rwlock, THREAD_LOCK_READ);
+ BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ);
origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
- BLI_rw_mutex_unlock(&origindex_cache_rwlock);
+ BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
if (origindex) {
return origindex;
}
- BLI_rw_mutex_lock(&origindex_cache_rwlock, THREAD_LOCK_WRITE);
+ BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
@@ -3832,7 +3865,7 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
CCGVert *v = ccgdm->vertMap[index].vert;
origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
}
- BLI_rw_mutex_unlock(&origindex_cache_rwlock);
+ BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
return origindex;
}
@@ -4158,7 +4191,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGKey key;
- int numGrids, grid_pbvh;
+ int numGrids;
CCG_key_top_level(&key, ccgdm->ss);
@@ -4170,35 +4203,85 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
if (!ob->sculpt)
return NULL;
- /* In vwpaint, we always use a grid_pbvh for multires/subsurf */
- grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm));
+ bool grid_pbvh = ccgDM_use_grid_pbvh(ccgdm);
+ if ((ob->mode & OB_MODE_SCULPT) == 0) {
+ /* In vwpaint, we may use a grid_pbvh for multires/subsurf, under certain conditions.
+ * More complex cases break 'history' trail back to original vertices, in that case we fall back to
+ * deformed cage only (i.e. original deformed mesh). */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+
+ grid_pbvh = true;
+ bool has_one_ccg_modifier = false;
+ for (; md; md = md->next) {
+ /* We can only accept to use this ccgdm if:
+ * - it's the only active ccgdm in the stack.
+ * - there is no topology-modifying modifier in the stack.
+ * Otherwise, there is no way to map back to original geometry from grid-generated PBVH.
+ */
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(NULL, md, eModifierMode_Realtime)) {
+ continue;
+ }
+ if (ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical)) {
+ continue;
+ }
+
+ if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
+ if (has_one_ccg_modifier) {
+ /* We only allow a single active ccg modifier in the stack. */
+ grid_pbvh = false;
+ break;
+ }
+ has_one_ccg_modifier = true;
+ continue;
+ }
+
+ /* Any other non-deforming modifier makes it impossible to use grid pbvh. */
+ grid_pbvh = false;
+ break;
+ }
+ }
if (ob->sculpt->pbvh) {
+ /* Note that we have to clean up exisitng pbvh instead of updating it in case it does not match current
+ * grid_pbvh status. */
if (grid_pbvh) {
- /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm
- * but this can be freed on ccgdm release, this updates the pointers
- * when the ccgdm gets remade, the assumption is that the topology
- * does not change. */
- ccgdm_create_grids(dm);
- BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces,
- ccgdm->gridFlagMats, ccgdm->gridHidden);
+ if (BKE_pbvh_get_ccgdm(ob->sculpt->pbvh) != NULL) {
+ /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm
+ * but this can be freed on ccgdm release, this updates the pointers
+ * when the ccgdm gets remade, the assumption is that the topology
+ * does not change. */
+ ccgdm_create_grids(dm);
+ BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces,
+ ccgdm->gridFlagMats, ccgdm->gridHidden);
+ }
+ else {
+ BKE_pbvh_free(ob->sculpt->pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
+ }
+ else if (BKE_pbvh_get_ccgdm(ob->sculpt->pbvh) != NULL) {
+ BKE_pbvh_free(ob->sculpt->pbvh);
+ ob->sculpt->pbvh = NULL;
}
ccgdm->pbvh = ob->sculpt->pbvh;
}
if (ccgdm->pbvh) {
- /* For vertex paint, keep track of ccgdm */
- if (!(ob->mode & OB_MODE_SCULPT)) {
+ /* For grid pbvh, keep track of ccgdm */
+ if (grid_pbvh) {
BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm);
}
return ccgdm->pbvh;
}
- /* no pbvh exists yet, we need to create one. only in case of multires
+ /* No pbvh exists yet, we need to create one. only in case of multires
* we build a pbvh over the modified mesh, in other cases the base mesh
* is being sculpted, so we build a pbvh from that. */
- /* Note: vwpaint always builds a pbvh over the modified mesh. */
+ /* Note: vwpaint tries to always build a pbvh over the modified mesh. */
if (grid_pbvh) {
ccgdm_create_grids(dm);
@@ -4224,13 +4307,27 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
BKE_pbvh_build_mesh(ccgdm->pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata,
looptri, looptris_num);
+
+ if (ob->sculpt->modifiers_active && ob->derivedDeform != NULL) {
+ DerivedMesh *deformdm = ob->derivedDeform;
+ float (*vertCos)[3];
+ int totvert;
+
+ totvert = deformdm->getNumVerts(deformdm);
+ vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
+ deformdm->getVertCos(deformdm, vertCos);
+ BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos);
+ MEM_freeN(vertCos);
+ }
}
- if (ccgdm->pbvh)
+ if (ccgdm->pbvh != NULL) {
pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(ccgdm->pbvh, ob->sculpt->show_mask);
+ }
- /* For vertex paint, keep track of ccgdm */
- if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) {
+ /* For grid pbvh, keep track of ccgdm. */
+ if (grid_pbvh && ccgdm->pbvh) {
BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm);
}
return ccgdm->pbvh;
@@ -4784,6 +4881,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4;
ccgdm->dm.numTessFaceData = 0;
+ BLI_mutex_init(&ccgdm->loops_cache_lock);
+ BLI_rw_mutex_init(&ccgdm->origindex_cache_rwlock);
+
return ccgdm;
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 122b605f160..fcedd880615 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -58,6 +58,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_colorband.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
@@ -185,7 +186,7 @@ void BKE_texture_colormapping_default(ColorMapping *colormap)
{
memset(colormap, 0, sizeof(ColorMapping));
- init_colorband(&colormap->coba, true);
+ BKE_colorband_init(&colormap->coba, true);
colormap->bright = 1.0;
colormap->contrast = 1.0;
@@ -198,365 +199,6 @@ void BKE_texture_colormapping_default(ColorMapping *colormap)
colormap->blend_factor = 0.0f;
}
-/* ****************** COLORBAND ******************* */
-
-void init_colorband(ColorBand *coba, bool rangetype)
-{
- int a;
-
- coba->data[0].pos = 0.0;
- coba->data[1].pos = 1.0;
-
- if (rangetype == 0) {
- coba->data[0].r = 0.0;
- coba->data[0].g = 0.0;
- coba->data[0].b = 0.0;
- coba->data[0].a = 0.0;
-
- coba->data[1].r = 1.0;
- coba->data[1].g = 1.0;
- coba->data[1].b = 1.0;
- coba->data[1].a = 1.0;
- }
- else {
- coba->data[0].r = 0.0;
- coba->data[0].g = 0.0;
- coba->data[0].b = 0.0;
- coba->data[0].a = 1.0;
-
- coba->data[1].r = 1.0;
- coba->data[1].g = 1.0;
- coba->data[1].b = 1.0;
- coba->data[1].a = 1.0;
- }
-
- for (a = 2; a < MAXCOLORBAND; a++) {
- coba->data[a].r = 0.5;
- coba->data[a].g = 0.5;
- coba->data[a].b = 0.5;
- coba->data[a].a = 1.0;
- coba->data[a].pos = 0.5;
- }
-
- coba->tot = 2;
- coba->color_mode = COLBAND_BLEND_RGB;
-}
-
-ColorBand *add_colorband(bool rangetype)
-{
- ColorBand *coba;
-
- coba = MEM_callocN(sizeof(ColorBand), "colorband");
- init_colorband(coba, rangetype);
-
- return coba;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static float colorband_hue_interp(
- const int ipotype_hue,
- const float mfac, const float fac,
- float h1, float h2)
-{
- float h_interp;
- int mode = 0;
-
-#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b)))
-#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f)
-
- h1 = HUE_MOD(h1);
- h2 = HUE_MOD(h2);
-
- BLI_assert(h1 >= 0.0f && h1 < 1.0f);
- BLI_assert(h2 >= 0.0f && h2 < 1.0f);
-
- switch (ipotype_hue) {
- case COLBAND_HUE_NEAR:
- {
- if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1;
- else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2;
- else mode = 0;
- break;
- }
- case COLBAND_HUE_FAR:
- {
- if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1;
- else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2;
- else mode = 0;
- break;
- }
- case COLBAND_HUE_CCW:
- {
- if (h1 > h2) mode = 2;
- else mode = 0;
- break;
- }
- case COLBAND_HUE_CW:
- {
- if (h1 < h2) mode = 1;
- else mode = 0;
- break;
- }
- }
-
- switch (mode) {
- case 0:
- h_interp = HUE_INTERP(h1, h2);
- break;
- case 1:
- h_interp = HUE_INTERP(h1 + 1.0f, h2);
- h_interp = HUE_MOD(h_interp);
- break;
- case 2:
- h_interp = HUE_INTERP(h1, h2 + 1.0f);
- h_interp = HUE_MOD(h_interp);
- break;
- }
-
- BLI_assert(h_interp >= 0.0f && h_interp < 1.0f);
-
-#undef HUE_INTERP
-#undef HUE_MOD
-
- return h_interp;
-}
-
-bool do_colorband(const ColorBand *coba, float in, float out[4])
-{
- const CBData *cbd1, *cbd2, *cbd0, *cbd3;
- float fac;
- int ipotype;
- int a;
-
- if (coba == NULL || coba->tot == 0) return false;
-
- cbd1 = coba->data;
-
- ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR;
-
- if (coba->tot == 1) {
- out[0] = cbd1->r;
- out[1] = cbd1->g;
- out[2] = cbd1->b;
- out[3] = cbd1->a;
- }
- else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) {
- out[0] = cbd1->r;
- out[1] = cbd1->g;
- out[2] = cbd1->b;
- out[3] = cbd1->a;
- }
- else {
- CBData left, right;
-
- /* we're looking for first pos > in */
- for (a = 0; a < coba->tot; a++, cbd1++) {
- if (cbd1->pos > in) {
- break;
- }
- }
-
- if (a == coba->tot) {
- cbd2 = cbd1 - 1;
- right = *cbd2;
- right.pos = 1.0f;
- cbd1 = &right;
- }
- else if (a == 0) {
- left = *cbd1;
- left.pos = 0.0f;
- cbd2 = &left;
- }
- else {
- cbd2 = cbd1 - 1;
- }
-
- if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) {
- out[0] = cbd1->r;
- out[1] = cbd1->g;
- out[2] = cbd1->b;
- out[3] = cbd1->a;
- }
- else {
-
- if (cbd2->pos != cbd1->pos) {
- fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos);
- }
- else {
- /* was setting to 0.0 in 2.56 & previous, but this
- * is incorrect for the last element, see [#26732] */
- fac = (a != coba->tot) ? 0.0f : 1.0f;
- }
-
- if (ipotype == COLBAND_INTERP_CONSTANT) {
- /* constant */
- out[0] = cbd2->r;
- out[1] = cbd2->g;
- out[2] = cbd2->b;
- out[3] = cbd2->a;
- }
- else if (ipotype >= COLBAND_INTERP_B_SPLINE) {
- /* ipo from right to left: 3 2 1 0 */
- float t[4];
-
- if (a >= coba->tot - 1) cbd0 = cbd1;
- else cbd0 = cbd1 + 1;
- if (a < 2) cbd3 = cbd2;
- else cbd3 = cbd2 - 1;
-
- CLAMP(fac, 0.0f, 1.0f);
-
- if (ipotype == COLBAND_INTERP_CARDINAL) {
- key_curve_position_weights(fac, t, KEY_CARDINAL);
- }
- else {
- key_curve_position_weights(fac, t, KEY_BSPLINE);
- }
-
- out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r;
- out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g;
- out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b;
- out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a;
- CLAMP(out[0], 0.0f, 1.0f);
- CLAMP(out[1], 0.0f, 1.0f);
- CLAMP(out[2], 0.0f, 1.0f);
- CLAMP(out[3], 0.0f, 1.0f);
- }
- else {
- float mfac;
-
- if (ipotype == COLBAND_INTERP_EASE) {
- mfac = fac * fac;
- fac = 3.0f * mfac - 2.0f * mfac * fac;
- }
-
- mfac = 1.0f - fac;
-
- if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) {
- float col1[3], col2[3];
-
- rgb_to_hsv_v(&cbd1->r, col1);
- rgb_to_hsv_v(&cbd2->r, col2);
-
- out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
- out[1] = mfac * col1[1] + fac * col2[1];
- out[2] = mfac * col1[2] + fac * col2[2];
- out[3] = mfac * cbd1->a + fac * cbd2->a;
-
- hsv_to_rgb_v(out, out);
- }
- else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) {
- float col1[3], col2[3];
-
- rgb_to_hsl_v(&cbd1->r, col1);
- rgb_to_hsl_v(&cbd2->r, col2);
-
- out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
- out[1] = mfac * col1[1] + fac * col2[1];
- out[2] = mfac * col1[2] + fac * col2[2];
- out[3] = mfac * cbd1->a + fac * cbd2->a;
-
- hsl_to_rgb_v(out, out);
- }
- else {
- /* COLBAND_BLEND_RGB */
- out[0] = mfac * cbd1->r + fac * cbd2->r;
- out[1] = mfac * cbd1->g + fac * cbd2->g;
- out[2] = mfac * cbd1->b + fac * cbd2->b;
- out[3] = mfac * cbd1->a + fac * cbd2->a;
- }
- }
- }
- }
- return true; /* OK */
-}
-
-void colorband_table_RGBA(ColorBand *coba, float **array, int *size)
-{
- int a;
-
- *size = CM_TABLE + 1;
- *array = MEM_callocN(sizeof(float) * (*size) * 4, "ColorBand");
-
- for (a = 0; a < *size; a++)
- do_colorband(coba, (float)a / (float)CM_TABLE, &(*array)[a * 4]);
-}
-
-static int vergcband(const void *a1, const void *a2)
-{
- const CBData *x1 = a1, *x2 = a2;
-
- if (x1->pos > x2->pos) return 1;
- else if (x1->pos < x2->pos) return -1;
- return 0;
-}
-
-void colorband_update_sort(ColorBand *coba)
-{
- int a;
-
- if (coba->tot < 2)
- return;
-
- for (a = 0; a < coba->tot; a++)
- coba->data[a].cur = a;
-
- qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
-
- for (a = 0; a < coba->tot; a++) {
- if (coba->data[a].cur == coba->cur) {
- coba->cur = a;
- break;
- }
- }
-}
-
-CBData *colorband_element_add(struct ColorBand *coba, float position)
-{
- if (coba->tot == MAXCOLORBAND) {
- return NULL;
- }
- else {
- CBData *xnew;
-
- xnew = &coba->data[coba->tot];
- xnew->pos = position;
-
- if (coba->tot != 0) {
- do_colorband(coba, position, &xnew->r);
- }
- else {
- zero_v4(&xnew->r);
- }
- }
-
- coba->tot++;
- coba->cur = coba->tot - 1;
-
- colorband_update_sort(coba);
-
- return coba->data + coba->cur;
-}
-
-int colorband_element_remove(struct ColorBand *coba, int index)
-{
- int a;
-
- if (coba->tot < 2)
- return 0;
-
- if (index < 0 || index >= coba->tot)
- return 0;
-
- coba->tot--;
- for (a = index; a < coba->tot; a++) {
- coba->data[a] = coba->data[a + 1];
- }
- if (coba->cur) coba->cur--;
- return 1;
-}
-
/* ******************* TEX ************************ */
/** Free (or release) any data used by this texture (does not free the texure itself). */
@@ -1357,7 +999,7 @@ void BKE_texture_pointdensity_init_data(PointDensity *pd)
pd->noise_depth = 1;
pd->noise_fac = 1.0f;
pd->noise_influence = TEX_PD_NOISE_STATIC;
- pd->coba = add_colorband(true);
+ pd->coba = BKE_colorband_add(true);
pd->speed_scale = 1.0f;
pd->totpoints = 0;
pd->object = NULL;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 07e071df04a..ebd4c04e8ce 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -2905,3 +2905,155 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking)
dopesheet->ok = true;
}
+
+/* NOTE: Returns NULL if the track comes from camera object, */
+MovieTrackingObject *BKE_tracking_find_object_for_track(
+ const MovieTracking *tracking,
+ const MovieTrackingTrack *track)
+{
+ const ListBase *tracksbase = &tracking->tracks;
+ if (BLI_findindex(tracksbase, track) != -1) {
+ return NULL;
+ }
+ MovieTrackingObject *object = tracking->objects.first;
+ while (object != NULL) {
+ if (BLI_findindex(&object->tracks, track) != -1) {
+ return object;
+ }
+ object = object->next;
+ }
+ return NULL;
+}
+
+ListBase *BKE_tracking_find_tracks_list_for_track(
+ MovieTracking *tracking,
+ const MovieTrackingTrack *track)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking,
+ track);
+ if (object != NULL) {
+ return &object->tracks;
+ }
+ return &tracking->tracks;
+}
+
+/* NOTE: Returns NULL if the track comes from camera object, */
+MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
+ const MovieTracking *tracking,
+ const MovieTrackingPlaneTrack *plane_track)
+{
+ const ListBase *plane_tracks_base = &tracking->plane_tracks;
+ if (BLI_findindex(plane_tracks_base, plane_track) != -1) {
+ return NULL;
+ }
+ MovieTrackingObject *object = tracking->objects.first;
+ while (object != NULL) {
+ if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
+ return object;
+ }
+ object = object->next;
+ }
+ return NULL;
+}
+
+ListBase *BKE_tracking_find_tracks_list_for_plane_track(
+ MovieTracking *tracking,
+ const MovieTrackingPlaneTrack *plane_track)
+{
+ MovieTrackingObject *object =
+ BKE_tracking_find_object_for_plane_track(tracking, plane_track);
+ if (object != NULL) {
+ return &object->plane_tracks;
+ }
+ return &tracking->plane_tracks;
+}
+
+void BKE_tracking_get_rna_path_for_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object =
+ BKE_tracking_find_object_for_track(tracking, track);
+ char track_name_esc[MAX_NAME * 2];
+ BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc));
+ if (object == NULL) {
+ BLI_snprintf(rna_path, rna_path_len,
+ "tracking.tracks[\"%s\"]",
+ track_name_esc);
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path, rna_path_len,
+ "tracking.objects[\"%s\"].tracks[\"%s\"]",
+ object_name_esc,
+ track_name_esc);
+ }
+}
+
+void BKE_tracking_get_rna_path_prefix_for_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object =
+ BKE_tracking_find_object_for_track(tracking, track);
+ if (object == NULL) {
+ BLI_snprintf(rna_path, rna_path_len, "tracking.tracks");
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path, rna_path_len,
+ "tracking.objects[\"%s\"]",
+ object_name_esc);
+ }
+}
+
+void BKE_tracking_get_rna_path_for_plane_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object =
+ BKE_tracking_find_object_for_plane_track(tracking, plane_track);
+ char track_name_esc[MAX_NAME * 2];
+ BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc));
+ if (object == NULL) {
+ BLI_snprintf(rna_path, rna_path_len,
+ "tracking.plane_tracks[\"%s\"]",
+ track_name_esc);
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path, rna_path_len,
+ "tracking.objects[\"%s\"].plane_tracks[\"%s\"]",
+ object_name_esc,
+ track_name_esc);
+ }
+}
+
+void BKE_tracking_get_rna_path_prefix_for_plane_track(
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object =
+ BKE_tracking_find_object_for_plane_track(tracking, plane_track);
+ if (object == NULL) {
+ BLI_snprintf(rna_path, rna_path_len, "tracking.plane_tracks");
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path, rna_path_len,
+ "tracking.objects[\"%s\"].plane_tracks",
+ object_name_esc);
+ }
+}
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 4ff4a129768..1cb474e6202 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -236,17 +236,15 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
}
}
-static bool check_track_trackable(MovieClip *clip,
+static bool check_track_trackable(const MovieClip *clip,
MovieTrackingTrack *track,
- MovieClipUser *user)
+ const MovieClipUser *user)
{
if (TRACK_SELECTED(track) &&
(track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0)
{
- MovieTrackingMarker *marker;
- int frame;
- frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
- marker = BKE_tracking_marker_get(track, frame);
+ int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame);
return (marker->flag & MARKER_DISABLED) == 0;
}
return false;
@@ -283,6 +281,108 @@ static bool tracking_check_marker_margin(libmv_Marker *libmv_marker,
return true;
}
+/* Provide Libmv side of auto track all information about given tracks. */
+static void fill_autotrack_tracks(const int frame_width,
+ const int frame_height,
+ const ListBase *tracksbase,
+ const bool backwards,
+ struct libmv_AutoTrack *autotrack)
+{
+ /* Count number of markers to be put to a context. */
+ size_t num_trackable_markers = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ for (int i = 0; i < track->markersnr; ++i) {
+ const MovieTrackingMarker *marker = track->markers + i;
+ if ((marker->flag & MARKER_DISABLED) == 0) {
+ num_trackable_markers++;
+ }
+ }
+ }
+ /* Early output if we don't have any markers. */
+ if (num_trackable_markers == 0) {
+ return;
+ }
+ /* Allocate memory for all the markers. */
+ libmv_Marker *libmv_markers = MEM_mallocN(
+ sizeof(libmv_Marker) * num_trackable_markers,
+ "libmv markers array");
+ /* Fill in markers array. */
+ int track_index = 0, num_filled_libmv_markers = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ for (int i = 0; i < track->markersnr; ++i) {
+ MovieTrackingMarker *marker = track->markers + i;
+ if ((marker->flag & MARKER_DISABLED) != 0) {
+ continue;
+ }
+ dna_marker_to_libmv_marker(
+ track,
+ marker,
+ 0,
+ track_index,
+ frame_width, frame_height,
+ backwards,
+ &libmv_markers[num_filled_libmv_markers++]);
+ }
+ /* Put all markers to autotrack at once. */
+ track_index++;
+ }
+ /* Add all markers to autotrack. */
+ libmv_autoTrackSetMarkers(autotrack,
+ libmv_markers,
+ num_trackable_markers);
+ /* Free temporary memory. */
+ MEM_freeN(libmv_markers);
+}
+
+static void create_per_track_tracking_options(const MovieClip *clip,
+ const MovieClipUser *user,
+ const ListBase *tracksbase,
+ AutoTrackContext *context)
+{
+ /* Count number of trackable tracks. */
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (check_track_trackable(clip, track, user)) {
+ context->num_tracks++;
+ }
+ }
+ /* Allocate required memory. */
+ context->options =
+ MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
+ "auto track options");
+ /* Fill in all the settings. */
+ int i = 0, track_index = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (!check_track_trackable(clip, track, user)) {
+ ++track_index;
+ continue;
+ }
+ AutoTrackOptions *options = &context->options[i++];
+ /* TODO(sergey): Single clip only for now. */
+ options->clip_index = 0;
+ options->track_index = track_index;
+ options->track = track;
+ tracking_configure_tracker(track,
+ NULL,
+ &options->track_region_options);
+ options->use_keyframe_match =
+ track->pattern_match == TRACK_MATCH_KEYFRAME;
+ context->tracks[track_index] = track;
+ ++track_index;
+ }
+}
+
AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
MovieClipUser *user,
const bool backwards,
@@ -291,16 +391,13 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext),
"autotrack context");
MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int i, track_index, frame_width, frame_height;
-
+ int frame_width, frame_height;
+ /* get size of frame to convert normalized coordinates to a picture ones. */
BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
-
/* TODO(sergey): Currently using only a single clip. */
context->clips[0] = clip;
context->num_clips = 1;
-
context->user = *user;
context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
context->user.render_flag = 0;
@@ -311,79 +408,34 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
context->first_frame = user->framenr;
context->sync_frame = user->framenr;
context->first_sync = true;
-
BLI_spin_init(&context->spin_lock);
-
- int num_total_tracks = BLI_listbase_count(tracksbase);
+ const int num_total_tracks = BLI_listbase_count(tracksbase);
context->tracks =
- MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
- "auto track pointers");
-
+ MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
+ "auto track pointers");
+ /* Initialize image accessor. */
context->image_accessor =
tracking_image_accessor_new(context->clips, 1,
context->tracks, num_total_tracks,
user->framenr);
+ /* Initialize auto track context and provide all information about currently
+ * tracked markers.
+ */
context->autotrack =
- libmv_autoTrackNew(context->image_accessor->libmv_accessor);
-
- /* Fill in Autotrack with all markers we know. */
- track_index = 0;
- for (track = tracksbase->first;
- track;
- track = track->next)
- {
- if (check_track_trackable(clip, track, user)) {
- context->num_tracks++;
- }
-
- for (i = 0; i < track->markersnr; ++i) {
- MovieTrackingMarker *marker = track->markers + i;
- if ((marker->flag & MARKER_DISABLED) == 0) {
- libmv_Marker libmv_marker;
- dna_marker_to_libmv_marker(track,
- marker,
- 0,
- track_index,
- frame_width,
- frame_height,
- backwards,
- &libmv_marker);
- libmv_autoTrackAddMarker(context->autotrack,
- &libmv_marker);
- }
- }
- track_index++;
- }
-
+ libmv_autoTrackNew(context->image_accessor->libmv_accessor);
+ fill_autotrack_tracks(frame_width, frame_height,
+ tracksbase,
+ backwards,
+ context->autotrack);
/* Create per-track tracking options. */
- context->options =
- MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
- "auto track options");
- i = track_index = 0;
- for (track = tracksbase->first;
- track;
- track = track->next)
- {
- if (check_track_trackable(clip, track, user)) {
- AutoTrackOptions *options = &context->options[i++];
- /* TODO(sergey): Single clip only for now. */
- options->clip_index = 0;
- options->track_index = track_index;
- options->track = track;
- tracking_configure_tracker(track,
- NULL,
- &options->track_region_options);
- options->use_keyframe_match =
- track->pattern_match == TRACK_MATCH_KEYFRAME;
- }
- context->tracks[track_index] = track;
- ++track_index;
- }
-
+ create_per_track_tracking_options(clip, user, tracksbase, context);
return context;
}
-static void autotrack_context_step_cb(void *userdata, int track)
+static void autotrack_context_step_cb(
+ void *__restrict userdata,
+ const int track,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
AutoTrackContext *context = userdata;
const int frame_delta = context->backwards ? -1 : 1;
@@ -461,10 +513,13 @@ bool BKE_autotrack_context_step(AutoTrackContext *context)
const int frame_delta = context->backwards ? -1 : 1;
context->step_ok = false;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (context->num_tracks > 1);
BLI_task_parallel_range(0, context->num_tracks,
context,
autotrack_context_step_cb,
- context->num_tracks > 1);
+ &settings);
/* Advance the frame. */
BLI_spin_lock(&context->spin_lock);
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index edddeb41cc8..cbf1a02a46c 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -1503,7 +1503,10 @@ typedef struct TrackingStabilizeFrameInterpolationData {
interpolation_func interpolation;
} TrackingStabilizeFrameInterpolationData;
-static void tracking_stabilize_frame_interpolation_cb(void *userdata, int j)
+static void tracking_stabilize_frame_interpolation_cb(
+ void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
TrackingStabilizeFrameInterpolationData *data = userdata;
ImBuf *ibuf = data->ibuf;
@@ -1597,10 +1600,14 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
.ibuf = ibuf, .tmpibuf = tmpibuf, .mat = mat,
.interpolation = interpolation
};
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (tmpibuf->y > 128);
BLI_task_parallel_range(0, tmpibuf->y,
&data,
tracking_stabilize_frame_interpolation_cb,
- tmpibuf->y > 128);
+ &settings);
if (tmpibuf->rect_float)
tmpibuf->userflags |= IB_RECT_INVALID;
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 4abd2a01d40..5da8dc563e2 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -108,7 +108,7 @@ void BKE_world_init(World *wrld)
wrld->mistdist = 25.0f;
}
-World *add_world(Main *bmain, const char *name)
+World *BKE_world_add(Main *bmain, const char *name)
{
World *wrld;
@@ -158,7 +158,7 @@ World *BKE_world_copy(Main *bmain, const World *wrld)
return wrld_copy;
}
-World *localize_world(World *wrld)
+World *BKE_world_localize(World *wrld)
{
/* TODO replace with something like
* World *wrld_copy;
@@ -174,7 +174,7 @@ World *localize_world(World *wrld)
for (a = 0; a < MAX_MTEX; a++) {
if (wrld->mtex[a]) {
- wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_world");
+ wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
}
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 60a1bdb0458..f745a840cea 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -158,7 +158,7 @@ static int write_audio_frame(FFMpegContext *context)
for (channel = 0; channel < c->channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size,
- context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
+ context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
}
}
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 367f1bb9de5..7eec54e67e1 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -30,9 +30,6 @@
/** \file BLI_linklist.h
* \ingroup bli
- * \brief Routines for working with singly linked lists
- * of 'links' - pointers to other data.
- *
*/
#include "BLI_compiler_attrs.h"
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 1e931e6f0d7..2a0f4e6f814 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -128,9 +128,9 @@ if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \
(lb_iter != lb_init)); \
}
-#define LINKLIST_FOREACH(type, var, list) \
- for (type var = (type)((list)->first); \
- var != NULL; \
+#define BLI_LISTBASE_FOREACH(type, var, list) \
+ for (type var = (type)((list)->first); \
+ var != NULL; \
var = (type)(((Link*)(var))->next))
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index e6a72298ae7..377b9325717 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -129,6 +129,9 @@ MINLINE int max_iii(int a, int b, int c);
MINLINE int min_iiii(int a, int b, int c, int d);
MINLINE int max_iiii(int a, int b, int c, int d);
+MINLINE size_t min_zz(size_t a, size_t b);
+MINLINE size_t max_zz(size_t a, size_t b);
+
MINLINE int compare_ff(float a, float b, const float max_diff);
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps);
@@ -140,6 +143,7 @@ MINLINE float power_of_2(float f);
MINLINE int integer_digits_f(const float f);
MINLINE int integer_digits_d(const double d);
+MINLINE int integer_digits_i(const int i);
/* these don't really fit anywhere but were being copied about a lot */
MINLINE int is_power_of_2_i(int n);
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index 1ac98a682d1..86213dc271f 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -31,7 +31,24 @@ extern "C" {
#include "BLI_math_inline.h"
-MINLINE unsigned int highest_order_bit_i(unsigned int n);
+/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
+MINLINE int bitscan_forward_i(int a);
+MINLINE unsigned int bitscan_forward_uint(unsigned int a);
+
+/* Similar to above, but also clears the bit. */
+MINLINE int bitscan_forward_clear_i(int *a);
+MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a);
+
+/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */
+MINLINE int bitscan_reverse_i(int a);
+MINLINE unsigned int bitscan_reverse_uint(unsigned int a);
+
+/* Similar to above, but also clears the bit. */
+MINLINE int bitscan_reverse_clear_i(int *a);
+MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a);
+
+/* NOTE: Those functions returns 2 to the power of index of highest order bit. */
+MINLINE unsigned int highest_order_bit_uint(unsigned int n);
MINLINE unsigned short highest_order_bit_s(unsigned short n);
#ifdef __GNUC__
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index e059327a490..1f206e5e234 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -97,6 +97,11 @@ float angle_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_qt(const float q[4]);
float angle_qtqt(const float q1[4], const float q2[4]);
+float angle_signed_normalized_qt(const float q[4]);
+float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]);
+float angle_signed_qt(const float q[4]);
+float angle_signed_qtqt(const float q1[4], const float q2[4]);
+
/* TODO: don't what this is, but it's not the same as mat3_to_quat */
void mat3_to_quat_is_ok(float q[4], float mat[3][3]);
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index ccfa2b6e2e7..d03010af8d2 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -19,7 +19,9 @@
*/
#ifndef __BLI_TASK_H__
-#define __BLI_TASK_H__
+#define __BLI_TASK_H__
+
+#include <string.h> /* for memset() */
struct Link;
struct ListBase;
@@ -116,32 +118,77 @@ void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id);
void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id);
/* Parallel for routines */
-typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter);
-typedef void (*TaskParallelRangeFuncEx)(void *userdata, void *userdata_chunk, const int iter, const int thread_id);
-typedef void (*TaskParallelRangeFuncFinalize)(void *userdata, void *userdata_chunk);
-void BLI_task_parallel_range_ex(
- int start, int stop,
- void *userdata,
- void *userdata_chunk,
- const size_t userdata_chunk_size,
- TaskParallelRangeFuncEx func_ex,
- const bool use_threading,
- const bool use_dynamic_scheduling);
+
+typedef enum eTaskSchedulingMode {
+ /* Task scheduler will divide overall work into equal chunks, scheduling
+ * even chunks to all worker threads.
+ * Least run time benefit, ideal for cases when each task requires equal
+ * amount of compute power.
+ */
+ TASK_SCHEDULING_STATIC,
+ /* Task scheduler will schedule small amount of work to each worker thread.
+ * Has more run time overhead, but deals much better with cases when each
+ * part of the work requires totally different amount of compute power.
+ */
+ TASK_SCHEDULING_DYNAMIC,
+} eTaskSchedulingMode;
+
+/* Per-thread specific data passed to the callback. */
+typedef struct ParallelRangeTLS {
+ /* Identifier of the thread who this data belongs to. */
+ int thread_id;
+ /* Copy of user-specifier chunk, which is copied from original chunk to all
+ * worker threads. This is similar to OpenMP's firstprivate.
+ */
+ void *userdata_chunk;
+} ParallelRangeTLS;
+
+typedef void (*TaskParallelRangeFunc)(void *__restrict userdata,
+ const int iter,
+ const ParallelRangeTLS *__restrict tls);
+typedef void (*TaskParallelRangeFuncFinalize)(void *__restrict userdata,
+ void *__restrict userdata_chunk);
+
+typedef struct ParallelRangeSettings {
+ /* Whether caller allows to do threading of the particular range.
+ * Usually set by some equation, which forces threading off when threading
+ * overhead becomes higher than speed benefit.
+ * BLI_task_parallel_range() by itself will always use threading when range
+ * is higher than a chunk size. As in, threading will always be performed.
+ */
+ bool use_threading;
+ /* Scheduling mode to use for this parallel range invocation. */
+ eTaskSchedulingMode scheduling_mode;
+ /* Each instance of looping chunks will get a copy of this data
+ * (similar to OpenMP's firstprivate).
+ */
+ void *userdata_chunk; /* Pointer to actual data. */
+ size_t userdata_chunk_size; /* Size of that data. */
+ /* Function called from calling thread once whole range have been
+ * processed.
+ */
+ TaskParallelRangeFuncFinalize func_finalize;
+ /* Minimum allowed number of range iterators to be handled by a single
+ * thread. This allows to achieve following:
+ * - Reduce amount of threading overhead.
+ * - Partially occupy thread pool with ranges which are computationally
+ * expensive, but which are smaller than amount of available threads.
+ * For example, it's possible to multi-thread [0 .. 64] range into 4
+ * thread which will be doing 16 iterators each.
+ * This is a preferred way to tell scheduler when to start threading than
+ * having a global use_threading switch based on just range size.
+ */
+ int min_iter_per_thread;
+} ParallelRangeSettings;
+
+BLI_INLINE void BLI_parallel_range_settings_defaults(
+ ParallelRangeSettings *settings);
+
void BLI_task_parallel_range(
- int start, int stop,
+ const int start, const int stop,
void *userdata,
TaskParallelRangeFunc func,
- const bool use_threading);
-
-void BLI_task_parallel_range_finalize(
- int start, int stop,
- void *userdata,
- void *userdata_chunk,
- const size_t userdata_chunk_size,
- TaskParallelRangeFuncEx func_ex,
- TaskParallelRangeFuncFinalize func_finalize,
- const bool use_threading,
- const bool use_dynamic_scheduling);
+ const ParallelRangeSettings *settings);
typedef void (*TaskParallelListbaseFunc)(void *userdata,
struct Link *iter,
@@ -161,6 +208,20 @@ void BLI_task_parallel_mempool(
TaskParallelMempoolFunc func,
const bool use_threading);
+/* TODO(sergey): Think of a better place for this. */
+BLI_INLINE void BLI_parallel_range_settings_defaults(
+ ParallelRangeSettings *settings)
+{
+ memset(settings, 0, sizeof(*settings));
+ settings->use_threading = true;
+ settings->scheduling_mode = TASK_SCHEDULING_STATIC;
+ /* NOTE: Current value mimics old behavior, but it's not ideal by any
+ * means. Would be cool to find a common value which will work good enough
+ * for both static and dynamic scheduling.
+ */
+ settings->min_iter_per_thread = 1;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 28e98c17a9d..bf2f25fae69 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -50,18 +50,27 @@
#include "BLI_ghash.h"
#include "BLI_strict_flags.h"
+/* -------------------------------------------------------------------- */
+/** \name Structs & Constants
+ * \{ */
+
#define GHASH_USE_MODULO_BUCKETS
-/* Also used by smallhash! */
+/**
+ * Next prime after `2^n` (skipping 2 & 3).
+ *
+ * \note Also used by: `BLI_edgehash` & `BLI_smallhash`.
+ */
const uint hashsizes[] = {
- 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
- 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
- 4194319, 8388617, 16777259, 33554467, 67108879, 134217757,
+ 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467, 67108879, 134217757,
268435459
};
#ifdef GHASH_USE_MODULO_BUCKETS
# define GHASH_MAX_SIZE 27
+BLI_STATIC_ASSERT(ARRAY_SIZE(hashsizes) == GHASH_MAX_SIZE, "Invalid 'hashsizes' size");
#else
# define GHASH_BUCKET_BIT_MIN 2
# define GHASH_BUCKET_BIT_MAX 28 /* About 268M of buckets... */
@@ -77,8 +86,6 @@ const uint hashsizes[] = {
#define GHASH_LIMIT_GROW(_nbkt) (((_nbkt) * 3) / 4)
#define GHASH_LIMIT_SHRINK(_nbkt) (((_nbkt) * 3) / 16)
-/***/
-
/* WARNING! Keep in sync with ugly _gh_Entry in header!!! */
typedef struct Entry {
struct Entry *next;
@@ -115,10 +122,9 @@ struct GHash {
uint flag;
};
+/** \} */
/* -------------------------------------------------------------------- */
-/* GHash API */
-
/** \name Internal Utility API
* \{ */
@@ -429,8 +435,9 @@ BLI_INLINE Entry *ghash_lookup_entry(GHash *gh, const void *key)
return ghash_lookup_entry_ex(gh, key, bucket_index);
}
-static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const uint nentries_reserve, const uint flag)
+static GHash *ghash_new(
+ GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
+ const uint nentries_reserve, const uint flag)
{
GHash *gh = MEM_mallocN(sizeof(*gh), info);
@@ -685,8 +692,8 @@ static GHash *ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP val
/** \} */
-
-/** \name Public API
+/* -------------------------------------------------------------------- */
+/** \name GHash Public API
* \{ */
/**
@@ -699,8 +706,9 @@ static GHash *ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP val
* Use this to avoid resizing buckets if the size is known or can be closely approximated.
* \return An empty GHash.
*/
-GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const uint nentries_reserve)
+GHash *BLI_ghash_new_ex(
+ GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
+ const uint nentries_reserve)
{
return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
}
@@ -974,8 +982,9 @@ bool BLI_ghash_pop(
* \param valfreefp Optional callback to free the value.
* \param nentries_reserve Optionally reserve the number of members that the hash will hold.
*/
-void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
- const uint nentries_reserve)
+void BLI_ghash_clear_ex(
+ GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
+ const uint nentries_reserve)
{
if (keyfreefp || valfreefp)
ghash_free_cb(gh, keyfreefp, valfreefp);
@@ -1028,11 +1037,8 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag)
/** \} */
-
/* -------------------------------------------------------------------- */
-/* GHash Iterator API */
-
-/** \name Iterator API
+/** \name GHash Iterator API
* \{ */
/**
@@ -1154,7 +1160,7 @@ bool BLI_ghashIterator_done(GHashIterator *ghi)
/** \} */
-
+/* -------------------------------------------------------------------- */
/** \name Generic Key Hash & Comparison Functions
* \{ */
@@ -1325,7 +1331,7 @@ void BLI_ghashutil_pairfree(void *ptr)
/** \} */
-
+/* -------------------------------------------------------------------- */
/** \name Convenience GHash Creation Functions
* \{ */
@@ -1367,16 +1373,14 @@ GHash *BLI_ghash_pair_new(const char *info)
/** \} */
-
/* -------------------------------------------------------------------- */
-/* GSet API */
-
-/* Use ghash API to give 'set' functionality */
-
-/** \name GSet Functions
+/** \name GSet Public API
+ *
+ * Use ghash API to give 'set' functionality
* \{ */
-GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
- const uint nentries_reserve)
+GSet *BLI_gset_new_ex(
+ GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
+ const uint nentries_reserve)
{
return (GSet *)ghash_new(hashfp, cmpfp, info, nentries_reserve, GHASH_FLAG_IS_GSET);
}
@@ -1504,11 +1508,13 @@ bool BLI_gset_pop(
}
}
-void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp,
- const uint nentries_reserve)
+void BLI_gset_clear_ex(
+ GSet *gs, GSetKeyFreeFP keyfreefp,
+ const uint nentries_reserve)
{
- BLI_ghash_clear_ex((GHash *)gs, keyfreefp, NULL,
- nentries_reserve);
+ BLI_ghash_clear_ex(
+ (GHash *)gs, keyfreefp, NULL,
+ nentries_reserve);
}
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
@@ -1533,6 +1539,7 @@ void BLI_gset_flag_clear(GSet *gs, uint flag)
/** \} */
+/* -------------------------------------------------------------------- */
/** \name GSet Combined Key/Value Usage
*
* \note Not typical ``set`` use, only use when the pointer identity matters.
@@ -1569,6 +1576,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key)
/** \} */
+/* -------------------------------------------------------------------- */
/** \name Convenience GSet Creation Functions
* \{ */
@@ -1601,7 +1609,7 @@ GSet *BLI_gset_pair_new(const char *info)
/** \} */
-
+/* -------------------------------------------------------------------- */
/** \name Debugging & Introspection
* \{ */
@@ -1713,8 +1721,9 @@ double BLI_gset_calc_quality_ex(
GSet *gs, double *r_load, double *r_variance,
double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
{
- return BLI_ghash_calc_quality_ex((GHash *)gs, r_load, r_variance,
- r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket);
+ return BLI_ghash_calc_quality_ex(
+ (GHash *)gs, r_load, r_variance,
+ r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket);
}
double BLI_ghash_calc_quality(GHash *gh)
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index bd16bc1a9c6..9c055a227a9 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -798,7 +798,10 @@ typedef struct BVHDivNodesData {
int first_of_next_level;
} BVHDivNodesData;
-static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
+static void non_recursive_bvh_div_nodes_task_cb(
+ void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
BVHDivNodesData *data = userdata;
@@ -872,7 +875,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
* to use multithread building.
*
* To archive this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper
- * implicit_needed_branches and implicit_leafs_index are auxiliary functions to solve that "optimal-split".
+ * #implicit_needed_branches and #implicit_leafs_index are auxiliary functions to solve that "optimal-split".
*/
static void non_recursive_bvh_div_nodes(
const BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs)
@@ -885,24 +888,23 @@ static void non_recursive_bvh_div_nodes(
BVHBuildHelper data;
int depth;
-
- /* set parent from root node to NULL */
- BVHNode *tmp = &branches_array[0];
- tmp->parent = NULL;
-
- /* Most of bvhtree code relies on 1-leaf trees having at least one branch
- * We handle that special case here */
- if (num_leafs == 1) {
- BVHNode *root = &branches_array[0];
- refit_kdop_hull(tree, root, 0, num_leafs);
- root->main_axis = get_largest_axis(root->bv) / 2;
- root->totnode = 1;
- root->children[0] = leafs_array[0];
- root->children[0]->parent = root;
- return;
- }
- branches_array--; /* Implicit trees use 1-based indexs */
+ {
+ /* set parent from root node to NULL */
+ BVHNode *root = &branches_array[1];
+ root->parent = NULL;
+
+ /* Most of bvhtree code relies on 1-leaf trees having at least one branch
+ * We handle that special case here */
+ if (num_leafs == 1) {
+ refit_kdop_hull(tree, root, 0, num_leafs);
+ root->main_axis = get_largest_axis(root->bv) / 2;
+ root->totnode = 1;
+ root->children[0] = leafs_array[0];
+ root->children[0]->parent = root;
+ return;
+ }
+ }
build_implicit_tree_helper(tree, &data);
@@ -923,14 +925,20 @@ static void non_recursive_bvh_div_nodes(
cb_data.depth = depth;
if (true) {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
BLI_task_parallel_range(
- i, i_stop, &cb_data, non_recursive_bvh_div_nodes_task_cb,
- num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ i, i_stop,
+ &cb_data,
+ non_recursive_bvh_div_nodes_task_cb,
+ &settings);
}
else {
/* Less hassle for debugging. */
+ ParallelRangeTLS tls = {0};
for (int i_task = i; i_task < i_stop; i_task++) {
- non_recursive_bvh_div_nodes_task_cb(&cb_data, i_task);
+ non_recursive_bvh_div_nodes_task_cb(&cb_data, i_task, &tls);
}
}
}
@@ -1044,9 +1052,6 @@ void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_balance(BVHTree *tree)
{
- int i;
-
- BVHNode *branches_array = tree->nodearray + tree->totleaf;
BVHNode **leafs_array = tree->nodes;
/* This function should only be called once
@@ -1054,13 +1059,14 @@ void BLI_bvhtree_balance(BVHTree *tree)
BLI_assert(tree->totbranch == 0);
/* Build the implicit tree */
- non_recursive_bvh_div_nodes(tree, branches_array, leafs_array, tree->totleaf);
+ non_recursive_bvh_div_nodes(tree, tree->nodearray + (tree->totleaf - 1), leafs_array, tree->totleaf);
/* current code expects the branches to be linked to the nodes array
* we perform that linkage here */
tree->totbranch = implicit_needed_branches(tree->tree_type, tree->totleaf);
- for (i = 0; i < tree->totbranch; i++)
- tree->nodes[tree->totleaf + i] = branches_array + i;
+ for (int i = 0; i < tree->totbranch; i++) {
+ tree->nodes[tree->totleaf + i] = &tree->nodearray[tree->totleaf + i];
+ }
#ifdef USE_SKIP_LINKS
build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL);
@@ -1276,7 +1282,10 @@ int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode);
}
-static void bvhtree_overlap_task_cb(void *userdata, const int j)
+static void bvhtree_overlap_task_cb(
+ void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
BVHOverlapData_Shared *data_shared = data->shared;
@@ -1341,9 +1350,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
data[j].thread = j;
}
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
BLI_task_parallel_range(
- 0, thread_num, data, bvhtree_overlap_task_cb,
- tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ 0, thread_num,
+ data,
+ bvhtree_overlap_task_cb,
+ &settings);
for (j = 0; j < thread_num; j++)
total += BLI_stack_count(data[j].overlap);
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 1500e23d72e..051792f7f7c 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -28,6 +28,10 @@
/** \file blender/blenlib/intern/BLI_linklist.c
* \ingroup bli
+ *
+ * Routines for working with single linked lists of 'links' - pointers to other data.
+ *
+ * For double linked lists see 'BLI_listbase.h'.
*/
#include <stdlib.h>
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
index e77e8cf40d0..fefd4b4587c 100644
--- a/source/blender/blenlib/intern/bitmap_draw_2d.c
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -162,7 +162,7 @@ static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *
}
/**
- * Draws a filled polyon with support for self intersections.
+ * Draws a filled polygon with support for self intersections.
*
* \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
* note that \a x_end will always be greater than \a x, so we can use:
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index d2cf0cf49a2..96c3972d802 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -29,7 +29,9 @@
/** \file blender/blenlib/intern/listbase.c
* \ingroup bli
*
- * Manipulations on ListBase structs
+ * Manipulations on double-linked list (#ListBase structs).
+ *
+ * For single linked lists see 'BLI_linklist.h'
*/
#include <string.h>
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 749c18fc0ce..2f5b0f420b1 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -315,6 +315,15 @@ MINLINE int max_iiii(int a, int b, int c, int d)
return max_ii(max_iii(a, b, c), d);
}
+MINLINE size_t min_zz(size_t a, size_t b)
+{
+ return (a < b) ? a : b;
+}
+MINLINE size_t max_zz(size_t a, size_t b)
+{
+ return (b < a) ? a : b;
+}
+
/**
* Almost-equal for IEEE floats, using absolute difference method.
*
@@ -388,6 +397,10 @@ MINLINE int integer_digits_d(const double d)
return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1;
}
+MINLINE int integer_digits_i(const int i)
+{
+ return (int)log10((double)i) + 1;
+}
/* Internal helpers for SSE2 implementation.
*
diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c
index 82d7e2114c2..37fdcd7878a 100644
--- a/source/blender/blenlib/intern/math_bits_inline.c
+++ b/source/blender/blenlib/intern/math_bits_inline.c
@@ -25,16 +25,77 @@
#ifndef __MATH_BITS_INLINE_C__
#define __MATH_BITS_INLINE_C__
+#ifdef _MSC_VER
+# include <intrin.h>
+#endif
+
#include "BLI_math_bits.h"
-MINLINE unsigned int highest_order_bit_i(unsigned int n)
+MINLINE int bitscan_forward_i(int a)
{
- n |= (n >> 1);
- n |= (n >> 2);
- n |= (n >> 4);
- n |= (n >> 8);
- n |= (n >> 16);
- return n - (n >> 1);
+ BLI_assert(a != 0);
+# ifdef _MSC_VER
+ unsigned long ctz;
+ _BitScanForward(&ctz, a);
+ return ctz;
+#else
+ return __builtin_ctz((unsigned int)a);
+#endif
+}
+
+MINLINE unsigned int bitscan_forward_uint(unsigned int a)
+{
+ return (unsigned int)bitscan_forward_i((int)a);
+}
+
+MINLINE int bitscan_forward_clear_i(int *a)
+{
+ int i = bitscan_forward_i(*a);
+ *a &= (*a) - 1;
+ return i;
+}
+
+MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a)
+{
+ return (unsigned int)bitscan_forward_clear_i((int *)a);
+}
+
+MINLINE int bitscan_reverse_i(int a)
+{
+ BLI_assert(a != 0);
+# ifdef _MSC_VER
+ unsigned long clz;
+ _BitScanReverse(&clz, a);
+ return clz;
+#else
+ return __builtin_clz((unsigned int)a);
+#endif
+}
+
+MINLINE unsigned int bitscan_reverse_uint(unsigned int a)
+{
+ return (unsigned int)bitscan_reverse_i((int)a);
+}
+
+MINLINE int bitscan_reverse_clear_i(int *a)
+{
+ int i = bitscan_reverse_i(*a);
+ /* TODO(sergey): This could probably be optimized. */
+ *a &= ~(1 << (sizeof(int) * 8 - i - 1));
+ return i;
+}
+
+MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a)
+{
+ return (unsigned int)bitscan_reverse_clear_i((int *)a);
+}
+
+MINLINE unsigned int highest_order_bit_uint(unsigned int n)
+{
+ if (n == 0) {
+ return 0;
+ }
+ return 1 << (sizeof(unsigned int) * 8 - bitscan_reverse_uint(n));
}
MINLINE unsigned short highest_order_bit_s(unsigned short n)
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 23bd5e60e22..29e7cf32ddc 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -511,6 +511,14 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
}
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Angle
+ *
+ * Unlike the angle between vectors, this does NOT return the shortest angle.
+ * See signed functions below for this.
+ *
+ * \{ */
+
float angle_normalized_qt(const float q[4])
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -548,6 +556,64 @@ float angle_qtqt(const float q1[4], const float q2[4])
return angle_normalized_qtqt(quat1, quat2);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternion Angle (Signed)
+ *
+ * Angles with quaternion calculation can exceed 180d,
+ * Having signed versions of these functions allows 'fabsf(angle_signed_qtqt(...))'
+ * to give us the shortest angle between quaternions.
+ * With higher precision than subtracting pi afterwards.
+ *
+ * \{ */
+
+float angle_signed_normalized_qt(const float q[4])
+{
+ BLI_ASSERT_UNIT_QUAT(q);
+ if (q[0] >= 0.0f) {
+ return 2.0f * saacos(q[0]);
+ }
+ else {
+ return -2.0f * saacos(-q[0]);
+ }
+}
+
+float angle_signed_normalized_qtqt(const float q1[4], const float q2[4])
+{
+ if (dot_qtqt(q1, q2) >= 0.0f) {
+ return angle_normalized_qtqt(q1, q2);
+ }
+ else {
+ float q2_copy[4];
+ negate_v4_v4(q2_copy, q2);
+ return -angle_normalized_qtqt(q1, q2_copy);
+ }
+}
+
+float angle_signed_qt(const float q[4])
+{
+ float tquat[4];
+
+ normalize_qt_qt(tquat, q);
+
+ return angle_signed_normalized_qt(tquat);
+}
+
+float angle_signed_qtqt(const float q1[4], const float q2[4])
+{
+ if (dot_qtqt(q1, q2) >= 0.0f) {
+ return angle_qtqt(q1, q2);
+ }
+ else {
+ float q2_copy[4];
+ negate_v4_v4(q2_copy, q2);
+ return -angle_qtqt(q1, q2_copy);
+ }
+}
+
+/** \} */
+
void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag)
{
const float eps = 1e-4f;
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index fd7418a8f7b..3a19f1d3603 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -46,7 +46,10 @@ typedef struct CovarianceData {
int nbr_cos_vn;
} CovarianceData;
-static void covariance_m_vn_ex_task_cb(void *userdata, const int a)
+static void covariance_m_vn_ex_task_cb(
+ void *__restrict userdata,
+ const int a,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
CovarianceData *data = userdata;
const float *cos_vn = data->cos_vn;
@@ -117,8 +120,14 @@ void BLI_covariance_m_vn_ex(
.covfac = covfac, .n = n, .nbr_cos_vn = nbr_cos_vn,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((nbr_cos_vn * n * n) >= 10000);
BLI_task_parallel_range(
- 0, n * n, &data, covariance_m_vn_ex_task_cb, (nbr_cos_vn * n * n) >= 10000);
+ 0, n * n,
+ &data,
+ covariance_m_vn_ex_task_cb,
+ &settings);
}
/**
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 3adc6b30f6e..764b12431d0 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -128,7 +128,7 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
/**
* \returns shortest distance from \a rect to x/y (0 if inside)
-*/
+ */
int BLI_rcti_length_x(const rcti *rect, const int x)
{
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index eb7f186702b..05cfe4f3972 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -693,7 +693,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
/* Ensure malloc will go fine from threads,
*
* This is needed because we could be in main thread here
- * and malloc could be non-threda safe at this point because
+ * and malloc could be non-thread safe at this point because
* no other jobs are running.
*/
BLI_begin_threaded_malloc();
@@ -994,7 +994,6 @@ typedef struct ParallelRangeState {
void *userdata;
TaskParallelRangeFunc func;
- TaskParallelRangeFuncEx func_ex;
int iter;
int chunk_size;
@@ -1015,51 +1014,67 @@ BLI_INLINE bool parallel_range_next_iter_get(
static void parallel_range_func(
TaskPool * __restrict pool,
void *userdata_chunk,
- int threadid)
+ int thread_id)
{
ParallelRangeState * __restrict state = BLI_task_pool_userdata(pool);
+ ParallelRangeTLS tls = {
+ .thread_id = thread_id,
+ .userdata_chunk = userdata_chunk,
+ };
int iter, count;
-
while (parallel_range_next_iter_get(state, &iter, &count)) {
- int i;
-
- if (state->func_ex) {
- for (i = 0; i < count; ++i) {
- state->func_ex(state->userdata, userdata_chunk, iter + i, threadid);
- }
- }
- else {
- for (i = 0; i < count; ++i) {
- state->func(state->userdata, iter + i);
- }
+ for (int i = 0; i < count; ++i) {
+ state->func(state->userdata, iter + i, &tls);
}
}
}
+static void palallel_range_single_thread(const int start, int const stop,
+ void *userdata,
+ TaskParallelRangeFunc func,
+ const ParallelRangeSettings *settings)
+{
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+ if (use_userdata_chunk) {
+ userdata_chunk_local = MALLOCA(userdata_chunk_size);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+ ParallelRangeTLS tls = {
+ .thread_id = 0,
+ .userdata_chunk = userdata_chunk_local,
+ };
+ for (int i = start; i < stop; ++i) {
+ func(userdata, i, &tls);
+ }
+ if (settings->func_finalize != NULL) {
+ settings->func_finalize(userdata, userdata_chunk_local);
+ }
+ MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
+}
+
/**
* This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement.
*
- * See public API doc for description of parameters.
+ * See public API doc of ParallelRangeSettings for description of all settings.
*/
-static void task_parallel_range_ex(
- int start, int stop,
- void *userdata,
- void *userdata_chunk,
- const size_t userdata_chunk_size,
- TaskParallelRangeFunc func,
- TaskParallelRangeFuncEx func_ex,
- TaskParallelRangeFuncFinalize func_finalize,
- const bool use_threading,
- const bool use_dynamic_scheduling)
+void BLI_task_parallel_range(const int start, const int stop,
+ void *userdata,
+ TaskParallelRangeFunc func,
+ const ParallelRangeSettings *settings)
{
TaskScheduler *task_scheduler;
TaskPool *task_pool;
ParallelRangeState state;
int i, num_threads, num_tasks;
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
void *userdata_chunk_local = NULL;
void *userdata_chunk_array = NULL;
- const bool use_userdata_chunk = (func_ex != NULL) && (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
if (start == stop) {
return;
@@ -1067,63 +1082,61 @@ static void task_parallel_range_ex(
BLI_assert(start < stop);
if (userdata_chunk_size != 0) {
- BLI_assert(func_ex != NULL && func == NULL);
BLI_assert(userdata_chunk != NULL);
}
/* If it's not enough data to be crunched, don't bother with tasks at all,
* do everything from the main thread.
*/
- if (!use_threading) {
- if (func_ex) {
- if (use_userdata_chunk) {
- userdata_chunk_local = MALLOCA(userdata_chunk_size);
- memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
- }
-
- for (i = start; i < stop; ++i) {
- func_ex(userdata, userdata_chunk_local, i, 0);
- }
-
- if (func_finalize) {
- func_finalize(userdata, userdata_chunk_local);
- }
-
- MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
- }
- else {
- for (i = start; i < stop; ++i) {
- func(userdata, i);
- }
- }
-
+ if (!settings->use_threading) {
+ palallel_range_single_thread(start, stop,
+ userdata,
+ func,
+ settings);
return;
}
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &state);
num_threads = BLI_task_scheduler_num_threads(task_scheduler);
/* The idea here is to prevent creating task for each of the loop iterations
* and instead have tasks which are evenly distributed across CPU cores and
* pull next iter to be crunched using the queue.
*/
- num_tasks = num_threads * 2;
+ num_tasks = num_threads + 2;
state.start = start;
state.stop = stop;
state.userdata = userdata;
state.func = func;
- state.func_ex = func_ex;
state.iter = start;
- if (use_dynamic_scheduling) {
- state.chunk_size = 32;
+ switch (settings->scheduling_mode) {
+ case TASK_SCHEDULING_STATIC:
+ state.chunk_size = max_ii(
+ settings->min_iter_per_thread,
+ (stop - start) / (num_tasks));
+ break;
+ case TASK_SCHEDULING_DYNAMIC:
+ /* TODO(sergey): Make it configurable from min_iter_per_thread. */
+ state.chunk_size = 32;
+ break;
}
- else {
- state.chunk_size = max_ii(1, (stop - start) / (num_tasks));
+
+ num_tasks = min_ii(num_tasks,
+ max_ii(1, (stop - start) / state.chunk_size));
+
+ if (num_tasks == 1) {
+ palallel_range_single_thread(start, stop,
+ userdata,
+ func,
+ settings);
+ return;
}
- num_tasks = min_ii(num_tasks, (stop - start) / state.chunk_size);
+ task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
+
+ /* NOTE: This way we are adding a memory barrier and ensure all worker
+ * threads can read and modify the value, without any locks. */
atomic_fetch_and_add_int32(&state.iter, 0);
if (use_userdata_chunk) {
@@ -1147,98 +1160,16 @@ static void task_parallel_range_ex(
BLI_task_pool_free(task_pool);
if (use_userdata_chunk) {
- if (func_finalize) {
+ if (settings->func_finalize != NULL) {
for (i = 0; i < num_tasks; i++) {
userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
- func_finalize(userdata, userdata_chunk_local);
+ settings->func_finalize(userdata, userdata_chunk_local);
}
}
MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
}
}
-/**
- * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement.
- *
- * \param start First index to process.
- * \param stop Index to stop looping (excluded).
- * \param userdata Common userdata passed to all instances of \a func.
- * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data
- * (similar to OpenMP's firstprivate).
- * \param userdata_chunk_size Memory size of \a userdata_chunk.
- * \param func_ex Callback function (advanced version).
- * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
- * (allows caller to use any kind of test to switch on parallelization or not).
- * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently),
- * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently).
- */
-void BLI_task_parallel_range_ex(
- int start, int stop,
- void *userdata,
- void *userdata_chunk,
- const size_t userdata_chunk_size,
- TaskParallelRangeFuncEx func_ex,
- const bool use_threading,
- const bool use_dynamic_scheduling)
-{
- task_parallel_range_ex(
- start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, NULL,
- use_threading, use_dynamic_scheduling);
-}
-
-/**
- * A simpler version of \a BLI_task_parallel_range_ex, which does not use \a use_dynamic_scheduling,
- * and does not handle 'firstprivate'-like \a userdata_chunk.
- *
- * \param start First index to process.
- * \param stop Index to stop looping (excluded).
- * \param userdata Common userdata passed to all instances of \a func.
- * \param func Callback function (simple version).
- * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
- * (allows caller to use any kind of test to switch on parallelization or not).
- */
-void BLI_task_parallel_range(
- int start, int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- const bool use_threading)
-{
- task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, NULL, use_threading, false);
-}
-
-/**
- * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement,
- * with an additional 'finalize' func called from calling thread once whole range have been processed.
- *
- * \param start First index to process.
- * \param stop Index to stop looping (excluded).
- * \param userdata Common userdata passed to all instances of \a func.
- * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data
- * (similar to OpenMP's firstprivate).
- * \param userdata_chunk_size Memory size of \a userdata_chunk.
- * \param func_ex Callback function (advanced version).
- * \param func_finalize Callback function, called after all workers have finished,
- * useful to finalize accumulative tasks.
- * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
- * (allows caller to use any kind of test to switch on parallelization or not).
- * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently),
- * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently).
- */
-void BLI_task_parallel_range_finalize(
- int start, int stop,
- void *userdata,
- void *userdata_chunk,
- const size_t userdata_chunk_size,
- TaskParallelRangeFuncEx func_ex,
- TaskParallelRangeFuncFinalize func_finalize,
- const bool use_threading,
- const bool use_dynamic_scheduling)
-{
- task_parallel_range_ex(
- start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, func_finalize,
- use_threading, use_dynamic_scheduling);
-}
-
#undef MALLOCA
#undef MALLOCA_FREE
@@ -1325,14 +1256,14 @@ void BLI_task_parallel_listbase(
}
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &state);
+ task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
num_threads = BLI_task_scheduler_num_threads(task_scheduler);
/* The idea here is to prevent creating task for each of the loop iterations
* and instead have tasks which are evenly distributed across CPU cores and
* pull next iter to be crunched using the queue.
*/
- num_tasks = num_threads * 2;
+ num_tasks = num_threads + 2;
state.index = 0;
state.link = listbase->first;
@@ -1413,14 +1344,14 @@ void BLI_task_parallel_mempool(
}
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &state);
+ task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
num_threads = BLI_task_scheduler_num_threads(task_scheduler);
/* The idea here is to prevent creating task for each of the loop iterations
* and instead have tasks which are evenly distributed across CPU cores and
* pull next item to be crunched using the threaded-aware BLI_mempool_iter.
*/
- num_tasks = num_threads * 2;
+ num_tasks = num_threads + 2;
state.userdata = userdata;
state.func = func;
diff --git a/source/blender/blenloader/BLO_blend_defs.h b/source/blender/blenloader/BLO_blend_defs.h
index a6b06a080cc..6776b1c3338 100644
--- a/source/blender/blenloader/BLO_blend_defs.h
+++ b/source/blender/blenloader/BLO_blend_defs.h
@@ -75,6 +75,6 @@ enum {
ENDB = BLEND_MAKE_ID('E', 'N', 'D', 'B'),
};
-#define BLEN_THUMB_MEMSIZE_FILE(_x, _y) (sizeof(int) * (size_t)(2 + (_x) * (_y)))
+#define BLEN_THUMB_MEMSIZE_FILE(_x, _y) (sizeof(int) * (2 + (size_t)(_x) * (size_t)(_y)))
#endif /* __BLO_BLEND_DEFS_H__ */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 94f5f790f1c..54444ff5151 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -41,6 +41,7 @@
#include <math.h> // for fabs
#include <stdarg.h> /* for va_start/end */
#include <time.h> /* for gmtime */
+#include <ctype.h> /* for isdigit */
#include "BLI_utildefines.h"
#ifndef WIN32
@@ -232,6 +233,15 @@
/* Use GHash for restoring pointers by name */
#define USE_GHASH_RESTORE_POINTER
+/* Define this to have verbose debug prints. */
+#define USE_DEBUG_PRINT
+
+#ifdef USE_DEBUG_PRINT
+# define DEBUG_PRINTF(...) printf(__VA_ARGS__)
+#else
+# define DEBUG_PRINTF(...)
+#endif
+
/***/
typedef struct OldNew {
@@ -294,7 +304,7 @@ static OldNewMap *oldnewmap_new(void)
OldNewMap *onm= MEM_callocN(sizeof(*onm), "OldNewMap");
onm->entriessize = 1024;
- onm->entries = MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");
+ onm->entries = MEM_malloc_arrayN(onm->entriessize, sizeof(*onm->entries), "OldNewMap.entries");
return onm;
}
@@ -541,7 +551,7 @@ void blo_split_main(ListBase *mainlist, Main *main)
/* (Library.temp_index -> Main), lookup table */
const unsigned int lib_main_array_len = BLI_listbase_count(&main->library);
- Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__);
+ Main **lib_main_array = MEM_malloc_arrayN(lib_main_array_len, sizeof(*lib_main_array), __func__);
int i = 0;
for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
@@ -897,39 +907,42 @@ static void decode_blender_header(FileData *fd)
{
char header[SIZEOFBLENDERHEADER], num[4];
int readsize;
-
+
/* read in the header data */
readsize = fd->read(fd, header, sizeof(header));
-
- if (readsize == sizeof(header)) {
- if (STREQLEN(header, "BLENDER", 7)) {
- fd->flags |= FD_FLAGS_FILE_OK;
-
- /* what size are pointers in the file ? */
- if (header[7]=='_') {
- fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4;
- if (sizeof(void *) != 4) {
- fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
- }
- }
- else {
- if (sizeof(void *) != 8) {
- fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
- }
+
+ if (readsize == sizeof(header) &&
+ STREQLEN(header, "BLENDER", 7) &&
+ ELEM(header[7], '_', '-') &&
+ ELEM(header[8], 'v', 'V') &&
+ (isdigit(header[9]) && isdigit(header[10]) && isdigit(header[11])))
+ {
+ fd->flags |= FD_FLAGS_FILE_OK;
+
+ /* what size are pointers in the file ? */
+ if (header[7] == '_') {
+ fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4;
+ if (sizeof(void *) != 4) {
+ fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
}
-
- /* is the file saved in a different endian
- * than we need ?
- */
- if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) {
- fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
+ }
+ else {
+ if (sizeof(void *) != 8) {
+ fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
}
-
- /* get the version number */
- memcpy(num, header + 9, 3);
- num[3] = 0;
- fd->fileversion = atoi(num);
}
+
+ /* is the file saved in a different endian
+ * than we need ?
+ */
+ if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) {
+ fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
+ }
+
+ /* get the version number */
+ memcpy(num, header + 9, 3);
+ num[3] = 0;
+ fd->fileversion = atoi(num);
}
}
@@ -984,7 +997,13 @@ static int *read_file_thumbnail(FileData *fd)
BLI_endian_switch_int32(&data[1]);
}
- if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(data[0], data[1])) {
+ int width = data[0];
+ int height = data[1];
+
+ if (!BLEN_THUMB_SAFE_MEMSIZE(width, height)) {
+ break;
+ }
+ if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(width, height)) {
break;
}
@@ -1423,23 +1442,28 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
{
FileData *fd;
- BlendThumbnail *data;
+ BlendThumbnail *data = NULL;
int *fd_data;
fd = blo_openblenderfile_minimal(filepath);
fd_data = fd ? read_file_thumbnail(fd) : NULL;
if (fd_data) {
- const size_t sz = BLEN_THUMB_MEMSIZE(fd_data[0], fd_data[1]);
- data = MEM_mallocN(sz, __func__);
+ int width = fd_data[0];
+ int height = fd_data[1];
- BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(fd_data[0], fd_data[1]) - (sizeof(*fd_data) * 2)));
- data->width = fd_data[0];
- data->height = fd_data[1];
- memcpy(data->rect, &fd_data[2], sz - sizeof(*data));
- }
- else {
- data = NULL;
+ /* Protect against buffer overflow vulnerability. */
+ if (BLEN_THUMB_SAFE_MEMSIZE(width, height)) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(width, height);
+ data = MEM_mallocN(sz, __func__);
+
+ if (data) {
+ BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*fd_data) * 2)));
+ data->width = width;
+ data->height = height;
+ memcpy(data->rect, &fd_data[2], sz - sizeof(*data));
+ }
+ }
}
blo_freefiledata(fd);
@@ -1985,7 +2009,7 @@ static void test_pointer_array(FileData *fd, void **mat)
len = MEM_allocN_len(*mat)/fd->filesdna->pointerlen;
if (fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) {
- ipoin=imat= MEM_mallocN(len * 4, "newmatar");
+ ipoin=imat= MEM_malloc_arrayN(len, 4, "newmatar");
lpoin= *mat;
while (len-- > 0) {
@@ -2000,7 +2024,7 @@ static void test_pointer_array(FileData *fd, void **mat)
}
if (fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) {
- lpoin = lmat = MEM_mallocN(len * 8, "newmatar");
+ lpoin = lmat = MEM_malloc_arrayN(len, 8, "newmatar");
ipoin = *mat;
while (len-- > 0) {
@@ -3217,7 +3241,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
ntree->adt = newdataadr(fd, ntree->adt);
direct_link_animdata(fd, ntree->adt);
- ntree->id.tag &= ~(LIB_TAG_ID_RECALC|LIB_TAG_ID_RECALC_DATA);
+ ntree->id.recalc &= ~ID_RECALC_ALL;
link_list(fd, &ntree->nodes);
for (node = ntree->nodes.first; node; node = node->next) {
@@ -3987,6 +4011,9 @@ static void direct_link_curve(FileData *fd, Curve *cu)
cu->adt= newdataadr(fd, cu->adt);
direct_link_animdata(fd, cu->adt);
+ /* Protect against integer overflow vulnerability. */
+ CLAMP(cu->len_wchar, 0, INT_MAX - 4);
+
cu->mat = newdataadr(fd, cu->mat);
test_pointer_array(fd, (void **)&cu->mat);
cu->str = newdataadr(fd, cu->str);
@@ -3999,7 +4026,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
else {
cu->nurb.first=cu->nurb.last= NULL;
- tb = MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBoxread");
+ tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
if (cu->tb) {
memcpy(tb, cu->tb, cu->totbox*sizeof(TextBox));
MEM_freeN(cu->tb);
@@ -4119,10 +4146,6 @@ static void lib_link_material(FileData *fd, Main *main)
IDP_LibLinkProperty(ma->id.properties, fd);
lib_link_animdata(fd, &ma->id, ma->adt);
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- IDP_LibLinkProperty(ma->id.properties, fd);
-
ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system
ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
@@ -4406,6 +4429,9 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
for (a = 0; a < MAX_MTEX; a++) {
part->mtex[a] = newdataadr(fd, part->mtex[a]);
}
+
+ /* Protect against integer overflow vulnerability. */
+ CLAMP(part->trail_count, 1, 100000);
}
static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase *particles)
@@ -5353,9 +5379,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
collmd->xnew = newdataadr(fd, collmd->xnew);
collmd->mfaces = newdataadr(fd, collmd->mfaces);
- collmd->current_x = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_x");
- collmd->current_xnew = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_xnew");
- collmd->current_v = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_v");
+ collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
+ collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
+ collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
#endif
collmd->x = NULL;
@@ -5824,11 +5850,6 @@ static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollectio
BLI_assert(link->data);
}
- for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
- link->data = newlibadr_us(fd, lib, link->data);
- BLI_assert(link->data);
- }
-
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
lib_link_scene_collection(fd, lib, nsc);
}
@@ -6113,7 +6134,6 @@ static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *vi
static void direct_link_scene_collection(FileData *fd, SceneCollection *sc)
{
link_list(fd, &sc->objects);
- link_list(fd, &sc->filter_objects);
link_list(fd, &sc->scene_collections);
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
@@ -7172,6 +7192,7 @@ static void lib_link_screen(FileData *fd, Main *main)
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
sc->animtimer = NULL; /* saved in rare cases */
+ sc->tool_tip = NULL;
sc->scrubbing = false;
for (ScrArea *area = sc->areabase.first; area; area = area->next) {
@@ -8458,22 +8479,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
const char *idname = bhead_id_name(fd, bhead);
-#ifdef PRINT_DEBUG
- printf("Checking %s...\n", idname);
-#endif
+ DEBUG_PRINTF("Checking %s...\n", idname);
if (bhead->code == ID_LI) {
Main *libmain = fd->old_mainlist->first;
/* Skip oldmain itself... */
for (libmain = libmain->next; libmain; libmain = libmain->next) {
-#ifdef PRINT_DEBUG
- printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
-#endif
+ DEBUG_PRINTF("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
Main *oldmain = fd->old_mainlist->first;
-#ifdef PRINT_DEBUG
- printf("FOUND!\n");
-#endif
+ DEBUG_PRINTF("FOUND!\n");
/* In case of a library, we need to re-add its main to fd->mainlist, because if we have later
* a missing ID_ID, we need to get the correct lib it is linked to!
* Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */
@@ -8487,19 +8502,13 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
}
return blo_nextbhead(fd, bhead);
}
-#ifdef PRINT_DEBUG
- printf("nothing...\n");
-#endif
+ DEBUG_PRINTF("nothing...\n");
}
}
else {
-#ifdef PRINT_DEBUG
- printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>");
-#endif
+ DEBUG_PRINTF("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>");
if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) {
-#ifdef PRINT_DEBUG
- printf("FOUND!\n");
-#endif
+ DEBUG_PRINTF("FOUND!\n");
/* Even though we found our linked ID, there is no guarantee its address is still the same... */
if (id != bhead->old) {
oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
@@ -8511,9 +8520,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
}
return blo_nextbhead(fd, bhead);
}
-#ifdef PRINT_DEBUG
- printf("nothing...\n");
-#endif
+ DEBUG_PRINTF("nothing...\n");
}
}
@@ -8521,7 +8528,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id = read_struct(fd, bhead, "lib block");
if (id) {
- const short idcode = (bhead->code == ID_ID) ? GS(id->name) : bhead->code;
+ const short idcode = GS(id->name);
/* do after read_struct, for dna reconstruct */
lb = which_libbase(main, idcode);
if (lb) {
@@ -8546,6 +8553,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
+ id->orig_id = NULL;
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
@@ -8957,14 +8965,20 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
const int *data = read_file_thumbnail(fd);
if (data) {
- const size_t sz = BLEN_THUMB_MEMSIZE(data[0], data[1]);
- bfd->main->blen_thumb = MEM_mallocN(sz, __func__);
+ int width = data[0];
+ int height = data[1];
+
+ /* Protect against buffer overflow vulnerability. */
+ if (BLEN_THUMB_SAFE_MEMSIZE(width, height)) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(width, height);
+ bfd->main->blen_thumb = MEM_mallocN(sz, __func__);
- BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) ==
- (BLEN_THUMB_MEMSIZE_FILE(data[0], data[1]) - (sizeof(*data) * 2)));
- bfd->main->blen_thumb->width = data[0];
- bfd->main->blen_thumb->height = data[1];
- memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb));
+ BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) ==
+ (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*data) * 2)));
+ bfd->main->blen_thumb->width = width;
+ bfd->main->blen_thumb->height = height;
+ memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb));
+ }
}
}
@@ -9085,7 +9099,7 @@ static void sort_bhead_old_map(FileData *fd)
fd->tot_bheadmap = tot;
if (tot == 0) return;
- bhs = fd->bheadmap = MEM_mallocN(tot * sizeof(struct BHeadSort), "BHeadSort");
+ bhs = fd->bheadmap = MEM_malloc_arrayN(tot, sizeof(struct BHeadSort), "BHeadSort");
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead), bhs++) {
bhs->bhead = bhead;
@@ -9923,10 +9937,6 @@ static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection
expand_doit(fd, mainvar, link->data);
}
- for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
- expand_doit(fd, mainvar, link->data);
- }
-
for (SceneCollection *nsc= sc->scene_collections.first; nsc; nsc = nsc->next) {
expand_scene_collection(fd, mainvar, nsc);
}
@@ -10322,7 +10332,7 @@ static void give_base_to_objects(
if (flag & FILE_AUTOSELECT) {
/* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag,
- * but it will miss objects from non-instanciated groups... */
+ * but it will miss objects from non-instantiated groups... */
if (base->flag & BASE_SELECTABLED) {
base->flag |= BASE_SELECTED;
BKE_scene_object_base_flag_sync_from_base(base);
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 3ee6891f17f..7036470c8e4 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -951,7 +951,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
if (ob->totcol && ob->matbits == NULL) {
int a;
- ob->matbits = MEM_callocN(sizeof(char)*ob->totcol, "ob->matbits");
+ ob->matbits = MEM_calloc_arrayN(ob->totcol, sizeof(char), "ob->matbits");
for (a = 0; a < ob->totcol; a++)
ob->matbits[a] = (ob->colbits & (1<<a)) != 0;
}
@@ -1783,7 +1783,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
ParticleEditSettings *pset = &sce->toolsettings->particle;
int a;
- for (a = 0; a < PE_TOT_BRUSH; a++)
+ for (a = 0; a < ARRAY_SIZE(pset->brush); a++)
pset->brush[a].strength /= 100.0f;
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 77542d8deb9..3ac934f7de7 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -2453,11 +2453,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so = (SpaceOops *)sl;
- if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE,
- SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS,
- SO_USERDEF))
+ if (!ELEM(so->outlinevis,
+ SO_SCENES,
+ SO_GROUPS,
+ SO_LIBRARIES,
+ SO_SEQUENCE,
+ SO_DATABLOCKS))
{
- so->outlinevis = SO_ALL_SCENES;
+ so->outlinevis = SO_SCENES;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index bf2d5c8e326..0800437c3d2 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1243,7 +1243,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!MAIN_VERSION_ATLEAST(main, 277, 1)) {
for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) {
if (pset->brush[a].strength > 1.0f) {
pset->brush[a].strength *= 0.01f;
}
@@ -1593,7 +1593,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (scene->toolsettings != NULL) {
ToolSettings *ts = scene->toolsettings;
ParticleEditSettings *pset = &ts->particle;
- for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) {
if (pset->brush[a].count == 0) {
pset->brush[a].count = 10;
}
@@ -1786,6 +1786,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ /* Simple deform modifier no longer assumes Z axis (X for bend type).
+ * Must set previous defaults. */
+ if (!DNA_struct_elem_find(fd->filesdna, "SimpleDeformModifierData", "char", "deform_axis")) {
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_SimpleDeform) {
+ SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
+ smd->deform_axis = 2;
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 84aab78ff18..aef1621c93f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -45,6 +45,7 @@
#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
@@ -190,21 +191,21 @@ void do_versions_after_linking_280(Main *main)
.collections = {NULL},
.created = 0,
.suffix = "",
- .flag_viewport = COLLECTION_VISIBLE | COLLECTION_SELECTABLE,
- .flag_render = COLLECTION_VISIBLE | COLLECTION_SELECTABLE
+ .flag_viewport = COLLECTION_SELECTABLE,
+ .flag_render = COLLECTION_SELECTABLE
},
{
.collections = {NULL},
.created = 0,
.suffix = " - Hide Viewport",
.flag_viewport = COLLECTION_SELECTABLE,
- .flag_render = COLLECTION_VISIBLE | COLLECTION_SELECTABLE
+ .flag_render = COLLECTION_SELECTABLE
},
{
.collections = {NULL},
.created = 0,
.suffix = " - Hide Render",
- .flag_viewport = COLLECTION_VISIBLE | COLLECTION_SELECTABLE,
+ .flag_viewport = COLLECTION_SELECTABLE,
.flag_render = COLLECTION_SELECTABLE | COLLECTION_DISABLED
},
{
@@ -352,7 +353,7 @@ void do_versions_after_linking_280(Main *main)
view_layer->pass_xor = srl->pass_xor;
view_layer->pass_alpha_threshold = srl->pass_alpha_threshold;
- BKE_freestyle_config_free(&view_layer->freestyle_config);
+ BKE_freestyle_config_free(&view_layer->freestyle_config, true);
view_layer->freestyle_config = srl->freestyleConfig;
view_layer->id_properties = srl->prop;
@@ -392,13 +393,9 @@ void do_versions_after_linking_280(Main *main)
for (int j = 1; j < 4; j++) {
if (collections[j].created & (1 << layer)) {
- layer_collection_child->flag =
- collections[j].flag_render & (~COLLECTION_DISABLED);
-
- if (collections[j].flag_render & COLLECTION_DISABLED) {
- BKE_collection_disable(view_layer, layer_collection_child);
- }
-
+ layer_collection_child->flag = COLLECTION_VIEWPORT |
+ COLLECTION_RENDER |
+ collections[j].flag_render;
layer_collection_child = layer_collection_child->next;
}
}
@@ -429,7 +426,7 @@ void do_versions_after_linking_280(Main *main)
IDP_FreeProperty(srl->prop);
MEM_freeN(srl->prop);
}
- BKE_freestyle_config_free(&srl->freestyleConfig);
+ BKE_freestyle_config_free(&srl->freestyleConfig, true);
}
}
BLI_freelistN(&scene->r.layers);
@@ -451,7 +448,7 @@ void do_versions_after_linking_280(Main *main)
/* We only need to disable the parent collection. */
if (is_disabled) {
- BKE_collection_disable(view_layer, layer_collection_parent);
+ layer_collection_parent->flag |= COLLECTION_DISABLED;
}
LayerCollection *layer_collection_child;
@@ -459,11 +456,9 @@ void do_versions_after_linking_280(Main *main)
for (int j = 1; j < 4; j++) {
if (collections[j].created & (1 << layer)) {
- layer_collection_child->flag = collections[j].flag_viewport & (~COLLECTION_DISABLED);
-
- if (collections[j].flag_viewport & COLLECTION_DISABLED) {
- BKE_collection_disable(view_layer, layer_collection_child);
- }
+ layer_collection_child->flag = COLLECTION_VIEWPORT |
+ COLLECTION_RENDER |
+ collections[j].flag_viewport;
layer_collection_child = layer_collection_child->next;
}
}
@@ -488,11 +483,6 @@ void do_versions_after_linking_280(Main *main)
base->lay = base->object->lay;
}
- /* Fallback name if only one layer was found in the original file */
- if (BLI_listbase_is_single(&sc_master->scene_collections)) {
- BKE_collection_rename(scene, sc_master->scene_collections.first, "Default Collection");
- }
-
/* remove bases once and for all */
for (Base *base = scene->base.first; base; base = base->next) {
id_us_min(&base->object->id);
@@ -514,7 +504,7 @@ void do_versions_after_linking_280(Main *main)
if (view_layer->spacetype == SPACE_OUTLINER) {
SpaceOops *soutliner = (SpaceOops *)view_layer;
- soutliner->outlinevis = SO_ACT_LAYER;
+ soutliner->outlinevis = SO_VIEW_LAYER;
if (BLI_listbase_count_ex(&layer->layer_collections, 2) == 1) {
if (soutliner->treestore == NULL) {
@@ -551,7 +541,7 @@ void do_versions_after_linking_280(Main *main)
IDP_FreeProperty(srl->prop);
MEM_freeN(srl->prop);
}
- BKE_freestyle_config_free(&srl->freestyleConfig);
+ BKE_freestyle_config_free(&srl->freestyleConfig, true);
}
BLI_freelistN(&scene->r.layers);
}
@@ -580,7 +570,9 @@ void do_versions_after_linking_280(Main *main)
}
}
}
- BLI_assert(workspace->view_layer == NULL);
+ /* While this should apply to most cases, it fails when reading workspaces.blend
+ * to get its list of workspaces without actually appending any of them. */
+// BLI_assert(workspace->view_layer == NULL);
}
}
@@ -606,11 +598,9 @@ void do_versions_after_linking_280(Main *main)
if (sc_hidden != NULL) {
LayerCollection *layer_collection_master, *layer_collection_hidden;
-
layer_collection_master = group->view_layer->layer_collections.first;
layer_collection_hidden = layer_collection_master->layer_collections.first;
-
- layer_collection_hidden->flag &= ~COLLECTION_VISIBLE;
+ layer_collection_hidden->flag |= COLLECTION_DISABLED;
}
}
@@ -620,6 +610,38 @@ void do_versions_after_linking_280(Main *main)
}
}
}
+
+ {
+ for (Object *object = main->object.first; object; object = object->id.next) {
+#ifndef VERSION_280_SUBVERSION_4
+ /* If any object already has an initialized value for
+ * duplicator_visibility_flag it means we've already doversioned it.
+ * TODO(all) remove the VERSION_280_SUBVERSION_4 code once the subversion was bumped. */
+ if (object->duplicator_visibility_flag != 0) {
+ break;
+ }
+#endif
+ if (object->particlesystem.first) {
+ object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
+ for (ParticleSystem *psys = object->particlesystem.first; psys; psys=psys->next) {
+ if (psys->part->draw & PART_DRAW_EMITTER) {
+ object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER;
+#ifndef VERSION_280_SUBVERSION_4
+ psys->part->draw &= ~PART_DRAW_EMITTER;
+#else
+ break;
+#endif
+ }
+ }
+ }
+ else if (object->transflag & OB_DUPLI){
+ object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
+ }
+ else {
+ object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
+ }
+ }
+ }
}
static void do_version_layer_collections_idproperties(ListBase *lb)
@@ -641,6 +663,25 @@ static void do_version_layer_collections_idproperties(ListBase *lb)
}
}
+static void do_version_view_layer_visibility(ViewLayer *view_layer)
+{
+ LayerCollection *layer_collection;
+ for (layer_collection = view_layer->layer_collections.first;
+ layer_collection;
+ layer_collection = layer_collection->next)
+ {
+ if (layer_collection->flag & COLLECTION_DISABLED) {
+ BKE_collection_enable(view_layer, layer_collection);
+ layer_collection->flag &= ~COLLECTION_DISABLED;
+ }
+
+ if ((layer_collection->flag & (1 << 0)) == 0) { /* !COLLECTION_VISIBLE */
+ layer_collection->flag |= COLLECTION_DISABLED;
+ }
+ layer_collection->flag |= COLLECTION_VIEWPORT | COLLECTION_RENDER;
+ }
+}
+
void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
{
@@ -840,6 +881,61 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
+ if (!MAIN_VERSION_ATLEAST(main, 280, 3)) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ do_version_view_layer_visibility(view_layer);
+ }
+ }
+
+ for (Group *group = main->group.first; group; group = group->id.next) {
+ if (group->view_layer != NULL){
+ do_version_view_layer_visibility(group->view_layer);
+ }
+ }
+ }
+
+ {
+ if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) {
+ bScreen *sc;
+ ScrArea *sa;
+ SpaceLink *sl;
+
+ /* Update files using invalid (outdated) outlinevis Outliner values. */
+ for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *so = (SpaceOops *)sl;
+
+ if (!ELEM(so->outlinevis,
+ SO_SCENES,
+ SO_GROUPS,
+ SO_LIBRARIES,
+ SO_SEQUENCE,
+ SO_DATABLOCKS,
+ SO_ID_ORPHANS,
+ SO_VIEW_LAYER,
+ SO_COLLECTIONS))
+ {
+ so->outlinevis = SO_VIEW_LAYER;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) {
+ for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) {
+ probe->intensity = 1.0f;
+ }
+ }
+ }
+
if (!DNA_struct_find(fd->filesdna, "SpaceTopBar")) {
for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index e2d4b140311..b09c7d77e59 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -58,7 +58,7 @@ void BLO_update_defaults_userpref_blend(void)
{
/* defaults from T37518 */
- U.uiflag |= USER_ZBUF_CURSOR;
+ U.uiflag |= USER_DEPTH_CURSOR;
U.uiflag |= USER_QUIT_PROMPT;
U.uiflag |= USER_CONTINUOUS_MOUSE;
@@ -203,7 +203,7 @@ void BLO_update_defaults_startup_blend(Main *bmain)
ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
ParticleEditSettings *pset = &ts->particle;
- for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) {
pset->brush[a].strength = 0.5f;
pset->brush[a].count = 10;
}
@@ -273,6 +273,7 @@ void BLO_update_defaults_startup_blend(Main *bmain)
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Fill");
if (!br) {
br = BKE_brush_add(bmain, "Fill", OB_MODE_TEXTURE_PAINT);
+ id_us_min(&br->id); /* fake user only */
br->imagepaint_tool = PAINT_TOOL_FILL;
br->ob_mode = OB_MODE_TEXTURE_PAINT;
}
@@ -281,12 +282,14 @@ void BLO_update_defaults_startup_blend(Main *bmain)
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Average");
if (!br) {
br = BKE_brush_add(bmain, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
+ id_us_min(&br->id); /* fake user only */
br->vertexpaint_tool = PAINT_BLEND_AVERAGE;
br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
}
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Smear");
if (!br) {
br = BKE_brush_add(bmain, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
+ id_us_min(&br->id); /* fake user only */
br->vertexpaint_tool = PAINT_BLEND_SMEAR;
br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 156a6e3d1c0..0af1c3951ad 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -113,7 +113,7 @@ static void vcol_to_fcol(Mesh *me)
if (me->totface == 0 || me->mcol == NULL)
return;
- mcoln = mcolmain = MEM_mallocN(4*sizeof(int)*me->totface, "mcoln");
+ mcoln = mcolmain = MEM_malloc_arrayN(me->totface, 4 * sizeof(int), "mcoln");
mcol = (unsigned int *)me->mcol;
mface = me->mface;
for (a = me->totface; a > 0; a--, mface++) {
@@ -1871,7 +1871,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
BKE_pose_tag_recalc(main, ob->pose);
/* cannot call stuff now (pointers!), done in setup_app_data */
- ob->id.tag |= LIB_TAG_ID_RECALC_ALL;
+ ob->id.recalc |= ID_RECALC_ALL;
/* new generic xray option */
arm = blo_do_versions_newlibadr(fd, lib, ob->data);
@@ -2949,7 +2949,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
- part = psys->part = psys_new_settings("ParticleSettings", main);
+ part = psys->part = BKE_particlesettings_add(main, "ParticleSettings");
/* needed for proper libdata lookup */
blo_do_versions_oldnewmap_insert(fd->libmap, psys->part, psys->part, 0);
@@ -3068,7 +3068,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
pset->totaddkey = 5;
pset->brushtype = PE_BRUSH_NONE;
- for (a = 0; a < PE_TOT_BRUSH; a++) {
+ for (a = 0; a < ARRAY_SIZE(pset->brush); a++) {
pset->brush[a].strength = 50;
pset->brush[a].size = 50;
pset->brush[a].step = 10;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0f9f509bfde..c5690376305 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -708,8 +708,10 @@ static void write_iddata(void *wd, const ID *id)
static void write_previews(WriteData *wd, const PreviewImage *prv_orig)
{
- /* Never write previews when doing memsave (i.e. undo/redo)! */
- if (prv_orig && !wd->current) {
+ /* Note we write previews also for undo steps. It takes up some memory,
+ * but not doing so would causes all previews to be re-rendered after
+ * undo which is too expensive. */
+ if (prv_orig) {
PreviewImage prv = *prv_orig;
/* don't write out large previews if not requested */
@@ -2594,7 +2596,6 @@ static void write_scene_collection(WriteData *wd, SceneCollection *sc)
writestruct(wd, DATA, SceneCollection, 1, sc);
writelist(wd, DATA, LinkData, &sc->objects);
- writelist(wd, DATA, LinkData, &sc->filter_objects);
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
write_scene_collection(wd, nsc);
@@ -3882,6 +3883,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
memset(fg.pad, 0, sizeof(fg.pad));
memset(fg.filename, 0, sizeof(fg.filename));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
+ fg.pad1 = NULL;
current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer);
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 96b2eb17c4c..8a1090891f2 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -419,7 +419,10 @@ typedef struct BMLoopInterpMultiresData {
float d;
} BMLoopInterpMultiresData;
-static void loop_interp_multires_cb(void *userdata, int ix)
+static void loop_interp_multires_cb(
+ void *__restrict userdata,
+ const int ix,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
BMLoopInterpMultiresData *data = userdata;
@@ -507,7 +510,10 @@ void BM_loop_interp_multires_ex(
.axis_x = axis_x, .axis_y = axis_y, .v1 = v1, .v4 = v4, .e1 = e1, .e2 = e2,
.res = res, .d = 1.0f / (float)(res - 1)
};
- BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, res > 5);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (res > 5);
+ BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings);
}
/**
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index b474ad9fc7b..60fd9808fcb 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -72,14 +72,15 @@
BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
#if 0
-#define ELE_TOUCH_TEST(e) \
- (CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \
- BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED))
+#define ELE_TOUCH_TEST(e) ( \
+ CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \
+ BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) \
+)
#endif
-#define ELE_TOUCH_MARK(e) \
- { CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \
- BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); } ((void)0)
-
+#define ELE_TOUCH_MARK(e) { \
+ CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \
+ BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); \
+} ((void)0)
#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)v, ELE_TOUCHED)
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index e35c1f3b66c..394faabbd25 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -389,12 +389,10 @@ void bmo_split_exec(BMesh *bm, BMOperator *op)
BMOperator *splitop = op;
BMOperator dupeop;
- BMOperator delop;
const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces");
/* initialize our sub-operator */
BMO_op_init(bm, &dupeop, op->flag, "duplicate");
- BMO_op_init(bm, &delop, op->flag, "delete");
BMO_slot_copy(splitop, slots_in, "geom",
&dupeop, slots_in, "geom");
@@ -437,24 +435,13 @@ void bmo_split_exec(BMesh *bm, BMOperator *op)
}
/* connect outputs of dupe to delete, exluding keep geometry */
- BMO_slot_int_set(delop.slots_in, "context", DEL_FACES);
- BMO_slot_buffer_from_enabled_flag(bm, &delop, delop.slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT);
-
- BMO_op_exec(bm, &delop);
+ BMO_mesh_delete_oflag_context(bm, SPLIT_INPUT, DEL_FACES);
/* now we make our outputs by copying the dupe output */
BMO_slot_copy(&dupeop, slots_out, "geom.out",
splitop, slots_out, "geom.out");
- BMO_slot_copy(&dupeop, slots_out, "boundary_map.out",
- splitop, slots_out, "boundary_map.out");
-
- BMO_slot_copy(&dupeop, slots_out, "isovert_map.out",
- splitop, slots_out, "isovert_map.out");
-
-
/* cleanup */
- BMO_op_finish(bm, &delop);
BMO_op_finish(bm, &dupeop);
#undef SPLIT_INPUT
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 2c6213dacce..35167835646 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -44,6 +44,8 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
+#include "eigen_capi.h"
+
#include "bmesh.h"
#include "bmesh_bevel.h" /* own include */
@@ -58,6 +60,7 @@
#define BEVEL_SMALL_ANG DEG2RADF(10.0f)
#define BEVEL_MAX_ADJUST_PCT 10.0f
#define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f
+#define BEVEL_MATCH_SPEC_WEIGHT 0.2
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
@@ -139,10 +142,14 @@ typedef struct BoundVert {
NewVert nv;
EdgeHalf *efirst; /* first of edges attached here: in CCW order */
EdgeHalf *elast;
+ EdgeHalf *eon; /* the "edge between" that this is on, in offset_on_edge_between case */
EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */
int index; /* used for vmesh indexing */
+ float sinratio; /* when eon set, ratio of sines of angles to eon edge */
+ struct BoundVert *adjchain; /* adjustment chain or cycle link pointer */
Profile profile; /* edge profile between this and next BoundVert */
bool any_seam; /* are any of the edges attached here seams? */
+ bool visited; /* used during delta adjust pass */
// int _pad;
} BoundVert;
@@ -192,6 +199,7 @@ typedef struct BevelParams {
bool use_weights; /* bevel amount affected by weights on edges or verts */
bool loop_slide; /* should bevel prefer to slide along edges rather than keep widths spec? */
bool limit_offset; /* should offsets be limited by collisions? */
+ bool offset_adjust; /* should offsets be adjusted to try to get even widths? */
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
@@ -207,6 +215,7 @@ static int bev_debug_flags = 0;
#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+
/* this flag values will get set on geom we want to return in 'out' slots for edges and verts */
#define EDGE_OUT 4
#define VERT_OUT 8
@@ -260,6 +269,9 @@ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float
vm->boundstart->prev = ans;
}
ans->profile.super_r = PRO_LINE_R;
+ ans->adjchain = NULL;
+ ans->sinratio = 1.0f;
+ ans->visited = false;
vm->count++;
return ans;
}
@@ -342,52 +354,6 @@ static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e, BevVert
return NULL;
}
-static bool other_edge_half_visited(BevelParams *bp, EdgeHalf *e)
-{
- BevVert *bvo;
-
- bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2);
- if (bvo)
- return bvo->visited;
- else
- return false;
-}
-
-static bool edge_half_offset_changed(EdgeHalf *e)
-{
- return e->offset_l != e->offset_l_spec ||
- e->offset_r != e->offset_r_spec;
-}
-
-static float adjusted_rel_change(float val, float spec)
-{
- float relchg;
-
- relchg = 0.0f;
- if (val != spec) {
- if (spec == 0)
- relchg = 1000.0f; /* arbitrary large value */
- else
- relchg = fabsf((val - spec) / spec);
- }
- return relchg;
-}
-
-static float max_edge_half_offset_rel_change(BevVert *bv)
-{
- int i;
- float max_rel_change;
- EdgeHalf *e;
-
- max_rel_change = 0.0f;
- for (i = 0; i < bv->edgecount; i++) {
- e = &bv->edges[i];
- max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec));
- max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec));
- }
- return max_rel_change;
-}
-
/* Return the next EdgeHalf after from_e that is beveled.
* If from_e is NULL, find the first beveled edge. */
static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
@@ -718,14 +684,18 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3])
/* Is co not on the edge e? if not, return the closer end of e in ret_closer_v */
static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_v)
{
- float d_squared;
-
- d_squared = dist_squared_to_line_segment_v3(co, e->e->v1->co, e->e->v2->co);
- if (d_squared > BEVEL_EPSILON_BIG * BEVEL_EPSILON_BIG) {
- if (len_squared_v3v3(co, e->e->v1->co) > len_squared_v3v3(co, e->e->v2->co))
- *ret_closer_v = e->e->v2;
- else
- *ret_closer_v = e->e->v1;
+ float h[3], u[3], lambda, lenu, *l1 = e->e->v1->co;
+
+ sub_v3_v3v3(u, e->e->v2->co, l1);
+ sub_v3_v3v3(h, co, l1);
+ lenu = normalize_v3(u);
+ lambda = dot_v3v3(u, h);
+ if (lambda <= -BEVEL_EPSILON_BIG * lenu) {
+ *ret_closer_v = e->e->v1;
+ return true;
+ }
+ else if (lambda >= (1.0f + BEVEL_EPSILON_BIG) * lenu) {
+ *ret_closer_v = e->e->v2;
return true;
}
else {
@@ -814,10 +784,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
copy_v3_v3(off1a, v->co);
d = max_ff(e1->offset_r, e2->offset_l);
madd_v3_v3fl(off1a, norm_perp1, d);
- if (e1->offset_r != d)
- e1->offset_r = d;
- else if (e2->offset_l != d)
- e2->offset_l = d;
copy_v3_v3(meetco, off1a);
}
else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) {
@@ -826,10 +792,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
* common line, at offset distance from v. */
d = max_ff(e1->offset_r, e2->offset_l);
slide_dist(e2, v, d, meetco);
- if (e1->offset_r != d)
- e1->offset_r = d;
- else if (e2->offset_l != d)
- e2->offset_l = d;
}
else {
/* Get normal to plane where meet point should be,
@@ -867,7 +829,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
negate_v3(norm_v2);
}
-
/* get vectors perp to each edge, perp to norm_v, and pointing into face */
cross_v3_v3v3(norm_perp1, dir1, norm_v1);
cross_v3_v3v3(norm_perp2, dir2, norm_v2);
@@ -887,9 +848,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
if (isect_kind == 0) {
/* lines are collinear: we already tested for this, but this used a different epsilon */
copy_v3_v3(meetco, off1a); /* just to do something */
- d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
- if (fabsf(d - e2->offset_l) > BEVEL_EPSILON)
- e2->offset_l = d;
}
else {
/* The lines intersect, but is it at a reasonable place?
@@ -899,11 +857,9 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
* or if the offset amount is > the edge length*/
if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) {
copy_v3_v3(meetco, closer_v->co);
- e2->offset_l = len_v3v3(meetco, v->co);
}
if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco, &closer_v)) {
copy_v3_v3(meetco, closer_v->co);
- e1->offset_r = len_v3v3(meetco, v->co);
}
if (edges_between && e1->offset_r > 0.0f && e2->offset_l > 0.0f) {
/* Try to drop meetco to a face between e1 and e2 */
@@ -922,8 +878,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
break;
}
}
- e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
- e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
}
}
}
@@ -990,40 +944,27 @@ static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *em
/* Calculate the best place for a meeting point for the offsets from edges e1 and e2
* on the in-between edge emid. Viewed from the vertex normal side, the CCW
* order of these edges is e1, emid, e2.
- * The offsets probably do not meet at a common point on emid, so need to pick
- * one that causes the least problems. If the other end of one of e1 or e2 has been visited
- * already, prefer to keep the offset the same on this end.
- * Otherwise, pick a point between the two intersection points on emid that minimizes
- * the sum of squares of errors from desired offset. */
-static void offset_on_edge_between(
- BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
- BMVert *v, float meetco[3])
+ * Return true if we placed meetco as compromise between where two edges met.
+ * If we did, put ration of sines of angles in *r_sinratio too */
+static bool offset_on_edge_between(
+ EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ BMVert *v, float meetco[3], float *r_sinratio)
{
- float d, ang1, ang2, sina1, sina2, lambda;
+ float ang1, ang2;
float meet1[3], meet2[3];
- bool visited1, visited2, ok1, ok2;
+ bool ok1, ok2;
+ bool retval = false;
BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev);
- visited1 = other_edge_half_visited(bp, e1);
- visited2 = other_edge_half_visited(bp, e2);
-
ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1);
ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2);
if (ok1 && ok2) {
- if (visited1 && !visited2) {
- copy_v3_v3(meetco, meet1);
- }
- else if (!visited1 && visited2) {
- copy_v3_v3(meetco, meet2);
- }
- else {
- /* find best compromise meet point */
- sina1 = sinf(ang1);
- sina2 = sinf(ang2);
- lambda = sina2 * sina2 / (sina1 * sina1 + sina2 * sina2);
- interp_v3_v3v3(meetco, meet1, meet2, lambda);
- }
+ mid_v3_v3v3(meetco, meet1, meet2);
+ if (r_sinratio)
+ /* ang1 should not be 0, but be paranoid */
+ *r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1);
+ retval = true;
}
else if (ok1 && !ok2) {
copy_v3_v3(meetco, meet1);
@@ -1037,13 +978,7 @@ static void offset_on_edge_between(
slide_dist(emid, v, e1->offset_r, meetco);
}
- /* offsets may have changed now */
- d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
- if (fabsf(d - e1->offset_r) > BEVEL_EPSILON)
- e1->offset_r = d;
- d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
- if (fabsf(d - e2->offset_l) > BEVEL_EPSILON)
- e2->offset_l = d;
+ return retval;
}
/* Offset by e->offset in plane with normal plane_no, on left if left==true,
@@ -1688,7 +1623,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
* Special case of build_boundary when a single edge is beveled.
* The 'width adjust' part of build_boundary has been done already,
* and \a efirst is the first beveled edge at vertex \a bv.
-*/
+ */
static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct)
{
MemArena *mem_arena = bp->mem_arena;
@@ -1802,6 +1737,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
}
}
+#if 0
/* Return a value that is v if v is within BEVEL_MAX_ADJUST_PCT of the spec (assumed positive),
* else clamp to make it at most that far away from spec */
static float clamp_adjust(float v, float spec)
@@ -1815,6 +1751,7 @@ static float clamp_adjust(float v, float spec)
else
return v;
}
+#endif
/* Make a circular list of BoundVerts for bv, each of which has the coordinates
* of a vertex on the boundary of the beveled vertex bv->v.
@@ -1831,11 +1768,10 @@ static float clamp_adjust(float v, float spec)
static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
{
MemArena *mem_arena = bp->mem_arena;
- EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eother;
+ EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon;
BoundVert *v;
- BevVert *bvother;
VMesh *vm;
- float co[3];
+ float co[3], r;
int nip, nnip;
/* Current bevel does nothing if only one edge into a vertex */
@@ -1849,30 +1785,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
vm = bv->vmesh;
- /* Find a beveled edge to be efirst. Then for each edge, try matching widths to other end. */
+ /* Find a beveled edge to be efirst */
e = efirst = next_bev(bv, NULL);
BLI_assert(e->is_bev);
- do {
- eother = find_other_end_edge_half(bp, e, &bvother);
- if (eother && bvother->visited && bp->offset_type != BEVEL_AMT_PERCENT) {
- /* try to keep bevel even by matching other end offsets */
- /* sometimes, adjustment can accumulate errors so use the bp->limit_offset to
- * let user limit the adjustment to within a reasonable range around spec */
- if (bp->limit_offset) {
- e->offset_l = clamp_adjust(eother->offset_r, e->offset_l_spec);
- e->offset_r = clamp_adjust(eother->offset_l, e->offset_r_spec);
- }
- else {
- e->offset_l = eother->offset_r;
- e->offset_r = eother->offset_l;
- }
- }
- else {
- /* reset to user spec */
- e->offset_l = e->offset_l_spec;
- e->offset_r = e->offset_r_spec;
- }
- } while ((e = e->next) != efirst);
if (bv->selcount == 1) {
/* special case: only one beveled edge in */
@@ -1886,6 +1801,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
e = efirst;
do {
BLI_assert(e->is_bev);
+ eon = NULL;
/* Make the BoundVert for the right side of e; other side will be made
* when the beveled edge to the left of e is handled.
* Analyze edges until next beveled edge.
@@ -1909,7 +1825,8 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
else if (nnip > 0) {
if (bp->loop_slide && nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
- offset_on_edge_between(bp, e, e2, enip, bv->v, co);
+ if (offset_on_edge_between(e, e2, enip, bv->v, co, &r))
+ eon = enip;
}
else {
offset_meet(e, e2, bv->v, NULL, true, co);
@@ -1918,7 +1835,8 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
else {
/* nip > 0 and nnip == 0 */
if (bp->loop_slide && nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) {
- offset_on_edge_between(bp, e, e2, eip, bv->v, co);
+ if (offset_on_edge_between(e, e2, eip, bv->v, co, &r))
+ eon = eip;
}
else {
offset_meet(e, e2, bv->v, e->fnext, true, co);
@@ -1929,6 +1847,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
v->efirst = e;
v->elast = e2;
v->ebev = e2;
+ v->eon = eon;
+ if (eon)
+ v->sinratio = r;
e->rightv = v;
e2->leftv = v;
for (e3 = e->next; e3 != e2; e3 = e3->next) {
@@ -1958,98 +1879,328 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
-/* Do a global pass to try to make offsets as even as possible.
- * Consider this graph:
- * nodes = BevVerts
- * edges = { (u,v) } where u and v are nodes such that u and v
- * are connected by a mesh edge that has at least one end
- * whose offset does not match the user spec.
- *
- * Do a breadth-first search on this graph, starting from nodes
- * that have any_adjust=true, and changing all
- * not-already-changed offsets on EdgeHalfs to match the
- * corresponding ones that changed on the other end.
- * The graph is dynamic in the sense that having an offset that
- * doesn't meet the user spec can be added as the search proceeds.
- * We want this search to be deterministic (not dependent
- * on order of processing through hash table), so as to avoid
- * flicker to to different decisions made if search is different
- * while dragging the offset number in the UI. So look for the
- * lower vertex number when there is a choice of where to start.
+#if 0
+static void print_adjust_stats(BoundVert *vstart)
+{
+ BoundVert *v;
+ EdgeHalf *eleft, *eright;
+ double even_residual2, spec_residual2;
+ double max_even_r, max_even_r_pct;
+ double max_spec_r, max_spec_r_pct;
+ double delta, delta_pct;
+
+ printf("\nSolution analysis\n");
+ even_residual2 = 0.0;
+ spec_residual2 = 0.0;
+ max_even_r = 0.0;
+ max_even_r_pct = 0.0;
+ max_spec_r = 0.0;
+ max_spec_r_pct = 0.0;
+ printf("width matching\n");
+ v = vstart;
+ do {
+ if (v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->adjchain->elast;
+ delta = fabs(eright->offset_r - eleft->offset_l);
+ delta_pct = 100.0 * delta / eright->offset_r_spec;
+ printf("e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n",
+ BM_elem_index_get(eright->e), eright->offset_r, eleft->offset_l, delta, delta_pct);
+ even_residual2 += delta * delta;
+ if (delta > max_even_r)
+ max_even_r = delta;
+ if (delta_pct > max_even_r_pct)
+ max_even_r_pct = delta_pct;
+ }
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ printf("spec matching\n");
+ v = vstart;
+ do {
+ if (v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->adjchain->elast;
+ delta = fabs(eright->offset_r - eright->offset_r_spec);
+ delta_pct = 100.0 * delta / eright->offset_r_spec;
+ printf("e%d r(%f) vs r spec(%f): abs(delta)=%f, delta_pct=%f\n",
+ BM_elem_index_get(eright->e), eright->offset_r, eright->offset_r_spec, delta, delta_pct);
+ spec_residual2 += delta * delta;
+ if (delta > max_spec_r)
+ max_spec_r = delta;
+ if (delta_pct > max_spec_r_pct)
+ max_spec_r_pct = delta_pct;
+
+ delta = fabs(eleft->offset_l - eleft->offset_l_spec);
+ delta_pct = 100.0 * delta / eright->offset_l_spec;
+ printf("e%d l(%f) vs l spec(%f): abs(delta)=%f, delta_pct=%f\n",
+ BM_elem_index_get(eright->e), eleft->offset_l, eleft->offset_l_spec, delta, delta_pct);
+ spec_residual2 += delta * delta;
+ if (delta > max_spec_r)
+ max_spec_r = delta;
+ if (delta_pct > max_spec_r_pct)
+ max_spec_r_pct = delta_pct;
+ }
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ printf("Analysis Result:\n");
+ printf("even residual2 = %f, spec residual2 = %f\n", even_residual2, spec_residual2);
+ printf("max even delta = %f, max as percent of spec = %f\n", max_even_r, max_even_r_pct);
+ printf("max spec delta = %f, max as percent of spec = %f\n", max_spec_r, max_spec_r_pct);
+}
+#endif
+
+static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscycle)
+{
+ BoundVert *v;
+ EdgeHalf *eleft, *eright;
+ float *g;
+ float *g_prod;
+ float gprod, gprod_sum, spec_sum, p;
+ int i;
+
+ g = MEM_mallocN(np * sizeof(float), "beveladjust");
+ g_prod = MEM_mallocN(np * sizeof(float), "beveladjust");
+
+ v = vstart;
+ spec_sum = 0.0f;
+ i = 0;
+ do {
+ g[i] = v->sinratio;
+ if (iscycle || v->adjchain != NULL) {
+ spec_sum += v->efirst->offset_r;
+ }
+ else {
+ spec_sum += v->elast->offset_l;
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ gprod = 1.00f;
+ gprod_sum = 1.0f;
+ for (i = np - 1; i > 0; i--) {
+ gprod *= g[i];
+ g_prod[i] = gprod;
+ gprod_sum += gprod;
+ }
+ if (iscycle) {
+ gprod *= g[0];
+ if (fabs(gprod - 1.0f) > BEVEL_EPSILON) {
+ /* fast cycle calc only works if total product is 1 */
+ MEM_freeN(g);
+ MEM_freeN(g_prod);
+ return false;
+ }
+ else
+ g_prod[0] = 1.0f;
+ }
+ if (gprod_sum == 0.0f) {
+ MEM_freeN(g);
+ MEM_freeN(g_prod);
+ return false;
+ }
+ p = spec_sum / gprod_sum;
+
+ /* apply the new offsets */
+ v = vstart;
+ i = 0;
+ do {
+ if (iscycle || v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->elast;
+ eright->offset_r = g_prod[(i + 1) % np] * p;
+ if (iscycle || v != vstart) {
+ eleft->offset_l = v->sinratio * eright->offset_r;
+ }
+ }
+ else {
+ /* not a cycle, and last of chain */
+ eleft = v->elast;
+ eleft->offset_l = p;
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ MEM_freeN(g);
+ MEM_freeN(g_prod);
+ return true;
+}
+
+/* Adjust the offsets for a single cycle or chain.
+ * For chains and some cycles, a fast solution exists.
+ * Otherwise, we set up and solve a linear least squares problem
+ * that tries to minimize the squared differences of lengths
+ * at each end of an edge, and (with smaller weight) the
+ * squared differences of the offsets from their specs.
+ */
+static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle)
+{
+ BoundVert *v;
+ EdgeHalf *eleft, *eright;
+ LinearSolver *solver;
+ double weight, val;
+ int i, np, nrows, row;
+
+ np = 0;
+ v = vstart;
+ do {
+ np++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ if (adjust_the_cycle_or_chain_fast(vstart, np, iscycle))
+ return;
+
+ nrows = iscycle ? 2 * np : 2 * np - 1;
+
+ solver = EIG_linear_least_squares_solver_new(nrows, np, 1);
+
+ v = vstart;
+ i = 0;
+ weight = BEVEL_MATCH_SPEC_WEIGHT; /* sqrt of factor to weight down importance of spec match */
+ do {
+ /* except at end of chain, v's indep variable is offset_r of v->efirst */
+ if (iscycle || v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->elast;
+
+ /* residue i: width difference between eright and eleft of next */
+ EIG_linear_solver_matrix_add(solver, i, i, 1.0);
+ EIG_linear_solver_right_hand_side_add(solver, 0, i, 0.0);
+ if (iscycle) {
+ EIG_linear_solver_matrix_add(solver, i > 0 ? i - 1 : np - 1, i, -v->sinratio);
+ }
+ else {
+ if (i > 0)
+ EIG_linear_solver_matrix_add(solver, i - 1, i, -v->sinratio);
+ }
+
+ /* residue np + i (if cycle) else np - 1 + i:
+ * right offset for parm i matches its spec; weighted */
+ row = iscycle ? np + i : np - 1 + i;
+ EIG_linear_solver_matrix_add(solver, row, i, weight);
+ EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r);
+ }
+ else {
+ /* not a cycle, and last of chain */
+ eleft = v->elast;
+ /* second part of residue i for last i */
+ EIG_linear_solver_matrix_add(solver, i - 1, i, -1.0);
+ /* residue 2 * np -2 : last spec match residue is for left offset of final parm */
+ row = 2 * np - 2;
+ EIG_linear_solver_matrix_add(solver, row, i, weight);
+ EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eleft->offset_l);
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+ EIG_linear_solver_solve(solver);
+
+ /* Use the solution to set new widths */
+ v = vstart;
+ i = 0;
+ do {
+ val = EIG_linear_solver_variable_get(solver, 0, i);
+ if (iscycle || v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->elast;
+ eright->offset_r = (float)val;
+ if (iscycle || v != vstart) {
+ eleft->offset_l = (float)(v->sinratio * val);
+ }
+ }
+ else {
+ /* not a cycle, and last of chain */
+ eleft = v->elast;
+ eleft->offset_l = (float)val;
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ EIG_linear_solver_delete(solver);
+}
+
+/* Adjust the offsets to try to make them, as much as possible,
+ * have even-width bevels with offsets that match their specs.
+ * The problem that we can try to amelieroate is that when loop slide
+ * is active, the meet point will probably not be the one that makes
+ * both sides have their specified width. And because both ends may be
+ * on loop slide edges, the widths at each end could be different.
*
- * Note that this might not process all BevVerts, only the ones
- * that need adjustment.
+ * It turns out that the dependent offsets either form chains or
+ * cycles, and we can process each of those separatey.
*/
static void adjust_offsets(BevelParams *bp)
{
- BevVert *bv, *searchbv, *bvother;
- int i, searchi;
+ BevVert *bv, *bvcur;
+ BoundVert *v, *vanchor, *vchainstart, *vnext;
+ EdgeHalf *enext;
GHashIterator giter;
- EdgeHalf *e, *efirst, *eother;
- GSQueue *q;
- float max_rel_adj;
+ bool iscycle;
- BLI_assert(!bp->vertex_only);
+ /* find and process chains and cycles of unvisited BoundVerts that have eon set */
GHASH_ITER(giter, bp->vert_hash) {
- bv = BLI_ghashIterator_getValue(&giter);
- bv->visited = false;
- }
+ bv = bvcur = BLI_ghashIterator_getValue(&giter);
+ vanchor = bv->vmesh->boundstart;
+ do {
+ if (vanchor->visited || !vanchor->eon)
+ continue;
- q = BLI_gsqueue_new(sizeof(BevVert *));
- /* the following loop terminates because at least one node is visited each time */
- for (;;) {
- /* look for root of a connected component in search graph */
- searchbv = NULL;
- searchi = -1;
- GHASH_ITER(giter, bp->vert_hash) {
- bv = BLI_ghashIterator_getValue(&giter);
- if (!bv->visited && max_edge_half_offset_rel_change(bv) > 0.0f) {
- i = BM_elem_index_get(bv->v);
- if (!searchbv || i < searchi) {
- searchbv = bv;
- searchi = i;
+ /* Find one of (1) a cycle that starts and ends at v
+ * where each v has v->eon set and had not been visited before;
+ * or (2) a chain of v's where the start and end of the chain do not have
+ * v->eon set but all else do.
+ * It is OK for the first and last elements to
+ * have been visited before, but not any of the inner ones.
+ * We chain the v's together through v->adjchain, and are following
+ * them in left->right direction, meaning that the left side of one edge
+ * pairs with the right side of the next edge in the cycle or chain. */
+
+ /* first follow paired edges in left->right direction */
+ v = vchainstart = vanchor;
+ iscycle = false;
+ while(v->eon && !v->visited && !iscycle) {
+ enext = find_other_end_edge_half(bp, v->efirst, &bvcur);
+ BLI_assert(enext != NULL);
+ vnext = enext->leftv;
+ v->adjchain = vnext;
+ v->visited = true;
+ if (vnext->visited) {
+ if (vnext != vchainstart) {
+ printf("WHOOPS, adjusting offsets, expected cycle!\n");
+ break;
+ }
+ adjust_the_cycle_or_chain(vchainstart, true);
+ iscycle = true;
}
+ v = vnext;
}
- }
- if (searchbv == NULL)
- break;
-
- BLI_gsqueue_push(q, &searchbv);
- while (!BLI_gsqueue_is_empty(q)) {
- BLI_gsqueue_pop(q, &bv);
- /* If do this check, don't have to check for already-on-queue before push, below */
- if (bv->visited)
- continue;
- bv->visited = true;
- build_boundary(bp, bv, false);
-
- e = efirst = &bv->edges[0];
- do {
- eother = find_other_end_edge_half(bp, e, &bvother);
- if (eother && !bvother->visited && edge_half_offset_changed(e)) {
- BLI_gsqueue_push(q, &bvother);
- }
- } while ((e = e->next) != efirst);
- }
+ if (!iscycle) {
+ /* right->left direction, changing vchainstart at each step */
+ v = vchainstart;
+ bvcur = bv;
+ do {
+ enext = find_other_end_edge_half(bp, v->elast, &bvcur);
+ BLI_assert(enext != NULL);
+ vnext = enext->rightv;
+ vnext->adjchain = v;
+ vchainstart = vnext;
+ v->visited = true;
+ v = vnext;
+ } while(!v->visited && v->eon);
+ adjust_the_cycle_or_chain(vchainstart, false);
+ }
+ } while ((vanchor = vanchor->next) != bv->vmesh->boundstart);
}
- BLI_gsqueue_free(q);
- /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments,
- * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not
- * obvious to users, who almost certainaly want clamping in this situation.
- * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression
- * suite, where relative adjust maximum is about .6). */
- if (!bp->limit_offset) {
- max_rel_adj = 0.0f;
- GHASH_ITER(giter, bp->vert_hash) {
- bv = BLI_ghashIterator_getValue(&giter);
- max_rel_adj = max_ff(max_rel_adj, max_edge_half_offset_rel_change(bv));
- }
- if (max_rel_adj > BEVEL_MAX_AUTO_ADJUST_PCT / 100.0f) {
- bp->limit_offset = true;
- adjust_offsets(bp);
- bp->limit_offset = false;
- }
+ /* Rebuild boundaries with new width specs */
+ GHASH_ITER(giter, bp->vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ build_boundary(bp, bv, false);
}
}
@@ -3194,7 +3345,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
/* If we make a poly out of verts around bv, snapping to rep frep, will uv poly have zero area?
* The uv poly is made by snapping all outside-of-frep vertices to the closest edge in frep.
- * Assume that this funciton is called when the only inside-of-frep vertex is vm->boundstart.
+ * Assume that this function is called when the only inside-of-frep vertex is vm->boundstart.
* The poly will have zero area if the distance of that first vertex to some edge e is zero, and all
* the other vertices snap to e or snap to an edge at a point that is essentially on e too. */
static bool is_bad_uv_poly(BevVert *bv, BMFace *frep)
@@ -4929,7 +5080,7 @@ static void bevel_limit_offset(BevelParams *bp)
* so we can just multiply them all by the reduction factor
* of the offset to have the effect of recalculating the specs
* with the new limited_offset.
- */
+ */
offset_factor = limited_offset / bp->offset;
GHASH_ITER(giter, bp->vert_hash) {
bv = BLI_ghashIterator_getValue(&giter);
@@ -4979,6 +5130,7 @@ void BM_mesh_bevel(
bp.use_weights = use_weights;
bp.loop_slide = loop_slide;
bp.limit_offset = limit_offset;
+ bp.offset_adjust = true;
bp.dvert = dvert;
bp.vertex_group = vertex_group;
bp.mat_nr = mat;
@@ -5015,7 +5167,7 @@ void BM_mesh_bevel(
}
/* Perhaps do a pass to try to even out widths */
- if (!bp.vertex_only) {
+ if (!bp.vertex_only && bp.offset_adjust) {
adjust_offsets(&bp);
}
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 5e6fe84d3a9..65acce41046 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -816,10 +816,11 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a
float rot[4], loc[3], scale[3];
mat4_to_quat(rot, mat);
- /*for ( int i = 0 ; i < 4 ; i ++ )
- {
- rot[i] = RAD2DEGF(rot[i]);
- }*/
+#if 0
+ for (int i = 0 ; i < 4; i++) {
+ rot[i] = RAD2DEGF(rot[i]);
+ }
+#endif
copy_v3_v3(loc, mat[3]);
mat4_to_size(scale, mat);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 9c8b8fc25d6..8832e0fd577 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -55,9 +55,10 @@ static const char *bc_get_joint_name(T *node)
}
-ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) :
+ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings) :
TransformReader(conv),
scene(sce),
+ view_layer(view_layer),
unit_converter(conv),
import_settings(import_settings),
empty(NULL),
@@ -411,7 +412,7 @@ Object *ArmatureImporter::get_empty_for_leaves()
{
if (empty) return empty;
- empty = bc_add_object(scene, OB_EMPTY, NULL);
+ empty = bc_add_object(scene, view_layer, OB_EMPTY, NULL);
empty->empty_drawtype = OB_EMPTY_SPHERE;
return empty;
@@ -586,7 +587,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
ob_arm = skin.set_armature(shared);
}
else {
- ob_arm = skin.create_armature(scene); //once for every armature
+ ob_arm = skin.create_armature(scene, view_layer); //once for every armature
}
// enter armature edit mode
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index 17173f157e5..f260bb2307c 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -63,6 +63,7 @@ class ArmatureImporter : private TransformReader
{
private:
Scene *scene;
+ ViewLayer *view_layer;
UnitConverter *unit_converter;
const ImportSettings *import_settings;
@@ -137,7 +138,7 @@ private:
TagsMap uid_tags_map;
public:
- ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings);
+ ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings);
~ArmatureImporter();
void add_root_joint(COLLADAFW::Node *node, Object *parent);
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index d3e23f740c8..dfd662aa66c 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -108,8 +108,9 @@ DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_set
import_settings(import_settings),
mImportStage(General),
mContext(C),
- armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), import_settings),
- mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)),
+ view_layer(CTX_data_view_layer(mContext)),
+ armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), view_layer, import_settings),
+ mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C), view_layer),
anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C))
{
}
@@ -134,7 +135,7 @@ bool DocumentImporter::import()
loader.registerExtraDataCallbackHandler(ehandler);
// deselect all to select new objects
- BKE_view_layer_base_deselect_all(CTX_data_view_layer(mContext));
+ BKE_view_layer_base_deselect_all(view_layer);
std::string mFilename = std::string(this->import_settings->filepath);
const std::string encodedFilename = bc_url_encode(mFilename);
@@ -380,7 +381,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera
return NULL;
}
- Object *ob = bc_add_object(sce, OB_CAMERA, NULL);
+ Object *ob = bc_add_object(sce, view_layer, OB_CAMERA, NULL);
Camera *cam = uid_camera_map[cam_uid];
Camera *old_cam = (Camera *)ob->data;
ob->data = cam;
@@ -396,7 +397,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
return NULL;
}
- Object *ob = bc_add_object(sce, OB_LAMP, NULL);
+ Object *ob = bc_add_object(sce, view_layer, OB_LAMP, NULL);
Lamp *la = uid_lamp_map[lamp_uid];
Lamp *old_lamp = (Lamp *)ob->data;
ob->data = la;
@@ -512,7 +513,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
if (parent_node == NULL && !is_library_node) {
// A Joint on root level is a skeleton without root node.
// Here we add the armature "on the fly":
- par = bc_add_object(sce, OB_ARMATURE, std::string("Armature").c_str());
+ par = bc_add_object(sce, view_layer, OB_ARMATURE, std::string("Armature").c_str());
objects_done->push_back(par);
root_objects->push_back(par);
object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par));
@@ -626,10 +627,10 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) {
//Check if Object is armature, by checking if immediate child is a JOINT node.
if (is_armature(node)) {
- ob = bc_add_object(sce, OB_ARMATURE, name.c_str());
+ ob = bc_add_object(sce, view_layer, OB_ARMATURE, name.c_str());
}
else {
- ob = bc_add_object(sce, OB_EMPTY, NULL);
+ ob = bc_add_object(sce, view_layer, OB_EMPTY, NULL);
}
objects_done->push_back(ob);
if (parent_node == NULL) {
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 62f76dbc022..fd61f3a68da 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -144,6 +144,7 @@ private:
ImportStage mImportStage;
bContext *mContext;
+ ViewLayer *view_layer;
UnitConverter unit_converter;
ArmatureImporter armature_importer;
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 87392352a48..5e7f92047d3 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -67,7 +67,7 @@ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettin
bool EffectsExporter::hasEffects(Scene *sce)
{
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT(sce, ob)
{
int a;
for (a = 0; a < ob->totcol; a++) {
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 587f30b6eb8..8dbee607b01 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -421,7 +421,6 @@ void GeometryExporter::createPolylist(short material_index,
polylist.finish();
}
-
// creates <source> for positions
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 9c95d4de695..f8cd487c355 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -207,7 +207,11 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
}
-MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
+MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer):
+ unitconverter(unitconv),
+ scene(sce),
+ view_layer(view_layer),
+ armature_importer(arm) {
}
bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
@@ -1141,7 +1145,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
const char *name = (id.length()) ? id.c_str() : NULL;
// add object
- Object *ob = bc_add_object(scene, OB_MESH, name);
+ Object *ob = bc_add_object(scene, view_layer, OB_MESH, name);
bc_set_mark(ob); // used later for material assignement optimization
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index e8ae934a393..f57f57e07a7 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -92,6 +92,8 @@ private:
UnitConverter *unitconverter;
Scene *scene;
+ ViewLayer *view_layer;
+
ArmatureImporter *armature_importer;
std::map<std::string, std::string> mesh_geom_map; // needed for correct shape key naming
@@ -159,7 +161,7 @@ private:
public:
- MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce);
+ MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer);
virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index c29f1748efc..a2cb8237d08 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -159,9 +159,9 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co)
}
// called from write_controller
-Object *SkinInfo::create_armature(Scene *scene)
+Object *SkinInfo::create_armature(Scene *scene, ViewLayer *view_layer)
{
- ob_arm = bc_add_object(scene, OB_ARMATURE, NULL);
+ ob_arm = bc_add_object(scene, view_layer, OB_ARMATURE, NULL);
return ob_arm;
}
diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h
index e074f59cffc..a399bff9e3c 100644
--- a/source/blender/collada/SkinInfo.h
+++ b/source/blender/collada/SkinInfo.h
@@ -99,7 +99,7 @@ public:
void set_controller(const COLLADAFW::SkinController* co);
// called from write_controller
- Object *create_armature(Scene *scene);
+ Object *create_armature(Scene *scene, ViewLayer *view_layer);
Object* set_armature(Object *ob_arm);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index 6a52027fb47..f351ebf7952 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -135,7 +135,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
return true;
}
-Object *bc_add_object(Scene *scene, int type, const char *name)
+Object *bc_add_object(Scene *scene, ViewLayer *view_layer, int type, const char *name)
{
Object *ob = BKE_object_add_only_object(G.main, type, name);
@@ -143,9 +143,6 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
ob->lay = scene->lay;
DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- /* XXX Collada should use the context scene layer, not the scene one. (dfelinto/gaia). */
- ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene);
-
LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer);
BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob);
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 75e9fb5dcea..5d6e836b9c3 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -67,7 +67,7 @@ typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex *> > TexIndexTextureA
extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index);
extern int bc_test_parent_loop(Object *par, Object *ob);
extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true);
-extern Object *bc_add_object(Scene *scene, int type, const char *name);
+extern Object *bc_add_object(Scene *scene, ViewLayer *view_layer, int type, const char *name);
extern Mesh *bc_get_mesh_copy(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate);
extern Object *bc_get_assigned_armature(Object *ob);
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index 99365cdd4a8..d3b11accd96 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -64,7 +64,7 @@ typedef enum ChunkExecutionState {
*/
class ExecutionGroup {
public:
- typedef std::vector<NodeOperation*> Operations;
+ typedef std::vector<NodeOperation*> Operations;
private:
// fields
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
index 382296a7f3a..de6ad3df030 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
@@ -37,14 +37,11 @@ void LuminanceMatteNode::convertToOperations(NodeConverter &converter, const Com
NodeOutput *outputSocketImage = this->getOutputSocket(0);
NodeOutput *outputSocketMatte = this->getOutputSocket(1);
- ConvertRGBToYUVOperation *rgbToYUV = new ConvertRGBToYUVOperation();
LuminanceMatteOperation *operationSet = new LuminanceMatteOperation();
operationSet->setSettings((NodeChroma *)editorsnode->storage);
- converter.addOperation(rgbToYUV);
converter.addOperation(operationSet);
- converter.mapInputSocket(inputSocket, rgbToYUV->getInputSocket(0));
- converter.addLink(rgbToYUV->getOutputSocket(), operationSet->getInputSocket(0));
+ converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0));
converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0));
SetAlphaOperation *operation = new SetAlphaOperation();
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cpp
index 84d36034ec6..c67f906b374 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.cpp
@@ -25,7 +25,7 @@
#ifdef __cplusplus
extern "C" {
#endif
-# include "BKE_texture.h"
+# include "BKE_colorband.h"
#ifdef __cplusplus
}
#endif
@@ -48,7 +48,7 @@ void ColorRampOperation::executePixelSampled(float output[4], float x, float y,
float values[4];
this->m_inputProgram->readSampled(values, x, y, sampler);
- do_colorband(this->m_colorBand, values[0], output);
+ BKE_colorband_evaluate(this->m_colorBand, values[0], output);
}
void ColorRampOperation::deinitExecution()
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
index 3be5447db3b..1401ab56fbd 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
@@ -22,6 +22,10 @@
#include "COM_LuminanceMatteOperation.h"
#include "BLI_math.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
LuminanceMatteOperation::LuminanceMatteOperation() : NodeOperation()
{
addInputSocket(COM_DT_COLOR);
@@ -43,41 +47,34 @@ void LuminanceMatteOperation::deinitExecution()
void LuminanceMatteOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inColor[4];
+ this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
const float high = this->m_settings->t1;
const float low = this->m_settings->t2;
+ const float luminance = IMB_colormanagement_get_luminance(inColor);
float alpha;
-
- this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
/* one line thread-friend algorithm:
- * output[0] = max(inputValue[3], min(high, max(low, ((inColor[0] - low) / (high - low))));
+ * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low))));
*/
/* test range */
- if (inColor[0] > high) {
+ if (luminance > high) {
alpha = 1.0f;
}
- else if (inColor[0] < low) {
+ else if (luminance < low) {
alpha = 0.0f;
}
else { /*blend */
- alpha = (inColor[0] - low) / (high - low);
+ alpha = (luminance - low) / (high - low);
}
-
/* store matte(alpha) value in [0] to go with
* COM_SetAlphaOperation and the Value output
*/
/* don't make something that was more transparent less transparent */
- if (alpha < inColor[3]) {
- output[0] = alpha;
- }
- else {
- /* leave now it was before */
- output[0] = inColor[3];
- }
+ output[0] = min_ff(alpha, inColor[3]);
}
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 0c2da8415f8..5d682352d46 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -35,6 +35,9 @@ MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation()
void MovieClipAttributeOperation::initExecution()
{
+ if (this->m_clip == NULL) {
+ return;
+ }
float loc[2], scale, angle;
loc[0] = 0.0f;
loc[1] = 0.0f;
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 9495321a0ff..c42d06bd0a2 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -53,13 +53,17 @@ set(SRC
intern/builder/deg_builder_relations_rig.cc
intern/builder/deg_builder_relations_view_layer.cc
intern/builder/deg_builder_transitive.cc
- intern/debug/deg_debug_graphviz.cc
+ intern/debug/deg_debug_relations_graphviz.cc
+ intern/debug/deg_debug_stats_gnuplot.cc
intern/eval/deg_eval.cc
intern/eval/deg_eval_copy_on_write.cc
intern/eval/deg_eval_flush.cc
+ intern/eval/deg_eval_stats.cc
intern/nodes/deg_node.cc
intern/nodes/deg_node_component.cc
+ intern/nodes/deg_node_id.cc
intern/nodes/deg_node_operation.cc
+ intern/nodes/deg_node_time.cc
intern/depsgraph.cc
intern/depsgraph_build.cc
intern/depsgraph_debug.cc
@@ -85,9 +89,12 @@ set(SRC
intern/eval/deg_eval.h
intern/eval/deg_eval_copy_on_write.h
intern/eval/deg_eval_flush.h
+ intern/eval/deg_eval_stats.h
intern/nodes/deg_node.h
intern/nodes/deg_node_component.h
+ intern/nodes/deg_node_id.h
intern/nodes/deg_node_operation.h
+ intern/nodes/deg_node_time.h
intern/depsgraph.h
intern/depsgraph_intern.h
intern/depsgraph_types.h
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 6bcbff4950b..4d3f36b5fba 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -140,37 +140,35 @@ void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph);
void DEG_on_visible_update(struct Main *bmain, const bool do_time);
/* Tag given ID for an update in all the dependency graphs. */
-enum {
+typedef enum eDepsgraph_Tag {
/* Object transformation changed, corresponds to OB_RECALC_OB. */
DEG_TAG_TRANSFORM = (1 << 0),
-
- /* Object geoemtry changed, corresponds to OB_RECALC_DATA. */
+ /* Object geometry changed, corresponds to OB_RECALC_DATA. */
DEG_TAG_GEOMETRY = (1 << 1),
-
/* Time changed and animation is to be re-evaluated, OB_RECALC_TIME. */
DEG_TAG_TIME = (1 << 2),
-
/* Particle system changed. */
- DEG_TAG_PSYSC_REDO = (1 << 3),
+ DEG_TAG_PSYS_REDO = (1 << 3),
DEG_TAG_PSYS_RESET = (1 << 4),
DEG_TAG_PSYS_TYPE = (1 << 5),
DEG_TAG_PSYS_CHILD = (1 << 6),
DEG_TAG_PSYS_PHYS = (1 << 7),
- DEG_TAG_PSYS = ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)),
-
+ DEG_TAG_PSYS_ALL = (DEG_TAG_PSYS_REDO |
+ DEG_TAG_PSYS_RESET |
+ DEG_TAG_PSYS_TYPE |
+ DEG_TAG_PSYS_CHILD |
+ DEG_TAG_PSYS_PHYS),
/* Update copy on write component without flushing down the road. */
DEG_TAG_COPY_ON_WRITE = (1 << 8),
-
/* Tag shading components for update.
* Only parameters of material changed).
*/
DEG_TAG_SHADING_UPDATE = (1 << 9),
DEG_TAG_SELECT_UPDATE = (1 << 10),
DEG_TAG_BASE_FLAGS_UPDATE = (1 << 11),
-
/* Only inform editors about the change. Don't modify datablock itself. */
DEG_TAG_EDITORS_UPDATE = (1 << 12),
-};
+} eDepsgraph_Tag;
void DEG_id_tag_update(struct ID *id, int flag);
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag);
@@ -196,6 +194,7 @@ void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph);
* editors about this.
*/
void DEG_ids_check_recalc(struct Main *bmain,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct ViewLayer *view_layer,
bool time);
@@ -250,6 +249,7 @@ bool DEG_needs_eval(Depsgraph *graph);
typedef struct DEGEditorUpdateContext {
struct Main *bmain;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct ViewLayer *view_layer;
} DEGEditorUpdateContext;
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index bd03874436b..363749dab26 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -53,7 +53,14 @@ void DEG_stats_simple(const struct Depsgraph *graph,
/* ************************************************ */
/* Diagram-Based Graph Debugging */
-void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval);
+void DEG_debug_relations_graphviz(const struct Depsgraph *graph,
+ FILE *stream,
+ const char *label);
+
+void DEG_debug_stats_gnuplot(const struct Depsgraph *graph,
+ FILE *stream,
+ const char *label,
+ const char *output_filename);
/* ************************************************ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 7771d35d581..adfda27117e 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -53,35 +53,44 @@ extern "C" {
bool DEG_id_type_tagged(struct Main *bmain, short id_type);
/* Get additional evaluation flags for the given ID. */
-short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
+short DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id);
/* Get scene the despgraph is created for. */
-struct Scene *DEG_get_evaluated_scene(struct Depsgraph *graph);
+struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
/* Get scene layer the despgraph is created for. */
-struct ViewLayer *DEG_get_evaluated_view_layer(struct Depsgraph *graph);
+struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);
/* Get evaluated version of object for given original one. */
-struct Object *DEG_get_evaluated_object(struct Depsgraph *depsgraph, struct Object *object);
+struct Object *DEG_get_evaluated_object(const struct Depsgraph *depsgraph,
+ struct Object *object);
/* Get evaluated version of given ID datablock. */
-struct ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, struct ID *id);
+struct ID *DEG_get_evaluated_id(const struct Depsgraph *depsgraph,
+ struct ID *id);
/* ************************ DEG iterators ********************* */
enum {
- DEG_ITER_OBJECT_FLAG_SET = (1 << 0),
- DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 1),
-
- DEG_ITER_OBJECT_FLAG_ALL = (DEG_ITER_OBJECT_FLAG_SET | DEG_ITER_OBJECT_FLAG_DUPLI),
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY = (1 << 0),
+ DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY = (1 << 1),
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET = (1 << 2),
+ DEG_ITER_OBJECT_FLAG_VISIBLE = (1 << 3),
+ DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4),
};
-typedef struct DEGOIterObjectData {
+typedef enum eDepsObjectIteratorMode {
+ DEG_ITER_OBJECT_MODE_VIEWPORT = 0,
+ DEG_ITER_OBJECT_MODE_RENDER = 1,
+} eDepsObjectIteratorMode;
+
+typedef struct DEGObjectIterData {
struct Depsgraph *graph;
struct Scene *scene;
struct EvaluationContext eval_ctx;
int flag;
+ eDepsObjectIteratorMode mode;
/* **** Iteration over dupli-list. *** */
@@ -103,16 +112,22 @@ typedef struct DEGOIterObjectData {
/* **** Iteration ober ID nodes **** */
size_t id_node_index;
size_t num_id_nodes;
-} DEGOIterObjectData;
+} DEGObjectIterData;
-void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGOIterObjectData *data);
+void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGObjectIterData *data);
void DEG_iterator_objects_next(struct BLI_Iterator *iter);
void DEG_iterator_objects_end(struct BLI_Iterator *iter);
-#define DEG_OBJECT_ITER(graph_, instance_, flag_) \
+/**
+ * Note: Be careful with DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY objects.
+ * Although they are available they have no overrides (collection_properties)
+ * and will crash if you try to access it.
+ */
+#define DEG_OBJECT_ITER(graph_, instance_, mode_, flag_) \
{ \
- DEGOIterObjectData data_ = { \
+ DEGObjectIterData data_ = { \
.graph = (graph_), \
+ .mode = (mode_), \
.flag = (flag_), \
}; \
\
@@ -125,6 +140,19 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
ITER_END \
}
+/**
+ * Depsgraph objects iterator for draw manager and final render
+ */
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph_, instance_, mode_) \
+ DEG_OBJECT_ITER(graph_, instance_, mode_, \
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \
+ DEG_ITER_OBJECT_FLAG_VISIBLE | \
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END \
+ DEG_OBJECT_ITER_END
+
/* ************************ DEG traversal ********************* */
typedef void (*DEGForeachIDCallback)(ID *id, void *user_data);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 20a93673350..2fcad233044 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -36,6 +36,7 @@
#include "intern/depsgraph.h"
#include "intern/depsgraph_types.h"
#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_id.h"
#include "util/deg_util_foreach.h"
@@ -52,7 +53,7 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
foreach (IDDepsNode *id_node, graph->id_nodes) {
ID *id = id_node->id_orig;
id_node->finalize_build(graph);
- if ((id->tag & LIB_TAG_ID_RECALC_ALL)) {
+ if ((id->recalc & ID_RECALC_ALL)) {
id_node->tag_update(graph);
}
/* TODO(sergey): This is not ideal at all, since this forces
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 3eed0697b5e..e30b9b44490 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -46,17 +46,38 @@
namespace DEG {
-void deg_graph_detect_cycles(Depsgraph *graph)
+typedef enum eCyclicCheckVisitedState {
+ /* Not is not visited at all during traversal. */
+ NODE_NOT_VISITED = 0,
+ /* Node has been visited during traversal and not in current stack. */
+ NODE_VISITED = 1,
+ /* Node has been visited during traversal and is in current stack. */
+ NODE_IN_STACK = 2,
+} eCyclicCheckVisitedState;
+
+BLI_INLINE void set_node_visited_state(DepsNode *node,
+ eCyclicCheckVisitedState state)
{
- enum {
- /* Not is not visited at all during traversal. */
- NODE_NOT_VISITED = 0,
- /* Node has been visited during traversal and not in current stack. */
- NODE_VISITED = 1,
- /* Node has been visited during traversal and is in current stack. */
- NODE_IN_STACK = 2,
- };
+ node->done = (node->done & ~0x3) | (int)state;
+}
+
+BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(DepsNode *node)
+{
+ return (eCyclicCheckVisitedState)(node->done & 0x3);
+}
+
+BLI_INLINE void set_node_num_visited_children(DepsNode *node, int num_children)
+{
+ node->done = (node->done & 0x3) | (num_children << 2);
+}
+
+BLI_INLINE int get_node_num_visited_children(DepsNode *node)
+{
+ return node->done >> 2;
+}
+void deg_graph_detect_cycles(Depsgraph *graph)
+{
struct StackEntry {
OperationDepsNode *node;
StackEntry *from;
@@ -73,29 +94,31 @@ void deg_graph_detect_cycles(Depsgraph *graph)
has_inlinks = true;
}
}
+ node->done = 0;
if (has_inlinks == false) {
StackEntry entry;
entry.node = node;
entry.from = NULL;
entry.via_relation = NULL;
BLI_stack_push(traversal_stack, &entry);
- node->tag = NODE_IN_STACK;
+ set_node_visited_state(node, NODE_IN_STACK);
}
else {
- node->tag = NODE_NOT_VISITED;
+ set_node_visited_state(node, NODE_NOT_VISITED);
}
- node->done = 0;
}
while (!BLI_stack_is_empty(traversal_stack)) {
StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
OperationDepsNode *node = entry->node;
bool all_child_traversed = true;
- for (int i = node->done; i < node->outlinks.size(); ++i) {
+ const int num_visited = get_node_num_visited_children(node);
+ for (int i = num_visited; i < node->outlinks.size(); ++i) {
DepsRelation *rel = node->outlinks[i];
if (rel->to->type == DEG_NODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
- if (to->tag == NODE_IN_STACK) {
+ eCyclicCheckVisitedState to_state = get_node_visited_state(to);
+ if (to_state == NODE_IN_STACK) {
printf("Dependency cycle detected:\n");
printf(" '%s' depends on '%s' through '%s'\n",
to->full_identifier().c_str(),
@@ -114,21 +137,21 @@ void deg_graph_detect_cycles(Depsgraph *graph)
/* TODO(sergey): So called russian roulette cycle solver. */
rel->flag |= DEPSREL_FLAG_CYCLIC;
}
- else if (to->tag == NODE_NOT_VISITED) {
+ else if (to_state == NODE_NOT_VISITED) {
StackEntry new_entry;
new_entry.node = to;
new_entry.from = entry;
new_entry.via_relation = rel;
BLI_stack_push(traversal_stack, &new_entry);
- to->tag = NODE_IN_STACK;
+ set_node_visited_state(node, NODE_IN_STACK);
all_child_traversed = false;
- node->done = i;
+ set_node_num_visited_children(node, i);
break;
}
}
}
if (all_child_traversed) {
- node->tag = NODE_VISITED;
+ set_node_visited_state(node, NODE_VISITED);
BLI_stack_discard(traversal_stack);
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 8fbd1e7a46d..ddae761cea0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -92,7 +92,6 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
#include "BKE_sound.h"
-#include "BKE_texture.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
@@ -107,9 +106,11 @@ extern "C" {
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_types.h"
#include "intern/depsgraph_intern.h"
+
#include "util/deg_util_foreach.h"
namespace DEG {
@@ -427,12 +428,24 @@ void DepsgraphNodeBuilder::build_group(Group *group)
return;
}
group_id->tag |= LIB_TAG_DOIT;
-
- LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) {
+ /* Build group objects. */
+ BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY);
}
-
- build_view_layer_collections(&group->id, group->view_layer);
+ /* Operation to evaluate the whole view layer.
+ *
+ * NOTE: We re-use DONE opcode even though the function does everything.
+ * This way we wouldn't need to worry about possible relations from DONE,
+ * regardless whether it's a group or scene or something else.
+ */
+ add_id_node(group_id);
+ Group *group_cow = get_cow_datablock(group);
+ add_operation_node(group_id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ function_bind(BKE_group_eval_view_layers,
+ _1,
+ group_cow),
+ DEG_OPCODE_VIEW_LAYER_DONE);
}
void DepsgraphNodeBuilder::build_object(Base *base,
@@ -686,7 +699,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
}
/* drivers */
- LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
+ BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
/* create driver */
build_driver(id, fcu);
}
@@ -804,7 +817,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
- LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
Object *object = base->object;
if (!object || (object->type != OB_MESH))
@@ -857,7 +870,7 @@ void DepsgraphNodeBuilder::build_particles(Object *object)
DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT);
/* particle systems */
- LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+ BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
ParticleSettings *part = psys->part;
/* Build particle settings operations.
@@ -972,8 +985,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
// TODO: "Done" operation
- /* Cloyth modifier. */
- LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) {
+ /* Cloth modifier. */
+ BLI_LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Cloth) {
build_cloth(object);
}
@@ -1218,7 +1231,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
ntree),
DEG_OPCODE_MATERIAL_UPDATE);
/* nodetree's nodes... */
- LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
+ BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
if (id == NULL) {
continue;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index c9bdd194227..cc8ad08ea3b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -102,7 +102,7 @@ struct DepsgraphNodeBuilder {
template<typename T>
T *get_orig_datablock(const T *cow) const {
if (DEG_depsgraph_use_copy_on_write()) {
- return (T *)cow->id.newid;
+ return (T *)cow->id.orig_id;
}
else {
return (T *)cow;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
index 79316e47022..137a79e7276 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
@@ -94,7 +94,7 @@ void DepsgraphNodeBuilder::build_layer_collections(ID *owner_id,
ListBase *layer_collections,
LayerCollectionState *state)
{
- LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
+ BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) {
build_layer_collection(owner_id, layer_collection, state);
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 531ea55cf5c..2fc42efa440 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -247,7 +247,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
op_node->set_as_exit();
/* bones */
- LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
+ BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
/* Node for bone evaluation. */
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
DEG_OPCODE_BONE_LOCAL);
@@ -293,7 +293,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
* as in ik-tree building
* - Animated chain-lengths are a problem.
*/
- LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
+ BLI_LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
build_ik_pose(object, pchan, con);
@@ -347,7 +347,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
object_cow),
DEG_OPCODE_POSE_INIT);
op_node->set_as_entry();
- LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
+ BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
/* Local bone transform. */
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_BONE,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index 49772c4f852..4ca19f4e14f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -84,7 +84,7 @@ void DepsgraphNodeBuilder::build_view_layer(
* otherwise remapping will not replace objects with their CoW versions
* for CoW bases.
*/
- LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *object = base->object;
add_id_node(&object->id, false);
}
@@ -145,15 +145,15 @@ void DepsgraphNodeBuilder::build_view_layer(
build_gpencil(scene->gpd);
}
/* Cache file. */
- LINKLIST_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
+ BLI_LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
build_cachefile(cachefile);
}
/* Masks. */
- LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) {
+ BLI_LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) {
build_mask(mask);
}
/* Movie clips. */
- LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
+ BLI_LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
build_movieclip(clip);
}
/* Collections. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 14dedef2601..cfb73ecc2ad 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -89,7 +89,6 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
#include "BKE_sound.h"
-#include "BKE_texture.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
@@ -105,7 +104,9 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
+#include "intern/nodes/deg_node_time.h"
#include "intern/depsgraph_intern.h"
#include "intern/depsgraph_types.h"
@@ -193,7 +194,7 @@ static bool particle_system_depends_on_time(ParticleSystem *psys)
static bool object_particles_depends_on_time(Object *object)
{
- LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+ BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
if (particle_system_depends_on_time(psys)) {
return true;
}
@@ -346,7 +347,7 @@ void DepsgraphRelationBuilder::add_forcefield_relations(
{
ListBase *effectors = pdInitEffectors(NULL, scene, object, psys, eff, false);
if (effectors != NULL) {
- LINKLIST_FOREACH(EffectorCache *, eff, effectors) {
+ BLI_LISTBASE_FOREACH (EffectorCache *, eff, effectors) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(eff_key, key, name);
@@ -427,15 +428,13 @@ void DepsgraphRelationBuilder::build_group(Object *object, Group *group)
DEG_OPCODE_TRANSFORM_LOCAL);
if (!group_done) {
- LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
build_object(NULL, base->object);
}
-
- build_view_layer_collections(&group->id, group->view_layer);
group_id->tag |= LIB_TAG_DOIT;
}
- LINKLIST_FOREACH (Base *, base, &group->view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
}
@@ -777,7 +776,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
else if (cti->get_constraint_targets) {
ListBase targets = {NULL, NULL};
cti->get_constraint_targets(con, &targets);
- LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) {
+ BLI_LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == NULL) {
continue;
}
@@ -924,7 +923,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
/* Animation curves and NLA. */
build_animdata_curves(id);
/* Drivers. */
- build_animdata_drievrs(id);
+ build_animdata_drivers(id);
}
void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
@@ -962,7 +961,7 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id)
/* Iterate over all curves and build relations. */
PointerRNA id_ptr;
RNA_id_pointer_create(id, &id_ptr);
- LINKLIST_FOREACH(FCurve *, fcu, &adt->action->curves) {
+ BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
PointerRNA ptr;
PropertyRNA *prop;
int index;
@@ -990,17 +989,29 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id)
graph_->add_new_relation(operation_from, operation_to,
"Animation -> Prop",
true);
+ /* It is possible that animation is writing to a nested ID datablock,
+ * need to make sure animation is evaluated after target ID is copied.
+ */
+ if (DEG_depsgraph_use_copy_on_write()) {
+ const IDDepsNode *id_node_from = operation_from->owner->owner;
+ const IDDepsNode *id_node_to = operation_to->owner->owner;
+ if (id_node_from != id_node_to) {
+ ComponentKey cow_key(id_node_to->id_orig,
+ DEG_NODE_TYPE_COPY_ON_WRITE);
+ add_relation(cow_key, adt_key, "Target CoW -> Animation", true);
+ }
+ }
}
}
-void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id)
+void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt == NULL) {
return;
}
ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
- LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
+ BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
OperationKey driver_key(id,
DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
@@ -1009,7 +1020,6 @@ void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id)
/* create the driver's relations to targets */
build_driver(id, fcu);
-
/* Special case for array drivers: we can not multithread them because
* of the way how they work internally: animation system will write the
* whole array back to RNA even when changing individual array value.
@@ -1024,7 +1034,7 @@ void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id)
*/
if (fcu->array_index > 0) {
FCurve *fcu_prev = NULL;
- LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
+ BLI_LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
/* Writing to different RNA paths is */
const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
if (!STREQ(fcu_candidate->rna_path, rna_path)) {
@@ -1140,6 +1150,25 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
else {
RNAPathKey target_key(id, rna_path);
add_relation(driver_key, target_key, "Driver -> Target");
+ /* Similar to the case with f-curves, driver might drive a nested
+ * datablock, which means driver execution should wait for that
+ * datablock to be copied.
+ */
+ if (DEG_depsgraph_use_copy_on_write()) {
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) {
+ if (id_ptr.id.data != ptr.id.data) {
+ ComponentKey cow_key((ID *)ptr.id.data,
+ DEG_NODE_TYPE_COPY_ON_WRITE);
+ add_relation(cow_key,
+ driver_key,
+ "Target CoW -> Driver",
+ true);
+ }
+ }
+ }
}
}
@@ -1154,7 +1183,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
const RNAPathKey self_key(id, rna_path);
- LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
+ BLI_LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
/* Only used targets. */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
@@ -1174,9 +1203,9 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
continue;
}
OperationKey variable_key(dtar->id,
- DEG_NODE_TYPE_BONE,
- target_pchan->name,
- DEG_OPCODE_BONE_DONE);
+ DEG_NODE_TYPE_BONE,
+ target_pchan->name,
+ DEG_OPCODE_BONE_DONE);
if (is_same_bone_dependency(variable_key, self_key)) {
continue;
}
@@ -1201,10 +1230,13 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
if (RNA_pointer_is_null(&variable_key.ptr)) {
continue;
}
- if (is_same_bone_dependency(variable_key, self_key)) {
+ if (is_same_bone_dependency(variable_key, self_key) ||
+ is_same_nodetree_node_dependency(variable_key, self_key) ||
+ is_same_shapekey_dependency(variable_key, self_key))
+ {
continue;
}
- add_relation(variable_key, driver_key, "RNA Bone -> Driver");
+ add_relation(variable_key, driver_key, "RNA Target -> Driver");
}
else {
if (dtar->id == id) {
@@ -1266,7 +1298,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
- LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
Object *object = base->object;
if (object == NULL || object->type != OB_MESH) {
continue;
@@ -1320,7 +1352,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* constraints */
if (rbw->constraints) {
- LINKLIST_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) {
Object *object = base->object;
if (object == NULL || !object->rigidbody_constraint) {
continue;
@@ -1354,12 +1386,9 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
OperationKey eval_init_key(&object->id,
DEG_NODE_TYPE_EVAL_PARTICLES,
DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT);
- if (object_particles_depends_on_time(object)) {
- add_relation(time_src_key, eval_init_key, "TimeSrc -> PSys");
- }
/* particle systems */
- LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+ BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
ParticleSettings *part = psys->part;
/* Build particle settings relations.
@@ -1436,8 +1465,8 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
/* boids */
if (part->boids) {
- LINKLIST_FOREACH (BoidState *, state, &part->boids->states) {
- LINKLIST_FOREACH (BoidRule *, rule, &state->rules) {
+ BLI_LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
+ BLI_LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
Object *ruleob = NULL;
if (rule->type == eBoidRuleType_Avoid)
ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
@@ -1455,6 +1484,13 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
ComponentKey dup_ob_key(&part->dup_ob->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(dup_ob_key, psys_key, "Particle Object Visualization");
+ if (part->dup_ob->type == OB_MBALL) {
+ ComponentKey dup_geometry_key(&part->dup_ob->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(obdata_ubereval_key,
+ dup_geometry_key,
+ "Particle MBall Visualization");
+ }
}
}
@@ -1577,7 +1613,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
/* Modifiers */
if (object->modifiers.first != NULL) {
- LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) {
+ BLI_LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
@@ -1798,7 +1834,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_animdata(ntree_id);
ComponentKey shading_key(ntree_id, DEG_NODE_TYPE_SHADING);
/* nodetree's nodes... */
- LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
+ BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
if (id == NULL) {
continue;
@@ -1919,7 +1955,8 @@ void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
// TODO: parent object (when that feature is implemented)
}
-void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
+void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
+{
/* Animation. */
build_animdata(&cache_file->id);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 9f661b8e825..30b3219f989 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -206,7 +206,7 @@ struct DepsgraphRelationBuilder
void build_animdata(ID *id);
void build_animdata_curves(ID *id);
void build_animdata_curves_targets(ID *id);
- void build_animdata_drievrs(ID *id);
+ void build_animdata_drivers(ID *id);
void build_driver(ID *id, FCurve *fcurve);
void build_driver_data(ID *id, FCurve *fcurve);
void build_driver_variables(ID *id, FCurve *fcurve);
@@ -297,9 +297,31 @@ protected:
DepsNodeHandle create_node_handle(const KeyType& key,
const char *default_name = "");
+ /* TODO(sergey): All those is_same* functions are to be generalized. */
+
+ /* Check whether two keys correponds to the same bone from same armature.
+ *
+ * This is used by drivers relations builder to avoid possible fake
+ * dependency cycle when one bone property drives another property of the
+ * same bone.
+ */
template <typename KeyFrom, typename KeyTo>
bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to);
+ /* Similar to above, but used to check whether driver is using node from
+ * the same node tree as a driver variable.
+ */
+ template <typename KeyFrom, typename KeyTo>
+ bool is_same_nodetree_node_dependency(const KeyFrom& key_from,
+ const KeyTo& key_to);
+
+ /* Similar to above, but used to check whether driver is using key from
+ * the same key datablock as a driver variable.
+ */
+ template <typename KeyFrom, typename KeyTo>
+ bool is_same_shapekey_dependency(const KeyFrom& key_from,
+ const KeyTo& key_to);
+
private:
/* State which never changes, same for the whole builder time. */
Main *bmain_;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index ba55a83b767..485586e844f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -30,6 +30,12 @@
#pragma once
+#include "intern/nodes/deg_node_id.h"
+
+extern "C" {
+#include "DNA_ID.h"
+}
+
namespace DEG {
template <typename KeyType>
@@ -140,9 +146,14 @@ bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from,
if (op_from == NULL || op_to == NULL) {
return false;
}
+ /* Different armatures, bone can't be the same. */
+ if (op_from->owner->owner != op_to->owner->owner) {
+ return false;
+ }
/* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */
if (!(op_from->opcode == DEG_OPCODE_BONE_DONE &&
- op_to->opcode == DEG_OPCODE_BONE_LOCAL)) {
+ op_to->opcode == DEG_OPCODE_BONE_LOCAL))
+ {
return false;
}
/* ... BUT, we also need to check if it's same bone. */
@@ -152,4 +163,64 @@ bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from,
return true;
}
+template <typename KeyFrom, typename KeyTo>
+bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(
+ const KeyFrom& key_from,
+ const KeyTo& key_to)
+{
+ /* Get operations for requested keys. */
+ DepsNode *node_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ if (node_from == NULL || node_to == NULL) {
+ return false;
+ }
+ OperationDepsNode *op_from = node_from->get_exit_operation();
+ OperationDepsNode *op_to = node_to->get_entry_operation();
+ if (op_from == NULL || op_to == NULL) {
+ return false;
+ }
+ /* Check if this is actually a node tree. */
+ if (GS(op_from->owner->owner->id_orig->name) != ID_NT) {
+ return false;
+ }
+ /* Different node trees. */
+ if (op_from->owner->owner != op_to->owner->owner) {
+ return false;
+ }
+ /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */
+ if (!(op_from->opcode == DEG_OPCODE_PARAMETERS_EVAL &&
+ op_to->opcode == DEG_OPCODE_PARAMETERS_EVAL))
+ {
+ return false;
+ }
+ return true;
+}
+
+template <typename KeyFrom, typename KeyTo>
+bool DepsgraphRelationBuilder::is_same_shapekey_dependency(
+ const KeyFrom& key_from,
+ const KeyTo& key_to)
+{
+ /* Get operations for requested keys. */
+ DepsNode *node_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ if (node_from == NULL || node_to == NULL) {
+ return false;
+ }
+ OperationDepsNode *op_from = node_from->get_exit_operation();
+ OperationDepsNode *op_to = node_to->get_entry_operation();
+ if (op_from == NULL || op_to == NULL) {
+ return false;
+ }
+ /* Check if this is actually a shape key datablock. */
+ if (GS(op_from->owner->owner->id_orig->name) != ID_KE) {
+ return false;
+ }
+ /* Different key data blocks. */
+ if (op_from->owner->owner != op_to->owner->owner) {
+ return false;
+ }
+ return true;
+}
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
index 452bd7b19e7..9cf82b5fb47 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
@@ -92,7 +92,7 @@ void DepsgraphRelationBuilder::build_layer_collections(
ListBase *layer_collections,
LayerCollectionState *state)
{
- LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
+ BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) {
/* Recurs into the layer. */
build_layer_collection(owner_id, layer_collection, state);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 2aff1ca33c7..ad812a4b505 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -341,8 +341,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
*/
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
- LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
+ BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ BLI_LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
build_ik_pose(object, pchan, con, &root_map);
@@ -382,7 +382,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
/* links between operations for each bone */
- LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
OperationKey bone_pose_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
OperationKey bone_ready_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
@@ -445,7 +445,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
{
OperationKey pose_init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
OperationKey pose_done_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
OperationKey bone_ready_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
OperationKey bone_done_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
index 29cff0cb28d..cfb98fe2f79 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
@@ -59,6 +59,7 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
@@ -77,7 +78,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
* passed to the evaluation functions. During relations builder we only
* do NULL-pointer check of the base, so it's fine to pass original one.
*/
- LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) {
+ BLI_LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
build_object(base, base->object);
}
if (scene->camera != NULL) {
@@ -104,11 +105,11 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
build_gpencil(scene->gpd);
}
/* Masks. */
- LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) {
+ BLI_LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) {
build_mask(mask);
}
/* Movie clips. */
- LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
+ BLI_LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
build_movieclip(clip);
}
/* Collections. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index b12af21fc8d..7731b76c6b9 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -37,6 +37,7 @@
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
@@ -79,13 +80,13 @@ static void deg_graph_tag_paths_recursive(DepsNode *node)
void deg_graph_transitive_reduction(Depsgraph *graph)
{
+ int num_removed_relations = 0;
foreach (OperationDepsNode *target, graph->operations) {
/* Clear tags. */
foreach (OperationDepsNode *node, graph->operations) {
node->done = 0;
}
-
- /* mark nodes from which we can reach the target
+ /* Mark nodes from which we can reach the target
* start with children, so the target node and direct children are not
* flagged.
*/
@@ -93,27 +94,30 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
foreach (DepsRelation *rel, target->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
}
-
/* Remove redundant paths to the target. */
for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
it_rel != target->inlinks.end();
)
{
DepsRelation *rel = *it_rel;
- /* Increment in advance, so we can safely remove the relation. */
- ++it_rel;
-
if (rel->from->type == DEG_NODE_TYPE_TIMESOURCE) {
/* HACK: time source nodes don't get "done" flag set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying.
*/
+ ++it_rel;
}
else if (rel->from->done & OP_REACHABLE) {
+ rel->unlink();
OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ ++num_removed_relations;
+ }
+ else {
+ ++it_rel;
}
}
}
+ DEG_DEBUG_PRINTF("Removed %d relations\n", num_removed_relations);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 5111db08e03..8fc4c0bcec1 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+/** \file blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
* \ingroup depsgraph
*
* Implementation of tools for debugging the depsgraph
@@ -41,6 +41,9 @@ extern "C" {
#include "DEG_depsgraph_debug.h"
#include "intern/depsgraph_intern.h"
+#include "intern/nodes/deg_node_id.h"
+#include "intern/nodes/deg_node_time.h"
+
#include "util/deg_util_foreach.h"
/* ****************** */
@@ -115,7 +118,7 @@ static int deg_debug_node_color_index(const DepsNode *node)
break;
}
/* Do others based on class. */
- switch (node->tclass) {
+ switch (node->get_class()) {
case DEG_NODE_CLASS_OPERATION:
return 4;
case DEG_NODE_CLASS_COMPONENT:
@@ -139,7 +142,6 @@ static int deg_debug_node_color_index(const DepsNode *node)
struct DebugContext {
FILE *file;
bool show_tags;
- bool show_eval_priority;
};
static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
@@ -180,7 +182,7 @@ static void deg_debug_graphviz_legend(const DebugContext &ctx)
#ifdef COLOR_SCHEME_NODE_TYPE
const int (*pair)[2];
for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- DepsNodeFactory *nti = DEG_get_node_factory((eDEG_NODE_TYPE)(*pair)[0]);
+ DepsNodeFactory *nti = deg_type_get_factory((eDepsNode_Type)(*pair)[0]);
deg_debug_graphviz_legend_color(ctx,
nti->tname().c_str(),
deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
@@ -202,7 +204,7 @@ static void deg_debug_graphviz_node_color(const DebugContext &ctx,
const char *color_update = "dodgerblue3";
const char *color = color_default;
if (ctx.show_tags) {
- if (node->tclass == DEG_NODE_CLASS_OPERATION) {
+ if (node->get_class() == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
color = color_modified;
@@ -223,7 +225,7 @@ static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
float penwidth_update = 4.0f;
float penwidth = penwidth_default;
if (ctx.show_tags) {
- if (node->tclass == DEG_NODE_CLASS_OPERATION) {
+ if (node->get_class() == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
penwidth = penwidth_modified;
@@ -261,14 +263,14 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod
{
const char *base_style = "filled"; /* default style */
if (ctx.show_tags) {
- if (node->tclass == DEG_NODE_CLASS_OPERATION) {
+ if (node->get_class() == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
base_style = "striped";
}
}
}
- switch (node->tclass) {
+ switch (node->get_class()) {
case DEG_NODE_CLASS_GENERIC:
deg_debug_fprintf(ctx, "\"%s\"", base_style);
break;
@@ -286,22 +288,11 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
{
const char *shape = "box";
string name = node->identifier();
- float priority = -1.0f;
- if (ctx.show_eval_priority && node->tclass == DEG_NODE_CLASS_OPERATION) {
- priority = ((OperationDepsNode *)node)->eval_priority;
- }
deg_debug_fprintf(ctx, "// %s\n", name.c_str());
deg_debug_fprintf(ctx, "\"node_%p\"", node);
deg_debug_fprintf(ctx, "[");
// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
- if (priority >= 0.0f) {
- deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
- name.c_str(),
- priority);
- }
- else {
- deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
- }
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
deg_debug_fprintf(ctx, ",shape=%s", shape);
@@ -403,6 +394,8 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
case DEG_NODE_TYPE_OPERATION:
deg_debug_graphviz_node_single(ctx, node);
break;
+ case NUM_DEG_NODE_TYPES:
+ break;
}
}
@@ -434,7 +427,7 @@ static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
static bool deg_debug_graphviz_is_owner(const DepsNode *node,
const DepsNode *other)
{
- switch (node->tclass) {
+ switch (node->get_class()) {
case DEG_NODE_CLASS_COMPONENT:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
@@ -474,6 +467,7 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
deg_debug_fprintf(ctx, "[");
/* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
/* NOTE: edge from node to own cluster is not possible and gives graphviz
@@ -524,7 +518,9 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
} // namespace DEG
-void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+void DEG_debug_relations_graphviz(const Depsgraph *graph,
+ FILE *f,
+ const char *label)
{
if (!graph) {
return;
@@ -534,8 +530,6 @@ void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool
DEG::DebugContext ctx;
ctx.file = f;
- ctx.show_tags = show_eval;
- ctx.show_eval_priority = show_eval;
DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL);
DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL);
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
new file mode 100644
index 00000000000..35888f8d5e3
--- /dev/null
+++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
@@ -0,0 +1,157 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
+ * \ingroup depsgraph
+ */
+
+#include "DEG_depsgraph_debug.h"
+
+#include <algorithm>
+#include <cstdarg>
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_math_base.h"
+
+#include "intern/depsgraph.h"
+#include "intern/nodes/deg_node_id.h"
+
+#include "util/deg_util_foreach.h"
+
+extern "C" {
+#include "DNA_ID.h"
+} /* extern "C" */
+
+#define NL "\r\n"
+
+namespace DEG {
+namespace {
+
+struct DebugContext {
+ FILE *file;
+ const Depsgraph *graph;
+ const char *label;
+ const char *output_filename;
+};
+
+struct StatsEntry {
+ const IDDepsNode *id_node;
+ double time;
+};
+
+/* TODO(sergey): De-duplicate with graphviz relation debugger. */
+static void deg_debug_fprintf(const DebugContext &ctx,
+ const char *fmt,
+ ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+BLI_INLINE double get_node_time(const DebugContext& /*ctx*/,
+ const DepsNode *node)
+{
+ // TODO(sergey): Figure out a nice way to define which exact time
+ // we want to show.
+ return node->stats.current_time;
+}
+
+bool stat_entry_comparator(const StatsEntry& a, const StatsEntry& b)
+{
+ return a.time < b.time;
+}
+
+void write_stats_data(const DebugContext& ctx)
+{
+ // Fill in array of all stats which are to be displayed.
+ vector<StatsEntry> stats;
+ stats.reserve(ctx.graph->id_nodes.size());
+ foreach (const IDDepsNode *id_node, ctx.graph->id_nodes) {
+ const double time = get_node_time(ctx, id_node);
+ if (time == 0.0) {
+ continue;
+ }
+ StatsEntry entry;
+ entry.id_node = id_node;
+ entry.time = time;
+ stats.push_back(entry);
+ }
+ // Sort the data.
+ std::sort(stats.begin(), stats.end(), stat_entry_comparator);
+ // We limit number of entries, otherwise things become unreadable.
+ stats.resize(min_ii(stats.size(), 32));
+ // Print data to the file stream.
+ deg_debug_fprintf(ctx, "$data << EOD" NL);
+ foreach (const StatsEntry& entry, stats) {
+ deg_debug_fprintf(ctx, "\"%s\",%f" NL,
+ entry.id_node->id_orig->name + 2,
+ entry.time);
+ }
+ deg_debug_fprintf(ctx, "EOD" NL);
+}
+
+void deg_debug_stats_gnuplot(const DebugContext& ctx)
+{
+ // Data itself.
+ write_stats_data(ctx);
+ // Optional label.
+ if (ctx.label && ctx.label[0]) {
+ deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label);
+ }
+ // Rest of the commands.
+ // TODO(sergey): Need to decide on the resolution somehow.
+ deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL);
+ deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename);
+ deg_debug_fprintf(ctx, "set grid" NL);
+ deg_debug_fprintf(ctx, "set datafile separator ','" NL);
+ deg_debug_fprintf(ctx, "set style fill solid" NL);
+ deg_debug_fprintf(ctx, "plot \"$data\" using " \
+ "($2*0.5):0:($2*0.5):(0.2):yticlabels(1) "
+ "with boxxyerrorbars t '' lt rgb \"#406090\"" NL);
+
+}
+
+} // namespace
+} // namespace DEG
+
+void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph,
+ FILE *f,
+ const char *label,
+ const char *output_filename)
+{
+ if (depsgraph == NULL) {
+ return;
+ }
+ DEG::DebugContext ctx;
+ ctx.file = f;
+ ctx.graph = (DEG::Depsgraph *)depsgraph;
+ ctx.label = label;
+ ctx.output_filename = output_filename;
+ DEG::deg_debug_stats_gnuplot(ctx);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 4fea8b49706..3a78c9050f7 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -49,6 +49,7 @@ extern "C" {
#include "RNA_access.h"
}
+#include <algorithm>
#include <cstring>
#include "DEG_depsgraph.h"
@@ -57,7 +58,9 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
+#include "intern/nodes/deg_node_time.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
@@ -79,6 +82,14 @@ namespace DEG {
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
+/* TODO(sergey): Find a better place for this. */
+template <typename T>
+static void remove_from_vector(vector<T> *vector, const T& value)
+{
+ vector->erase(std::remove(vector->begin(), vector->end(), value),
+ vector->end());
+}
+
Depsgraph::Depsgraph()
: time_source(NULL),
need_update(true),
@@ -156,7 +167,7 @@ static bool pointer_to_component_node_criteria(
return true;
}
else if (object->pose != NULL) {
- LINKLIST_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) {
+ BLI_LISTBASE_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) {
if (BLI_findindex(&pchan->constraints, con) != -1) {
/* bone transforms */
*type = DEG_NODE_TYPE_BONE;
@@ -193,11 +204,7 @@ static bool pointer_to_component_node_criteria(
}
}
else if (ptr->type == &RNA_ShapeKey) {
- Key *key = (Key *)ptr->id.data;
- /* ShapeKeys are currently handled as geometry on the geometry that
- * owns it.
- */
- *id = key->from;
+ *id = (ID *)ptr->id.data;
*type = DEG_NODE_TYPE_GEOMETRY;
return true;
}
@@ -263,7 +270,7 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
TimeSourceDepsNode *Depsgraph::add_time_source()
{
if (time_source == NULL) {
- DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_TIMESOURCE);
+ DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_TIMESOURCE);
time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", "Time Source");
}
return time_source;
@@ -284,7 +291,7 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, bool do_tag, ID *id_cow_hint)
BLI_assert((id->tag & LIB_TAG_COPY_ON_WRITE) == 0);
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_ID_REF);
+ DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", id->name);
id_node->init_copy_on_write(id_cow_hint);
if (do_tag) {
@@ -354,7 +361,7 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
if (comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
IDDepsNode *id_to = to->owner->owner;
IDDepsNode *id_from = from->owner->owner;
- if (id_to != id_from && (id_to->id_orig->tag & LIB_TAG_ID_RECALC_ALL)) {
+ if (id_to != id_from && (id_to->id_orig->recalc & ID_RECALC_ALL)) {
if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
id_from->tag_update(this);
id_from->eval_flags |= DAG_EVAL_NEED_CPU;
@@ -431,7 +438,15 @@ DepsRelation::DepsRelation(DepsNode *from,
DepsRelation::~DepsRelation()
{
/* Sanity check. */
- BLI_assert(this->from && this->to);
+ BLI_assert(from != NULL && to != NULL);
+}
+
+void DepsRelation::unlink()
+{
+ /* Sanity check. */
+ BLI_assert(from != NULL && to != NULL);
+ remove_from_vector(&from->outlinks, this);
+ remove_from_vector(&to->inlinks, this);
}
/* Low level tagging -------------------------------------- */
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 8a34be0c7a2..f18b93c9807 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -87,6 +87,8 @@ struct DepsRelation {
const char *description);
~DepsRelation();
+
+ void unlink();
};
/* ********* */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 57153279acb..902cbe039cd 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -68,6 +68,7 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_types.h"
@@ -293,8 +294,8 @@ void DEG_graph_relations_update(Depsgraph *graph,
void DEG_relations_tag_update(Main *bmain)
{
DEG_DEBUG_PRINTF("%s: Tagging relations for update.\n", __func__);
- LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
- LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Depsgraph *depsgraph =
(Depsgraph *)BKE_scene_get_depsgraph(scene,
view_layer,
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 42c1cf861eb..e8d166532ad 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -42,6 +42,9 @@ extern "C" {
#include "DEG_depsgraph_build.h"
#include "intern/depsgraph_intern.h"
+#include "intern/nodes/deg_node_id.h"
+#include "intern/nodes/deg_node_time.h"
+
#include "util/deg_util_foreach.h"
bool DEG_debug_compare(const struct Depsgraph *graph1,
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 1d389b902b8..ad1a850a807 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -48,12 +48,10 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_operation.h"
+#include "intern/nodes/deg_node_time.h"
#include "intern/depsgraph.h"
-/* Unfinished and unused, and takes quite some pre-processing time. */
-#undef USE_EVAL_PRIORITY
-
/* ****************** */
/* Evaluation Context */
@@ -85,11 +83,10 @@ void DEG_evaluation_context_init_from_scene(EvaluationContext *eval_ctx,
eEvaluationMode mode)
{
DEG_evaluation_context_init(eval_ctx, mode);
- eval_ctx->depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ eval_ctx->depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
eval_ctx->view_layer = view_layer;
eval_ctx->engine_type = engine_type;
eval_ctx->ctime = BKE_scene_frame_get(scene);
- BLI_assert(eval_ctx->depsgraph != NULL);
}
/* Free evaluation context. */
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index e7e472ea5d6..df5e51a3910 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -60,8 +60,8 @@ namespace DEG {
/* Typeinfo Struct (nti) */
struct DepsNodeFactory {
virtual eDepsNode_Type type() const = 0;
- virtual eDepsNode_Class tclass() const = 0;
virtual const char *tname() const = 0;
+ virtual int id_recalc_tag() const = 0;
virtual DepsNode *create_node(const ID *id,
const char *subdata,
@@ -71,8 +71,8 @@ struct DepsNodeFactory {
template <class NodeType>
struct DepsNodeFactoryImpl : public DepsNodeFactory {
eDepsNode_Type type() const { return NodeType::typeinfo.type; }
- eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
const char *tname() const { return NodeType::typeinfo.tname; }
+ int id_recalc_tag() const { return NodeType::typeinfo.id_recalc_tag; }
DepsNode *create_node(const ID *id, const char *subdata, const char *name) const
{
@@ -80,7 +80,6 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
/* populate base node settings */
node->type = type();
- node->tclass = tclass();
if (name[0] != '\0') {
/* set name if provided ... */
@@ -103,10 +102,7 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
void deg_register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
-DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type);
-
-/* Get typeinfo for provided node */
-DepsNodeFactory *deg_node_get_factory(const DepsNode *node);
+DepsNodeFactory *deg_type_get_factory(const eDepsNode_Type type);
/* Editors Integration -------------------------------------------------- */
@@ -116,11 +112,6 @@ void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx,
void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
bool updated);
-/* Tagging helpers ------------------------------------------------------ */
-
-void lib_id_recalc_tag(struct Main *bmain, struct ID *id);
-void lib_id_recalc_data_tag(struct Main *bmain, struct ID *id);
-
#define DEG_DEBUG_PRINTF(...) \
do { \
if (G.debug & G_DEBUG_DEPSGRAPH) { \
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 6892bdaa178..63c9aa1407a 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -46,13 +46,14 @@ extern "C" {
#include "DEG_depsgraph_query.h"
#include "intern/depsgraph_intern.h"
+#include "intern/nodes/deg_node_id.h"
bool DEG_id_type_tagged(Main *bmain, short id_type)
{
return bmain->id_tag_update[BKE_idcode_to_index(id_type)] != 0;
}
-short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
+short DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
{
if (graph == NULL) {
/* Happens when converting objects to mesh from a python script
@@ -64,9 +65,8 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return 0;
}
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
-
- DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ const DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
@@ -75,16 +75,16 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return id_node->eval_flags;
}
-Scene *DEG_get_evaluated_scene(Depsgraph *graph)
+Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
Scene *scene_orig = deg_graph->scene;
return reinterpret_cast<Scene *>(deg_graph->get_cow_id(&scene_orig->id));
}
-ViewLayer *DEG_get_evaluated_view_layer(Depsgraph *graph)
+ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph)
{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
Scene *scene_cow = DEG_get_evaluated_scene(graph);
ViewLayer *view_layer_orig = deg_graph->view_layer;
ViewLayer *view_layer_cow =
@@ -94,19 +94,19 @@ ViewLayer *DEG_get_evaluated_view_layer(Depsgraph *graph)
return view_layer_cow;
}
-Object *DEG_get_evaluated_object(Depsgraph *depsgraph, Object *object)
+Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
{
return (Object *)DEG_get_evaluated_id(depsgraph, &object->id);
}
-ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, ID *id)
+ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
{
/* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
* but here we never do assert, since we don't know nature of the
* incoming ID datablock.
*/
- DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph;
- DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
+ const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph;
+ const DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
return id;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index b1353f528bc..e6692cf49b3 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -50,6 +50,7 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "util/deg_util_foreach.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index d8a54642a85..30c9d9f10be 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -38,6 +38,7 @@ extern "C" {
#include "BKE_anim.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_object.h"
} /* extern "C" */
#include "DNA_object_types.h"
@@ -49,15 +50,41 @@ extern "C" {
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
+#include "intern/nodes/deg_node_id.h"
+
#ifndef NDEBUG
# include "intern/eval/deg_eval_copy_on_write.h"
#endif
/* ************************ DEG ITERATORS ********************* */
+static void verify_id_proeprties_freed(DEGObjectIterData *data)
+{
+ if (data->dupli_object_current == NULL) {
+ // We didn't enter duplication yet, so we can't have any dangling
+ // pointers.
+ return;
+ }
+ const Object *dupli_object = data->dupli_object_current->ob;
+ Object *temp_dupli_object = &data->temp_dupli_object;
+ if (temp_dupli_object->id.properties == NULL) {
+ // No ID proeprties in temp datablock -- no leak is possible.
+ return;
+ }
+ if (temp_dupli_object->id.properties == dupli_object->id.properties) {
+ // Temp copy of object did not modify ID properties.
+ return;
+ }
+ // Free memory which is owned by temporary storage which is about to
+ // get overwritten.
+ IDP_FreeProperty(temp_dupli_object->id.properties);
+ MEM_freeN(temp_dupli_object->id.properties);
+ temp_dupli_object->id.properties = NULL;
+}
+
static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
{
- DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
while (data->dupli_object_next != NULL) {
DupliObject *dob = data->dupli_object_next;
Object *obd = dob->ob;
@@ -75,17 +102,29 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
continue;
}
+ verify_id_proeprties_freed(data);
+
data->dupli_object_current = dob;
/* Temporary object to evaluate. */
Object *dupli_parent = data->dupli_parent;
Object *temp_dupli_object = &data->temp_dupli_object;
*temp_dupli_object = *dob->ob;
+ temp_dupli_object->transflag &= ~OB_DUPLI;
temp_dupli_object->select_color = dupli_parent->select_color;
temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI;
- BLI_assert(dob->collection_properties != NULL);
- temp_dupli_object->base_collection_properties = dob->collection_properties;
- IDP_MergeGroup(temp_dupli_object->base_collection_properties, dupli_parent->base_collection_properties, false);
+
+ if (dob->collection_properties != NULL) {
+ temp_dupli_object->base_collection_properties = dob->collection_properties;
+ IDP_MergeGroup(temp_dupli_object->base_collection_properties,
+ dupli_parent->base_collection_properties,
+ false);
+ }
+ else {
+ temp_dupli_object->base_collection_properties =
+ dupli_parent->base_collection_properties;
+ }
+
copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
iter->current = &data->temp_dupli_object;
BLI_assert(
@@ -99,45 +138,63 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node)
{
- /* Reset the skip in case we are running from within a loop. */
- iter->skip = false;
+ /* Set it early in case we need to exit and we are running from within a loop. */
+ iter->skip = true;
- DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
const ID_Type id_type = GS(id_node->id_orig->name);
if (id_type != ID_OB) {
- iter->skip = true;
return;
}
switch (id_node->linked_state) {
case DEG::DEG_ID_LINKED_DIRECTLY:
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) {
+ return;
+ }
break;
case DEG::DEG_ID_LINKED_VIA_SET:
- if (data->flag & DEG_ITER_OBJECT_FLAG_SET) {
- break;
- }
- else {
- ATTR_FALLTHROUGH;
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) {
+ return;
}
+ break;
case DEG::DEG_ID_LINKED_INDIRECTLY:
- iter->skip = true;
- return;
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) {
+ return;
+ }
+ break;
}
Object *object = (Object *)id_node->id_cow;
BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id));
- if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) {
+ if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) &&
+ ((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0))
+ {
+ return;
+ }
+
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
+ (object->transflag & OB_DUPLI))
+ {
data->dupli_parent = object;
data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object);
data->dupli_object_next = (DupliObject *)data->dupli_list->first;
+ const eObjectVisibilityCheck mode =
+ (data->mode == DEG_ITER_OBJECT_MODE_RENDER)
+ ? OB_VISIBILITY_CHECK_FOR_RENDER
+ : OB_VISIBILITY_CHECK_FOR_VIEWPORT;
+ if (BKE_object_is_visible(object, mode) == false) {
+ return;
+ }
}
iter->current = object;
+ iter->skip = false;
}
-void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data)
+void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
{
Depsgraph *depsgraph = data->graph;
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
@@ -149,7 +206,10 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data)
}
/* TODO(sergey): What evaluation type we want here? */
- DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER);
+ /* TODO(dfelinto): Get rid of evaluation context here, it's only used to do
+ * direct dupli-objects update in group.c. Which is terribly bad, and all
+ * objects are expected to be evaluated already. */
+ DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_VIEWPORT);
data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
iter->data = data;
@@ -171,15 +231,17 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data)
void DEG_iterator_objects_next(BLI_Iterator *iter)
{
- DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
Depsgraph *depsgraph = data->graph;
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
do {
+ iter->skip = false;
if (data->dupli_list) {
if (deg_objects_dupli_iterator_next(iter)) {
return;
}
else {
+ verify_id_proeprties_freed(data);
free_object_duplilist(data->dupli_list);
data->dupli_parent = NULL;
data->dupli_list = NULL;
@@ -202,8 +264,10 @@ void DEG_iterator_objects_next(BLI_Iterator *iter)
void DEG_iterator_objects_end(BLI_Iterator *iter)
{
#ifndef NDEBUG
- DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
- /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
+ /* Force crash in case the iterator data is referenced and accessed down
+ * the line. (T51718)
+ */
memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
#else
(void) iter;
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index e928da58e87..38f43f5720b 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -35,8 +35,9 @@
#include <queue>
#include "BLI_utildefines.h"
-#include "BLI_task.h"
#include "BLI_listbase.h"
+#include "BLI_math_bits.h"
+#include "BLI_task.h"
extern "C" {
#include "DNA_object_types.h"
@@ -63,225 +64,63 @@ extern "C" {
#include "intern/eval/deg_eval_flush.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
-/* Define this in order to have more strict sanitization of what tagging flags
- * are used for ID databnlocks. Ideally, we would always want this, but there
- * are cases in generic modules (like IR remapping) where we don't want to spent
- * lots of time trying to guess which components are to be updated.
- */
-// #define STRICT_COMPONENT_TAGGING
-
/* *********************** */
/* Update Tagging/Flushing */
namespace DEG {
-/* Data-Based Tagging ------------------------------- */
-
-void lib_id_recalc_tag(Main *bmain, ID *id)
-{
- id->tag |= LIB_TAG_ID_RECALC;
- DEG_id_type_tag(bmain, GS(id->name));
-}
-
-void lib_id_recalc_data_tag(Main *bmain, ID *id)
-{
- id->tag |= LIB_TAG_ID_RECALC_DATA;
- DEG_id_type_tag(bmain, GS(id->name));
-}
-
namespace {
void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag);
-void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
-{
- /* This bit of code ensures legacy object->recalc flags are still filled in
- * the same way as it was expected with the old dependency graph.
- *
- * This is because some areas like motion paths and likely some other
- * physics baking process are doing manual scene update on all the frames,
- * trying to minimize number of updates.
- *
- * But this flag will also let us to re-construct entry nodes for update
- * after relations update and after layer visibility changes.
- */
- if (flag) {
- if (flag & OB_RECALC_OB) {
- lib_id_recalc_tag(bmain, id);
- }
- if (flag & (OB_RECALC_DATA | PSYS_RECALC)) {
- lib_id_recalc_data_tag(bmain, id);
- }
- }
- else {
- lib_id_recalc_tag(bmain, id);
- }
-}
-
-/* Special tagging */
-void id_tag_update_special_zero_flag(Depsgraph *graph, IDDepsNode *id_node)
-{
- /* NOTE: Full ID node update for now, need to minimize that i9n the future. */
- id_node->tag_update(graph);
-}
-
-/* Tag corresponding to OB_RECALC_OB. */
-void id_tag_update_object_transform(Depsgraph *graph, IDDepsNode *id_node)
+void depsgraph_geometry_tag_to_component(const ID *id,
+ eDepsNode_Type *component_type)
{
- ComponentDepsNode *transform_comp =
- id_node->find_component(DEG_NODE_TYPE_TRANSFORM);
- if (transform_comp == NULL) {
-#ifdef STRICT_COMPONENT_TAGGING
- DEG_ERROR_PRINTF("ERROR: Unable to find transform component for %s\n",
- id_node->id_orig->name);
- BLI_assert(!"This is not supposed to happen!");
-#endif
- return;
- }
- transform_comp->tag_update(graph);
-}
-
-/* Tag corresponding to OB_RECALC_DATA. */
-void id_tag_update_object_data(Depsgraph *graph, IDDepsNode *id_node)
-{
- const ID_Type id_type = GS(id_node->id_orig->name);
- ComponentDepsNode *data_comp = NULL;
+ const ID_Type id_type = GS(id->name);
switch (id_type) {
case ID_OB:
{
- const Object *object = (Object *)id_node->id_orig;
+ const Object *object = (Object *)id;
switch (object->type) {
case OB_MESH:
case OB_CURVE:
case OB_SURF:
case OB_FONT:
case OB_MBALL:
- data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY);
+ *component_type = DEG_NODE_TYPE_GEOMETRY;
break;
case OB_ARMATURE:
- data_comp = id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
+ *component_type = DEG_NODE_TYPE_EVAL_POSE;
break;
- /* TODO(sergey): More cases here? */
+ /* TODO(sergey): More cases here? */
}
break;
}
case ID_ME:
- data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY);
+ *component_type = DEG_NODE_TYPE_GEOMETRY;
break;
case ID_PA:
return;
case ID_LP:
- data_comp = id_node->find_component(DEG_NODE_TYPE_PARAMETERS);
+ *component_type = DEG_NODE_TYPE_PARAMETERS;
break;
default:
break;
}
- if (data_comp == NULL) {
-#ifdef STRICT_COMPONENT_TAGGING
- DEG_ERROR_PRINTF("ERROR: Unable to find data component for %s\n",
- id_node->id_orig->name);
- BLI_assert(!"This is not supposed to happen!");
-#endif
- return;
- }
- data_comp->tag_update(graph);
- /* Special legacy compatibility code, tag data ID for update when object
- * is tagged for data update.
- */
- if (id_type == ID_OB) {
- Object *object = (Object *)id_node->id_orig;
- ID *data_id = (ID *)object->data;
- if (data_id != NULL) {
- IDDepsNode *data_id_node = graph->find_id_node(data_id);
- // BLI_assert(data_id_node != NULL);
- /* TODO(sergey): Do we want more granular tags here? */
- /* TODO(sergey): Hrm, during some operations it's possible to have
- * object node existing but not it's data. For example, when making
- * objects local. This is valid situation, but how can we distinguish
- * that from someone trying to do stupid things with dependency
- * graph?
- */
- if (data_id_node != NULL) {
- data_id_node->tag_update(graph);
- }
- }
- }
-}
-
-/* Tag corresponding to OB_RECALC_TIME. */
-void id_tag_update_object_time(Depsgraph *graph, IDDepsNode *id_node)
-{
- ComponentDepsNode *animation_comp =
- id_node->find_component(DEG_NODE_TYPE_ANIMATION);
- if (animation_comp == NULL) {
- /* It's not necessarily we've got animation component in cases when
- * we are tagging for time updates.
- */
- return;
- }
- animation_comp->tag_update(graph);
- /* TODO(sergey): More components to tag here? */
-}
-
-void id_tag_update_particle(Depsgraph *graph, IDDepsNode *id_node, int tag)
-{
- ComponentDepsNode *particle_comp =
- id_node->find_component(DEG_NODE_TYPE_PARAMETERS);
- ParticleSettings *particle_settings = (ParticleSettings *)id_node->id_orig;
- particle_settings->recalc |= (tag & PSYS_RECALC);
- if (particle_comp == NULL) {
-#ifdef STRICT_COMPONENT_TAGGING
- DEG_ERROR_PRINTF("ERROR: Unable to find particle component for %s\n",
- id_node->id_orig->name);
- BLI_assert(!"This is not supposed to happen!");
-#endif
- return;
- }
- particle_comp->tag_update(graph);
-}
-
-void id_tag_update_shading(Depsgraph *graph, IDDepsNode *id_node)
-{
- ComponentDepsNode *shading_comp;
- if (GS(id_node->id_orig->name) == ID_NT) {
- shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING_PARAMETERS);
- }
- else {
- shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING);
- }
- if (shading_comp == NULL) {
-#ifdef STRICT_COMPONENT_TAGGING
- DEG_ERROR_PRINTF("ERROR: Unable to find shading component for %s\n",
- id_node->id_orig->name);
- BLI_assert(!"This is not supposed to happen!");
-#endif
- return;
- }
- shading_comp->tag_update(graph);
-}
-
-/* Tag corresponding to DEG_TAG_COPY_ON_WRITE. */
-void id_tag_update_copy_on_write(Depsgraph *graph, IDDepsNode *id_node)
-{
- if (!DEG_depsgraph_use_copy_on_write()) {
- return;
- }
- ComponentDepsNode *cow_comp =
- id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
- OperationDepsNode *cow_node = cow_comp->get_entry_operation();
- cow_node->tag_update(graph);
}
-void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node)
+void depsgraph_select_tag_to_component_opcode(
+ const ID *id,
+ eDepsNode_Type *component_type,
+ eDepsOperation_Code *operation_code)
{
- ComponentDepsNode *component;
- OperationDepsNode *node = NULL;
- const ID_Type id_type = GS(id_node->id_orig->name);
+ const ID_Type id_type = GS(id->name);
if (id_type == ID_SCE) {
/* We need to flush base flags to all objects in a scene since we
* don't know which ones changed. However, we don't want to update
@@ -292,62 +131,124 @@ void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node)
* does nothing and which is only used to cascade flush down the
* road.
*/
- component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
- BLI_assert(component != NULL);
- if (component != NULL) {
- node = component->find_operation(DEG_OPCODE_VIEW_LAYER_DONE);
- }
+ *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS;
+ *operation_code = DEG_OPCODE_VIEW_LAYER_DONE;
}
else if (id_type == ID_OB) {
- component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
- /* NOTE: This component might be missing for indirectly linked
- * objects.
- */
- if (component != NULL) {
- node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS);
- }
+ *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS;
+ *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS;
}
else {
- component = id_node->find_component(DEG_NODE_TYPE_BATCH_CACHE);
- BLI_assert(component != NULL);
- if (component != NULL) {
- node = component->find_operation(DEG_OPCODE_GEOMETRY_SELECT_UPDATE,
- "", -1);
- }
- }
- if (node != NULL) {
- node->tag_update(graph);
+ *component_type = DEG_NODE_TYPE_BATCH_CACHE;
+ *operation_code = DEG_OPCODE_GEOMETRY_SELECT_UPDATE;
}
}
-void id_tag_update_base_flags(Depsgraph *graph, IDDepsNode *id_node)
+void depsgraph_base_flags_tag_to_component_opcode(
+ const ID *id,
+ eDepsNode_Type *component_type,
+ eDepsOperation_Code *operation_code)
{
- ComponentDepsNode *component;
- OperationDepsNode *node = NULL;
- const ID_Type id_type = GS(id_node->id_orig->name);
+ const ID_Type id_type = GS(id->name);
if (id_type == ID_SCE) {
- component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
- if (component == NULL) {
- return;
- }
- node = component->find_operation(DEG_OPCODE_VIEW_LAYER_INIT);
+ *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS;
+ *operation_code = DEG_OPCODE_VIEW_LAYER_INIT;
}
else if (id_type == ID_OB) {
- component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
- if (component == NULL) {
- return;
- }
- node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS);
- if (node == NULL) {
- return;
- }
+ *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS;
+ *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS;
}
- if (node != NULL) {
- node->tag_update(graph);
+}
+
+void depsgraph_tag_to_component_opcode(const ID *id,
+ eDepsgraph_Tag tag,
+ eDepsNode_Type *component_type,
+ eDepsOperation_Code *operation_code)
+{
+ const ID_Type id_type = GS(id->name);
+ *component_type = DEG_NODE_TYPE_UNDEFINED;
+ *operation_code = DEG_OPCODE_OPERATION;
+ /* Special case for now, in the future we should get rid of this. */
+ if (tag == 0) {
+ *component_type = DEG_NODE_TYPE_ID_REF;
+ *operation_code = DEG_OPCODE_OPERATION;
+ return;
+ }
+ switch (tag) {
+ case DEG_TAG_TRANSFORM:
+ *component_type = DEG_NODE_TYPE_TRANSFORM;
+ break;
+ case DEG_TAG_GEOMETRY:
+ depsgraph_geometry_tag_to_component(id, component_type);
+ break;
+ case DEG_TAG_TIME:
+ *component_type = DEG_NODE_TYPE_ANIMATION;
+ break;
+ case DEG_TAG_PSYS_REDO:
+ case DEG_TAG_PSYS_RESET:
+ case DEG_TAG_PSYS_TYPE:
+ case DEG_TAG_PSYS_CHILD:
+ case DEG_TAG_PSYS_PHYS:
+ if (id_type == ID_PA) {
+ /* NOTES:
+ * - For particle settings node we need to use different
+ * component. Will be nice to get this unified with object,
+ * but we can survive for now with single exception here.
+ * Particles needs reconsideration anyway,
+ * - We do direct injection of particle settings recalc flag
+ * here. This is what we need to do for until particles
+ * are switched away from own recalc flag and are using
+ * ID->recalc flags instead.
+ */
+ ParticleSettings *particle_settings = (ParticleSettings *)id;
+ particle_settings->recalc |= (tag & DEG_TAG_PSYS_ALL);
+ *component_type = DEG_NODE_TYPE_PARAMETERS;
+ }
+ else {
+ *component_type = DEG_NODE_TYPE_EVAL_PARTICLES;
+ }
+ break;
+ case DEG_TAG_COPY_ON_WRITE:
+ *component_type = DEG_NODE_TYPE_COPY_ON_WRITE;
+ break;
+ case DEG_TAG_SHADING_UPDATE:
+ if (id_type == ID_NT) {
+ *component_type = DEG_NODE_TYPE_SHADING_PARAMETERS;
+ }
+ else {
+ *component_type = DEG_NODE_TYPE_SHADING;
+ }
+ break;
+ case DEG_TAG_SELECT_UPDATE:
+ depsgraph_select_tag_to_component_opcode(id,
+ component_type,
+ operation_code);
+ break;
+ case DEG_TAG_BASE_FLAGS_UPDATE:
+ depsgraph_base_flags_tag_to_component_opcode(id,
+ component_type,
+ operation_code);
+ case DEG_TAG_EDITORS_UPDATE:
+ /* There is no such node in depsgraph, this tag is to be handled
+ * separately.
+ */
+ break;
+ case DEG_TAG_PSYS_ALL:
+ BLI_assert(!"Should not happen");
+ break;
+ }
+}
+
+void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag)
+{
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree == NULL) {
+ return;
}
+ deg_graph_id_tag_update(bmain, graph, &ntree->id, flag);
}
-void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id)
+void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id)
{
/* NOTE: We handle this immediately, without delaying anything, to be
* sure we don't cause threading issues with OpenGL.
@@ -355,96 +256,158 @@ void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id)
/* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */
DEGEditorUpdateContext update_ctx = {NULL};
update_ctx.bmain = bmain;
+ update_ctx.depsgraph = (::Depsgraph *)graph;
update_ctx.scene = graph->scene;
update_ctx.view_layer = graph->view_layer;
deg_editors_id_update(&update_ctx, id);
}
-void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag)
+void depsgraph_tag_component(Depsgraph *graph,
+ IDDepsNode *id_node,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code operation_code)
{
- bNodeTree *ntree = NULL;
- switch (GS(id->name)) {
- case ID_MA:
- ntree = ((Material *)id)->nodetree;
- break;
- default:
- break;
- }
- if (ntree == NULL) {
+ ComponentDepsNode *component_node =
+ id_node->find_component(component_type);
+ if (component_node == NULL) {
return;
}
- IDDepsNode *id_node = graph->find_id_node(&ntree->id);
- if (id_node != NULL) {
- deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag);
+ if (operation_code == DEG_OPCODE_OPERATION) {
+ component_node->tag_update(graph);
+ }
+ else {
+ OperationDepsNode *operation_node =
+ component_node->find_operation(operation_code);
+ if (operation_node != NULL) {
+ operation_node->tag_update(graph);
+ }
}
}
-void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag)
+/* This is a tag compatibility with legacy code.
+ *
+ * Mainly, old code was tagging object with OB_RECALC_DATA tag to inform
+ * that object's data datablock changed. Now API expects that ID is given
+ * explicitly, but not all areas are aware of this yet.
+ */
+void deg_graph_id_tag_legacy_compat(Main *bmain,
+ ID *id,
+ eDepsgraph_Tag tag)
{
- Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
- IDDepsNode *id_node = deg_graph->find_id_node(id);
- /* Make sure legacy flags are all nicely update. */
- lib_id_recalc_tag_flag(bmain, id, flag);
- if (id_node == NULL) {
- /* Shouldn't happen, but better be sure here. */
- return;
- }
- /* Tag components based on flags. */
- if (flag == 0) {
- id_tag_update_special_zero_flag(graph, id_node);
- id_tag_update_ntree_special(bmain, graph, id, flag);
- return;
- }
- if (flag & OB_RECALC_OB) {
- id_tag_update_object_transform(graph, id_node);
- }
- if (flag & OB_RECALC_DATA) {
- id_tag_update_object_data(graph, id_node);
- if (DEG_depsgraph_use_copy_on_write()) {
- if (flag & DEG_TAG_COPY_ON_WRITE) {
- const ID_Type id_type = GS(id_node->id_orig->name);
- if (id_type == ID_OB) {
- Object *object = (Object *)id_node->id_orig;
- ID *ob_data = (ID *)object->data;
- DEG_id_tag_update_ex(bmain, ob_data, flag);
- }
- }
+ if (tag == DEG_TAG_GEOMETRY && GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ ID *data_id = (ID *)object->data;
+ if (data_id != NULL) {
+ DEG_id_tag_update_ex(bmain, data_id, 0);
}
}
- if (flag & OB_RECALC_TIME) {
- id_tag_update_object_time(graph, id_node);
- }
- if (flag & PSYS_RECALC) {
- id_tag_update_particle(graph, id_node, flag);
+}
+
+void deg_graph_id_tag_update_single_flag(Main *bmain,
+ Depsgraph *graph,
+ ID *id,
+ IDDepsNode *id_node,
+ eDepsgraph_Tag tag)
+{
+ if (tag == DEG_TAG_EDITORS_UPDATE) {
+ if (graph != NULL) {
+ depsgraph_update_editors_tag(bmain, graph, id);
+ }
+ return;
}
- if (flag & DEG_TAG_SHADING_UPDATE) {
- id_tag_update_shading(graph, id_node);
+ /* Get description of what is to be tagged. */
+ eDepsNode_Type component_type;
+ eDepsOperation_Code operation_code;
+ depsgraph_tag_to_component_opcode(id,
+ tag,
+ &component_type,
+ &operation_code);
+ /* Check whether we've got something to tag. */
+ if (component_type == DEG_NODE_TYPE_UNDEFINED) {
+ /* Given ID does not support tag. */
+ /* TODO(sergey): Shall we raise some panic here? */
+ return;
}
- if (flag & DEG_TAG_COPY_ON_WRITE) {
- id_tag_update_copy_on_write(graph, id_node);
+ /* Tag ID recalc flag. */
+ DepsNodeFactory *factory = deg_type_get_factory(component_type);
+ BLI_assert(factory != NULL);
+ id->recalc |= factory->id_recalc_tag();
+ /* Some sanity checks before moving forward. */
+ if (id_node == NULL) {
+ /* Happens when object is tagged for update and not yet in the
+ * dependency graph (but will be after relations update).
+ */
+ return;
}
- if (flag & DEG_TAG_SELECT_UPDATE) {
- id_tag_update_select_update(graph, id_node);
+ /* Tag corresponding dependency graph operation for update. */
+ if (component_type == DEG_NODE_TYPE_ID_REF) {
+ id_node->tag_update(graph);
}
- if (flag & DEG_TAG_BASE_FLAGS_UPDATE) {
- id_tag_update_base_flags(graph, id_node);
+ else {
+ depsgraph_tag_component(graph, id_node, component_type, operation_code);
}
- if (flag & DEG_TAG_EDITORS_UPDATE) {
- id_tag_update_editors_update(bmain, graph, id);
+ /* TODO(sergey): Get rid of this once all areas are using proper data ID
+ * for tagging.
+ */
+ deg_graph_id_tag_legacy_compat(bmain, id, tag);
+
+}
+
+void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag)
+{
+ IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id)
+ : NULL;
+ DEG_id_type_tag(bmain, GS(id->name));
+ if (flag == 0) {
+ /* TODO(sergey): Which recalc flags to set here? */
+ id->recalc |= ID_RECALC_ALL;
+ if (id_node != NULL) {
+ id_node->tag_update(graph);
+ }
}
+ int current_flag = flag;
+ while (current_flag != 0) {
+ eDepsgraph_Tag tag =
+ (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(&current_flag));
+ deg_graph_id_tag_update_single_flag(bmain,
+ graph,
+ id,
+ id_node,
+ tag);
+ }
+ /* Special case for nested node tree datablocks. */
id_tag_update_ntree_special(bmain, graph, id, flag);
}
+/* TODO(sergey): Consider storing scene and view layer at depsgraph allocation
+ * time.
+ */
+void deg_ensure_scene_view_layer(Depsgraph *graph,
+ Scene *scene,
+ ViewLayer *view_layer)
+{
+ if (!graph->need_update) {
+ return;
+ }
+ graph->scene = scene;
+ graph->view_layer = view_layer;
+}
+
void deg_id_tag_update(Main *bmain, ID *id, int flag)
{
- lib_id_recalc_tag_flag(bmain, id, flag);
- LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
- LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ deg_graph_id_tag_update(bmain, NULL, id, flag);
+ BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Depsgraph *depsgraph =
(Depsgraph *)BKE_scene_get_depsgraph(scene,
view_layer,
false);
if (depsgraph != NULL) {
+ /* Make sure depsgraph is pointing to a correct scene and
+ * view layer. This is mainly required in cases when depsgraph
+ * was not built yet.
+ */
+ deg_ensure_scene_view_layer(depsgraph, scene, view_layer);
deg_graph_id_tag_update(bmain, depsgraph, id, flag);
}
}
@@ -469,7 +432,10 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag);
}
/* Make sure collection properties are up to date. */
- for (Scene *scene_iter = graph->scene; scene_iter != NULL; scene_iter = scene_iter->set) {
+ for (Scene *scene_iter = graph->scene;
+ scene_iter != NULL;
+ scene_iter = scene_iter->set)
+ {
IDDepsNode *scene_id_node = graph->find_id_node(&scene_iter->id);
BLI_assert(scene_id_node != NULL);
scene_id_node->tag_update(graph);
@@ -480,6 +446,8 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
} // namespace DEG
+/* Data-Based Tagging */
+
/* Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(ID *id, int flag)
{
@@ -539,8 +507,8 @@ void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph)
void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
{
- LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
- LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Depsgraph *depsgraph =
(Depsgraph *)BKE_scene_get_depsgraph(scene,
view_layer,
@@ -556,6 +524,7 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
* editors about this.
*/
void DEG_ids_check_recalc(Main *bmain,
+ Depsgraph *depsgraph,
Scene *scene,
ViewLayer *view_layer,
bool time)
@@ -578,6 +547,7 @@ void DEG_ids_check_recalc(Main *bmain,
DEGEditorUpdateContext update_ctx = {NULL};
update_ctx.bmain = bmain;
+ update_ctx.depsgraph = depsgraph;
update_ctx.scene = scene;
update_ctx.view_layer = view_layer;
DEG::deg_editors_scene_update(&update_ctx, (updated || time));
@@ -601,12 +571,12 @@ void DEG_ids_clear_recalc(Main *bmain)
if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = (ID *)id->next) {
- id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
+ id->recalc &= ~ID_RECALC_ALL;
/* Some ID's contain semi-datablock nodetree */
ntree = ntreeFromID(id);
if (ntree != NULL) {
- ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
+ ntree->id.recalc &= ~ID_RECALC_ALL;
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 24fbb8d6e6e..22df3161428 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -51,14 +51,7 @@ namespace DEG {
/* Global type registry */
-/**
- * \note For now, this is a hashtable not array, since the core node types
- * currently do not have contiguous ID values. Using a hash here gives us
- * more flexibility, albeit using more memory and also sacrificing a little
- * speed. Later on, when things stabilise we may turn this back to an array
- * since there are only just a few node types that an array would cope fine...
- */
-static GHash *_depsnode_typeinfo_registry = NULL;
+static DepsNodeFactory *depsnode_typeinfo_registry[NUM_DEG_NODE_TYPES] = {NULL};
/* Registration ------------------------------------------- */
@@ -66,28 +59,16 @@ static GHash *_depsnode_typeinfo_registry = NULL;
void deg_register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != NULL);
- BLI_ghash_insert(_depsnode_typeinfo_registry,
- SET_INT_IN_POINTER(factory->type()),
- factory);
+ depsnode_typeinfo_registry[factory->type()] = factory;
}
/* Getters ------------------------------------------------- */
/* Get typeinfo for specified type */
-DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type)
+DepsNodeFactory *deg_type_get_factory(const eDepsNode_Type type)
{
/* look up type - at worst, it doesn't exist in table yet, and we fail */
- return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry,
- SET_INT_IN_POINTER(type));
-}
-
-/* Get typeinfo for provided node */
-DepsNodeFactory *deg_node_get_factory(const DepsNode *node)
-{
- if (node != NULL) {
- return NULL;
- }
- return deg_get_node_factory(node->type);
+ return depsnode_typeinfo_registry[type];
}
/* Stringified opcodes ------------------------------------- */
@@ -183,9 +164,6 @@ const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
/* Register all node types */
void DEG_register_node_types(void)
{
- /* initialise registry */
- DEG::_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
-
/* register node types */
DEG::deg_register_base_depsnodes();
DEG::deg_register_component_depsnodes();
@@ -195,5 +173,4 @@ void DEG_register_node_types(void)
/* Free registry on exit */
void DEG_free_node_types(void)
{
- BLI_ghash_free(DEG::_depsnode_typeinfo_registry, NULL, NULL);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index b12becc5589..d091f42bf80 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -96,9 +96,9 @@ typedef enum eDepsNode_LinkedState_Type {
/* Types of Nodes */
typedef enum eDepsNode_Type {
/* Fallback type for invalid return value */
- DEG_NODE_TYPE_UNDEFINED = -1,
+ DEG_NODE_TYPE_UNDEFINED = 0,
/* Inner Node (Operation) */
- DEG_NODE_TYPE_OPERATION = 0,
+ DEG_NODE_TYPE_OPERATION,
/* **** Generic Types **** */
@@ -149,6 +149,9 @@ typedef enum eDepsNode_Type {
DEG_NODE_TYPE_CACHE,
/* Batch Cache Component */
DEG_NODE_TYPE_BATCH_CACHE,
+
+ /* Total number of meaningful node types. */
+ NUM_DEG_NODE_TYPES,
} eDepsNode_Type;
/* Identifiers for common operations (as an enum). */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 5aebd6814a0..a6c6a16a528 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -46,20 +46,16 @@
#include "atomic_ops.h"
#include "intern/eval/deg_eval_flush.h"
+#include "intern/eval/deg_eval_stats.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
+#include "intern/nodes/deg_node_time.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_intern.h"
-#include "util/deg_util_foreach.h"
-
-/* Unfinished and unused, and takes quite some pre-processing time. */
-#undef USE_EVAL_PRIORITY
-/* Use integrated debugger to keep track how much each of the nodes was
- * evaluating.
- */
-#undef USE_DEBUGGER
+#include "util/deg_util_foreach.h"
namespace DEG {
@@ -75,52 +71,28 @@ static void schedule_children(TaskPool *pool,
struct DepsgraphEvalState {
EvaluationContext *eval_ctx;
Depsgraph *graph;
+ bool do_stats;
};
static void deg_task_run_func(TaskPool *pool,
void *taskdata,
int thread_id)
{
- DepsgraphEvalState *state =
- reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool));
- OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata);
-
+ void *userdata_v = BLI_task_pool_userdata(pool);
+ DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v;
+ OperationDepsNode *node = (OperationDepsNode *)taskdata;
+ /* Sanity checks. */
BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
-
- /* Should only be the case for NOOPs, which never get to this point. */
- BLI_assert(node->evaluate);
-
- /* Get context. */
- /* TODO: Who initialises this? "Init" operations aren't able to
- * initialise it!!!
- */
- /* TODO(sergey): We don't use component contexts at this moment. */
- /* ComponentDepsNode *comp = node->owner; */
- BLI_assert(node->owner != NULL);
-
- /* Since we're not leaving the thread for until the graph branches it is
- * possible to have NO-OP on the way. for which evaluate() will be NULL.
- * but that's all fine, we'll just scheduler it's children.
- */
- if (node->evaluate) {
- /* Take note of current time. */
-#ifdef USE_DEBUGGER
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
-#endif
-
- /* Perform operation. */
+ /* Perform operation. */
+ if (state->do_stats) {
+ const double start_time = PIL_check_seconds_timer();
node->evaluate(state->eval_ctx);
-
- /* Note how long this took. */
-#ifdef USE_DEBUGGER
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
-#endif
+ node->stats.current_time += PIL_check_seconds_timer() - start_time;
}
-
+ else {
+ node->evaluate(state->eval_ctx);
+ }
+ /* Schedule children. */
BLI_task_pool_delayed_push_begin(pool, thread_id);
schedule_children(pool, state->graph, node, thread_id);
BLI_task_pool_delayed_push_end(pool, thread_id);
@@ -130,7 +102,10 @@ typedef struct CalculatePengindData {
Depsgraph *graph;
} CalculatePengindData;
-static void calculate_pending_func(void *data_v, int i)
+static void calculate_pending_func(
+ void *__restrict data_v,
+ const int i,
+ const ParallelRangeTLS *__restrict /*tls*/)
{
CalculatePengindData *data = (CalculatePengindData *)data_v;
Depsgraph *graph = data->graph;
@@ -157,42 +132,30 @@ static void calculate_pending_func(void *data_v, int i)
static void calculate_pending_parents(Depsgraph *graph)
{
const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
CalculatePengindData data;
data.graph = graph;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
BLI_task_parallel_range(0,
num_operations,
&data,
calculate_pending_func,
- do_threads);
+ &settings);
}
-#ifdef USE_EVAL_PRIORITY
-static void calculate_eval_priority(OperationDepsNode *node)
+static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
{
- if (node->done) {
- return;
- }
- node->done = 1;
-
- if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- /* XXX standard cost of a node, could be estimated somewhat later on */
- const float cost = 1.0f;
- /* NOOP nodes have no cost */
- node->eval_priority = node->is_noop() ? cost : 0.0f;
-
- foreach (DepsRelation *rel, node->outlinks) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- BLI_assert(to->type == DEG_NODE_TYPE_OPERATION);
- calculate_eval_priority(to);
- node->eval_priority += to->eval_priority;
+ const bool do_stats = state->do_stats;
+ calculate_pending_parents(graph);
+ /* Clear tags and other things which needs to be clear. */
+ foreach (OperationDepsNode *node, graph->operations) {
+ node->done = 0;
+ if (do_stats) {
+ node->stats.reset_current();
}
}
- else {
- node->eval_priority = 0.0f;
- }
}
-#endif
/* Schedule a node if it needs evaluation.
* dec_parents: Decrement pending parents count, true when child nodes are
@@ -267,28 +230,23 @@ static void schedule_children(TaskPool *pool,
void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph)
{
- /* Generate base evaluation context, upon which all the others are derived. */
- // TODO: this needs both main and scene access...
-
/* Nothing to update, early out. */
if (BLI_gset_size(graph->entry_tags) == 0) {
return;
}
-
/* Set time for the current graph evaluation context. */
TimeSourceDepsNode *time_src = graph->find_time_source();
eval_ctx->depsgraph = (::Depsgraph *)graph;
eval_ctx->view_layer = DEG_get_evaluated_view_layer((::Depsgraph *)graph);
eval_ctx->ctime = time_src->cfra;
-
- /* XXX could use a separate pool for each eval context */
+ /* Set up evaluation context for depsgraph itself. */
DepsgraphEvalState state;
state.eval_ctx = eval_ctx;
state.graph = graph;
-
+ state.do_stats = (G.debug_value != 0);
+ /* Set up task scheduler and pull for threaded evaluation. */
TaskScheduler *task_scheduler;
bool need_free_scheduler;
-
if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
task_scheduler = BLI_task_scheduler_create(1);
need_free_scheduler = true;
@@ -297,31 +255,22 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
task_scheduler = BLI_task_scheduler_get();
need_free_scheduler = false;
}
-
TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
-
- calculate_pending_parents(graph);
-
- /* Clear tags. */
- foreach (OperationDepsNode *node, graph->operations) {
- node->done = 0;
- }
-
- /* Calculate priority for operation nodes. */
-#ifdef USE_EVAL_PRIORITY
- foreach (OperationDepsNode *node, graph->operations) {
- calculate_eval_priority(node);
- }
-#endif
-
+ /* Prepare all nodes for evaluation. */
+ initialize_execution(&state, graph);
+ /* Do actual evaluation now. */
schedule_graph(task_pool, graph);
-
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
-
+ /* Finalize statistics gathering. This is because we only gather single
+ * operation timing here, without aggregating anything to avoid any extra
+ * synchronization.
+ */
+ if (state.do_stats) {
+ deg_eval_stats_aggregate(graph);
+ }
/* Clear any uncleared tags - just in case. */
deg_graph_clear_tags(graph);
-
if (need_free_scheduler) {
BLI_task_scheduler_free(task_scheduler);
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 97e38af4367..a6668208574 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -46,6 +46,7 @@
#include "BLI_string.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -80,6 +81,7 @@ extern "C" {
#include "intern/depsgraph.h"
#include "intern/builder/deg_builder_nodes.h"
#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_id.h"
namespace DEG {
@@ -324,7 +326,6 @@ static bool check_datablocks_copy_on_writable(const ID *id_orig)
return !ELEM(id_type, ID_BR,
ID_LS,
ID_AC,
- ID_GR,
ID_PAL);
}
@@ -467,6 +468,137 @@ void update_special_pointers(const Depsgraph *depsgraph,
}
}
+void update_copy_on_write_layer_collections(
+ ListBase *layer_collections_cow,
+ const ListBase *layer_collections_orig);
+
+void update_copy_on_write_layer_collection(
+ LayerCollection *layer_collection_cow,
+ const LayerCollection *layer_collection_orig)
+{
+ // Make a local copy of original layer collection, so we can start
+ // modifying it.
+ LayerCollection local = *layer_collection_orig;
+ // Copy all pointer data from original CoW version of layer collection.
+ local.next = layer_collection_cow->next;
+ local.prev = layer_collection_cow->prev;
+ local.scene_collection = layer_collection_cow->scene_collection;
+ local.object_bases = layer_collection_cow->object_bases;
+ local.overrides = layer_collection_cow->overrides;
+ local.layer_collections = layer_collection_cow->layer_collections;
+ local.properties = layer_collection_cow->properties;
+ local.properties_evaluated = layer_collection_cow->properties_evaluated;
+ // Synchronize pointer-related data.
+ IDP_Reset(local.properties, layer_collection_orig->properties);
+ // Copy synchronized version back.
+ *layer_collection_cow = local;
+ // Recurs into nested layer collections.
+ update_copy_on_write_layer_collections(
+ &layer_collection_cow->layer_collections,
+ &layer_collection_orig->layer_collections);
+}
+
+void update_copy_on_write_layer_collections(
+ ListBase *layer_collections_cow,
+ const ListBase *layer_collections_orig)
+{
+ const LayerCollection *layer_collection_orig =
+ (const LayerCollection *)layer_collections_orig->first;
+ LayerCollection *layer_collection_cow =
+ (LayerCollection *)layer_collections_cow->first;
+ while (layer_collection_orig != NULL) {
+ update_copy_on_write_layer_collection(layer_collection_cow,
+ layer_collection_orig);
+ layer_collection_orig = layer_collection_orig->next;
+ layer_collection_cow = layer_collection_cow->next;
+ }
+}
+
+void update_copy_on_write_view_layer(const Depsgraph *depsgraph,
+ ViewLayer *view_layer_cow,
+ const ViewLayer *view_layer_orig)
+{
+ // Update pointers to active base.
+ if (view_layer_orig->basact == NULL) {
+ view_layer_cow->basact = NULL;
+ }
+ else {
+ const Object *obact_orig = view_layer_orig->basact->object;
+ Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id);
+ view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow);
+ }
+ // Update base flags.
+ //
+ // TODO(sergey): We should probably check visibled/selectabled.
+ // flag here?
+ const Base *base_orig = (Base *)view_layer_orig->object_bases.first;
+ Base *base_cow = (Base *)view_layer_cow->object_bases.first;;
+ while (base_orig != NULL) {
+ base_cow->flag = base_orig->flag;
+ base_orig = base_orig->next;
+ base_cow = base_cow->next;
+ }
+ // Synchronize settings.
+ view_layer_cow->active_collection = view_layer_orig->active_collection;
+ view_layer_cow->flag = view_layer_orig->flag;
+ view_layer_cow->layflag = view_layer_orig->layflag;
+ view_layer_cow->passflag = view_layer_orig->passflag;
+ view_layer_cow->pass_alpha_threshold = view_layer_orig->pass_alpha_threshold;
+ // Synchronize ID properties.
+ IDP_Reset(view_layer_cow->properties, view_layer_orig->properties);
+ IDP_Reset(view_layer_cow->id_properties, view_layer_orig->id_properties);
+ // Synchronize layer collections.
+ update_copy_on_write_layer_collections(
+ &view_layer_cow->layer_collections,
+ &view_layer_orig->layer_collections);
+}
+
+void update_copy_on_write_view_layers(const Depsgraph *depsgraph,
+ Scene *scene_cow,
+ const Scene *scene_orig)
+{
+ const ViewLayer *view_layer_orig = (const ViewLayer *)scene_orig->view_layers.first;
+ ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first;
+ while (view_layer_orig != NULL) {
+ update_copy_on_write_view_layer(depsgraph,
+ view_layer_cow,
+ view_layer_orig);
+ view_layer_orig = view_layer_orig->next;
+ view_layer_cow = view_layer_cow->next;
+ }
+}
+
+void update_copy_on_write_scene_collections(
+ ListBase *collections_cow,
+ const ListBase *collections_orig);
+
+void update_copy_on_write_scene_collection(
+ SceneCollection *collection_cow,
+ const SceneCollection *collection_orig)
+{
+ collection_cow->active_object_index = collection_orig->active_object_index;
+ update_copy_on_write_scene_collections(
+ &collection_cow->scene_collections,
+ &collection_orig->scene_collections);
+}
+
+void update_copy_on_write_scene_collections(
+ ListBase *collections_cow,
+ const ListBase *collections_orig)
+{
+ const SceneCollection *nested_collection_orig =
+ (const SceneCollection *)collections_orig->first;
+ SceneCollection *nested_collection_cow =
+ (SceneCollection *)collections_cow->first;
+ while (nested_collection_orig != NULL) {
+ update_copy_on_write_scene_collection(
+ nested_collection_cow,
+ nested_collection_orig);
+ nested_collection_orig = nested_collection_orig->next;
+ nested_collection_cow = nested_collection_cow->next;
+ }
+}
+
/* Update copy-on-write version of scene from original scene. */
void update_copy_on_write_scene(const Depsgraph *depsgraph,
Scene *scene_cow,
@@ -476,33 +608,10 @@ void update_copy_on_write_scene(const Depsgraph *depsgraph,
// TODO(sergey): Are we missing something here?
scene_cow->r.cfra = scene_orig->r.cfra;
scene_cow->r.subframe = scene_orig->r.subframe;
- // Update bases.
- const ViewLayer *view_layer_orig = (ViewLayer *)scene_orig->view_layers.first;
- ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first;
- while (view_layer_orig != NULL) {
- // Update pointers to active base.
- if (view_layer_orig->basact == NULL) {
- view_layer_cow->basact = NULL;
- }
- else {
- const Object *obact_orig = view_layer_orig->basact->object;
- Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id);
- view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow);
- }
- // Update base flags.
- //
- // TODO(sergey): We should probably check visibled/selectabled
- // flag here?
- const Base *base_orig = (Base *)view_layer_orig->object_bases.first;
- Base *base_cow = (Base *)view_layer_cow->object_bases.first;;
- while (base_orig != NULL) {
- base_cow->flag = base_orig->flag;
- base_orig = base_orig->next;
- base_cow = base_cow->next;
- }
- view_layer_orig = view_layer_orig->next;
- view_layer_cow = view_layer_cow->next;
- }
+ // Update view layers and collections.
+ update_copy_on_write_view_layers(depsgraph, scene_cow, scene_orig);
+ update_copy_on_write_scene_collection(scene_cow->collection,
+ scene_orig->collection);
// Update edit object pointer.
if (scene_orig->obedit != NULL) {
scene_cow->obedit = (Object *)depsgraph->get_cow_id(&scene_orig->obedit->id);
@@ -781,7 +890,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
*/
if (mesh_evaluated != NULL) {
if (object->data == mesh_evaluated) {
- object->data = mesh_evaluated->id.newid;
+ object->data = mesh_evaluated->id.orig_id;
}
}
/* Make a backup of base flags. */
@@ -817,7 +926,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
* pointers are left behind.
*/
mesh_evaluated->edit_btmesh =
- ((Mesh *)mesh_evaluated->id.newid)->edit_btmesh;
+ ((Mesh *)mesh_evaluated->id.orig_id)->edit_btmesh;
}
}
if (base_collection_properties != NULL) {
@@ -921,8 +1030,7 @@ bool deg_validate_copy_on_write_datablock(ID *id_cow)
void deg_tag_copy_on_write_id(ID *id_cow, const ID *id_orig)
{
id_cow->tag |= LIB_TAG_COPY_ON_WRITE;
- /* TODO(sergey): Is it safe to re-use newid for original ID link? */
- id_cow->newid = (ID *)id_orig;
+ id_cow->orig_id = (ID *)id_orig;
}
bool deg_copy_on_write_is_expanded(const ID *id_cow)
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index a30812c692f..c0d5e08b80f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -36,6 +36,7 @@
#include <deque>
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
@@ -47,6 +48,7 @@ extern "C" {
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
@@ -70,14 +72,20 @@ typedef std::deque<OperationDepsNode *> FlushQueue;
namespace {
-void flush_init_operation_node_func(void *data_v, int i)
+void flush_init_operation_node_func(
+ void *__restrict data_v,
+ const int i,
+ const ParallelRangeTLS *__restrict /*tls*/)
{
Depsgraph *graph = (Depsgraph *)data_v;
OperationDepsNode *node = graph->operations[i];
node->scheduled = false;
}
-void flush_init_id_node_func(void *data_v, int i)
+void flush_init_id_node_func(
+ void *__restrict data_v,
+ const int i,
+ const ParallelRangeTLS *__restrict /*tls*/)
{
Depsgraph *graph = (Depsgraph *)data_v;
IDDepsNode *id_node = graph->id_nodes[i];
@@ -89,16 +97,26 @@ void flush_init_id_node_func(void *data_v, int i)
BLI_INLINE void flush_prepare(Depsgraph *graph)
{
- const int num_operations = graph->operations.size();
- BLI_task_parallel_range(0, num_operations,
- graph,
- flush_init_operation_node_func,
- (num_operations > 256));
- const int num_id_nodes = graph->id_nodes.size();
- BLI_task_parallel_range(0, num_id_nodes,
- graph,
- flush_init_id_node_func,
- (num_id_nodes > 256));
+ {
+ const int num_operations = graph->operations.size();
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+ BLI_task_parallel_range(0, num_operations,
+ graph,
+ flush_init_operation_node_func,
+ &settings);
+ }
+ {
+ const int num_id_nodes = graph->id_nodes.size();
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+ BLI_task_parallel_range(0, num_id_nodes,
+ graph,
+ flush_init_id_node_func,
+ &settings);
+ }
}
BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
@@ -190,14 +208,27 @@ BLI_INLINE OperationDepsNode *flush_schedule_children(
return result;
}
-BLI_INLINE void flush_editors_id_update(Main *bmain,
- Depsgraph *graph,
- const DEGEditorUpdateContext *update_ctx)
+void flush_engine_data_update(ID *id)
+{
+ if (GS(id->name) != ID_OB) {
+ return;
+ }
+ Object *object = (Object *)id;
+ BLI_LISTBASE_FOREACH(ObjectEngineData *, engine_data, &object->drawdata) {
+ engine_data->recalc |= id->recalc;
+ }
+}
+
+/* NOTE: It will also accumulate flags from changed components. */
+void flush_editors_id_update(Main *bmain,
+ Depsgraph *graph,
+ const DEGEditorUpdateContext *update_ctx)
{
foreach (IDDepsNode *id_node, graph->id_nodes) {
if (id_node->done != ID_STATE_MODIFIED) {
continue;
}
+ DEG_id_type_tag(bmain, GS(id_node->id_orig->name));
/* TODO(sergey): Do we need to pass original or evaluated ID here? */
ID *id_orig = id_node->id_orig;
ID *id_cow = id_node->id_cow;
@@ -205,13 +236,26 @@ BLI_INLINE void flush_editors_id_update(Main *bmain,
* This is because DEG_id_tag_update() sets tags on original
* data.
*/
- id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL);
+ id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL);
+ /* Gather recalc flags from all changed components. */
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ if (comp_node->done != COMPONENT_STATE_DONE) {
+ continue;
+ }
+ DepsNodeFactory *factory = deg_type_get_factory(comp_node->type);
+ BLI_assert(factory != NULL);
+ id_cow->recalc |= factory->id_recalc_tag();
+ }
+ GHASH_FOREACH_END();
+ DEG_DEBUG_PRINTF("Accumulated recalc bits for %s: %u\n",
+ id_orig->name, (unsigned int)id_cow->recalc);
+ /* Inform editors. */
if (deg_copy_on_write_is_expanded(id_cow)) {
deg_editors_id_update(update_ctx, id_cow);
+ /* Inform draw engines that something was changed. */
+ flush_engine_data_update(id_cow);
}
- lib_id_recalc_tag(bmain, id_orig);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_orig);
}
}
@@ -236,11 +280,11 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
FlushQueue queue;
flush_schedule_entrypoints(graph, &queue);
/* Prepare update context for editors. */
- DEGEditorUpdateContext update_ctx = {
- bmain,
- graph->scene,
- graph->view_layer,
- };
+ DEGEditorUpdateContext update_ctx;
+ update_ctx.bmain = bmain;
+ update_ctx.depsgraph = (::Depsgraph *)graph;
+ update_ctx.scene = graph->scene;
+ update_ctx.view_layer = graph->view_layer;
/* Do actual flush. */
while (!queue.empty()) {
OperationDepsNode *op_node = queue.front();
@@ -265,7 +309,10 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
flush_editors_id_update(bmain, graph, &update_ctx);
}
-static void graph_clear_func(void *data_v, int i)
+static void graph_clear_func(
+ void *__restrict data_v,
+ const int i,
+ const ParallelRangeTLS *__restrict /*tls*/)
{
Depsgraph *graph = (Depsgraph *)data_v;
OperationDepsNode *node = graph->operations[i];
@@ -278,8 +325,13 @@ void deg_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+ BLI_task_parallel_range(0, num_operations,
+ graph,
+ graph_clear_func,
+ &settings);
/* Clear any entry tags which haven't been flushed. */
BLI_gset_clear(graph->entry_tags, NULL);
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
new file mode 100644
index 00000000000..52ce744cc0a
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
@@ -0,0 +1,70 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_stats.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_stats.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "intern/depsgraph.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void deg_eval_stats_aggregate(Depsgraph *graph)
+{
+ /* Reset current evaluation stats for ID and component nodes.
+ * Those are not filled in by the evaluation engine.
+ */
+ foreach (DepsNode *node, graph->id_nodes) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ comp_node->stats.reset_current();
+ }
+ GHASH_FOREACH_END();
+ id_node->stats.reset_current();
+ }
+ /* Now accumulate operation timings to components and IDs. */
+ foreach (OperationDepsNode *op_node, graph->operations) {
+ ComponentDepsNode *comp_node = op_node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+ id_node->stats.current_time += op_node->stats.current_time;
+ comp_node->stats.current_time += op_node->stats.current_time;
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.h b/source/blender/depsgraph/intern/eval/deg_eval_stats.h
new file mode 100644
index 00000000000..8a7272ac89c
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_stats.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Aggregate operation timings to overall component and ID nodes timing. */
+void deg_eval_stats_aggregate(Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 5f83d02082b..fdcfc129073 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -31,48 +31,57 @@
#include "intern/nodes/deg_node.h"
#include <stdio.h>
-#include <cstring> /* required for STREQ later on. */
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
-extern "C" {
-#include "DNA_ID.h"
-#include "DNA_anim_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_animsys.h"
-#include "BKE_library.h"
-}
-
-#include "DEG_depsgraph.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
+#include "intern/nodes/deg_node_time.h"
#include "intern/depsgraph_intern.h"
+
#include "util/deg_util_foreach.h"
#include "util/deg_util_function.h"
namespace DEG {
-/* *************** */
-/* Node Management */
+/*******************************************************************************
+ * Type information.
+ */
-/* Add ------------------------------------------------ */
+DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type,
+ const char *tname,
+ int id_recalc_tag)
+ : type(type),
+ tname(tname),
+ id_recalc_tag(id_recalc_tag)
+{
+}
-DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
+/*******************************************************************************
+ * Evaluation statistics.
+ */
+
+DepsNode::Stats::Stats()
{
- this->type = type;
- if (type == DEG_NODE_TYPE_OPERATION)
- this->tclass = DEG_NODE_CLASS_OPERATION;
- else if (type < DEG_NODE_TYPE_PARAMETERS)
- this->tclass = DEG_NODE_CLASS_GENERIC;
- else
- this->tclass = DEG_NODE_CLASS_COMPONENT;
- this->tname = tname;
+ reset();
}
+void DepsNode::Stats::reset()
+{
+ current_time = 0.0;
+}
+
+void DepsNode::Stats::reset_current()
+{
+ current_time = 0.0;
+}
+
+/*******************************************************************************
+ * Node itself.
+ */
+
DepsNode::DepsNode()
{
name = "";
@@ -100,216 +109,24 @@ string DepsNode::identifier() const
return string(typebuf) + " : " + name;
}
-/* ************* */
-/* Generic Nodes */
-
-/* Time Source Node ============================================== */
-
-void TimeSourceDepsNode::tag_update(Depsgraph *graph)
-{
- foreach (DepsRelation *rel, outlinks) {
- DepsNode *node = rel->to;
- node->tag_update(graph);
- }
-}
-
-/* Time Source Node ======================================= */
-
-DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source");
-static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
-
-/* ID Node ================================================ */
-
-IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type,
- const char *name)
- : type(type), name(name)
-{
-}
-
-bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const
-{
- return type == other.type &&
- STREQ(name, other.name);
-}
-
-static unsigned int id_deps_node_hash_key(const void *key_v)
-{
- const IDDepsNode::ComponentIDKey *key =
- reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
- return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type),
- BLI_ghashutil_strhash_p(key->name));
-}
-
-static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
-{
- const IDDepsNode::ComponentIDKey *key_a =
- reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a);
- const IDDepsNode::ComponentIDKey *key_b =
- reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b);
- return !(*key_a == *key_b);
-}
-
-static void id_deps_node_hash_key_free(void *key_v)
-{
- typedef IDDepsNode::ComponentIDKey ComponentIDKey;
- ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
- OBJECT_GUARDED_DELETE(key, ComponentIDKey);
-}
-
-static void id_deps_node_hash_value_free(void *value_v)
-{
- ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v);
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
-}
-
-/* Initialize 'id' node - from pointer data given. */
-void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
-{
- BLI_assert(id != NULL);
- /* Store ID-pointer. */
- id_orig = (ID *)id;
- eval_flags = 0;
- linked_state = DEG_ID_LINKED_INDIRECTLY;
-
- components = BLI_ghash_new(id_deps_node_hash_key,
- id_deps_node_hash_key_cmp,
- "Depsgraph id components hash");
-}
-
-void IDDepsNode::init_copy_on_write(ID *id_cow_hint)
-{
- /* Early output for non-copy-on-write case: we keep CoW pointer same as
- * an original one.
- */
- if (!DEG_depsgraph_use_copy_on_write()) {
- UNUSED_VARS(id_cow_hint);
- id_cow = id_orig;
- return;
+eDepsNode_Class DepsNode::get_class() const {
+ if (type == DEG_NODE_TYPE_OPERATION) {
+ return DEG_NODE_CLASS_OPERATION;
}
- /* Create pointer as early as possible, so we can use it for function
- * bindings. Rest of data we'll be copying to the new datablock when
- * it is actually needed.
- */
- if (id_cow_hint != NULL) {
- // BLI_assert(deg_copy_on_write_is_needed(id_orig));
- if (deg_copy_on_write_is_needed(id_orig)) {
- id_cow = id_cow_hint;
- }
- else {
- id_cow = id_orig;
- }
- }
- else if (deg_copy_on_write_is_needed(id_orig)) {
- id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name));
- DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n",
- id_orig->name, id_orig, id_cow);
- deg_tag_copy_on_write_id(id_cow, id_orig);
+ else if (type < DEG_NODE_TYPE_PARAMETERS) {
+ return DEG_NODE_CLASS_GENERIC;
}
else {
- id_cow = id_orig;
- }
-}
-
-/* Free 'id' node. */
-IDDepsNode::~IDDepsNode()
-{
- destroy();
-}
-
-void IDDepsNode::destroy()
-{
- if (id_orig == NULL) {
- return;
- }
-
- BLI_ghash_free(components,
- id_deps_node_hash_key_free,
- id_deps_node_hash_value_free);
-
- /* Free memory used by this CoW ID. */
- if (id_cow != id_orig && id_cow != NULL) {
- deg_free_copy_on_write_datablock(id_cow);
- MEM_freeN(id_cow);
- DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n",
- id_orig->name, id_orig, id_cow);
- }
-
- /* Tag that the node is freed. */
- id_orig = NULL;
-}
-
-ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
- const char *name) const
-{
- ComponentIDKey key(type, name);
- return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
-}
-
-ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
- const char *name)
-{
- ComponentDepsNode *comp_node = find_component(type, name);
- if (!comp_node) {
- DepsNodeFactory *factory = deg_get_node_factory(type);
- comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name);
-
- /* Register. */
- ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
- BLI_ghash_insert(components, key, comp_node);
- comp_node->owner = this;
+ return DEG_NODE_CLASS_COMPONENT;
}
- return comp_node;
}
-void IDDepsNode::tag_update(Depsgraph *graph)
-{
- GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
- {
- /* TODO(sergey): What about drivers? */
- bool do_component_tag = comp_node->type != DEG_NODE_TYPE_ANIMATION;
- if (comp_node->type == DEG_NODE_TYPE_ANIMATION) {
- AnimData *adt = BKE_animdata_from_id(id_orig);
- /* Animation data might be null if relations are tagged for update. */
- if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM)) {
- do_component_tag = true;
- }
- }
- else if (comp_node->type == DEG_NODE_TYPE_SHADING) {
- /* TODO(sergey): For until we properly handle granular flags for DEG_id_tag_update()
- * we skip flushing here to keep Luca happy.
- */
- if (GS(id_orig->name) != ID_MA &&
- GS(id_orig->name) != ID_WO)
- {
- do_component_tag = false;
- }
- }
- else if (comp_node->type == DEG_NODE_TYPE_SHADING_PARAMETERS) {
- do_component_tag = false;
- }
- else if (comp_node->type == DEG_NODE_TYPE_EVAL_PARTICLES) {
- /* Only do explicit particle settings tagging. */
- do_component_tag = false;
- }
- else if (comp_node->type == DEG_NODE_TYPE_BATCH_CACHE) {
- do_component_tag = false;
- }
- if (do_component_tag) {
- comp_node->tag_update(graph);
- }
- }
- GHASH_FOREACH_END();
-}
-
-void IDDepsNode::finalize_build(Depsgraph *graph)
-{
- /* Finalize build of all components. */
- GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
- {
- comp_node->finalize_build(graph);
- }
- GHASH_FOREACH_END();
-}
+/*******************************************************************************
+ * Generic nodes definition.
+ */
+\
+DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source");
+static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
DEG_DEPSNODE_DEFINE(IDDepsNode, DEG_NODE_TYPE_ID_REF, "ID Node");
static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index fd3ed694c9c..603a6be7ceb 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -51,22 +51,24 @@ struct OperationDepsNode;
struct DepsNode {
/* Helper class for static typeinfo in subclasses. */
struct TypeInfo {
- TypeInfo(eDepsNode_Type type, const char *tname);
-
+ TypeInfo(eDepsNode_Type type, const char *tname, int id_recalc_tag = 0);
eDepsNode_Type type;
- eDepsNode_Class tclass;
const char *tname;
+ int id_recalc_tag;
+ };
+ struct Stats {
+ Stats();
+ /* Reset all the counters. Including all stats needed for average
+ * evaluation time calculation.
+ */
+ void reset();
+ /* Reset counters needed for the current graph evaluation, does not
+ * touch averaging accumulators.
+ */
+ void reset_current();
+ /* Time spend on this node during current graph evaluation. */
+ double current_time;
};
-
- /* Identifier - mainly for debugging purposes. */
- const char *name;
-
- /* Structural type of node. */
- eDepsNode_Type type;
-
- /* Type of data/behaviour represented by node... */
- eDepsNode_Class tclass;
-
/* Relationships between nodes
* The reason why all depsgraph nodes are descended from this type (apart
* from basic serialization benefits - from the typeinfo) is that we can have
@@ -74,23 +76,18 @@ struct DepsNode {
*/
typedef vector<DepsRelation *> Relations;
- /* Nodes which this one depends on. */
- Relations inlinks;
-
- /* Nodes which depend on this one. */
- Relations outlinks;
-
- /* Generic tags for traversal algorithms. */
- int done;
- int tag;
+ const char *name; /* Identifier - mainly for debugging purposes. */
+ eDepsNode_Type type; /* Structural type of node. */
+ Relations inlinks; /* Nodes which this one depends on. */
+ Relations outlinks; /* Nodes which depend on this one. */
+ int done; /* Generic tags for traversal algorithms. */
+ Stats stats; /* Evaluation statistics. */
/* Methods. */
-
DepsNode();
virtual ~DepsNode();
virtual string identifier() const;
- string full_identifier() const;
virtual void init(const ID * /*id*/,
const char * /*subdata*/) {}
@@ -99,6 +96,8 @@ struct DepsNode {
virtual OperationDepsNode *get_entry_operation() { return NULL; }
virtual OperationDepsNode *get_exit_operation() { return NULL; }
+
+ virtual eDepsNode_Class get_class() const;
};
/* Macros for common static typeinfo. */
@@ -107,68 +106,6 @@ struct DepsNode {
#define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \
const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_)
-/* Generic Nodes ======================= */
-
-struct ComponentDepsNode;
-struct IDDepsNode;
-
-/* Time Source Node. */
-struct TimeSourceDepsNode : public DepsNode {
- /* New "current time". */
- float cfra;
-
- /* time-offset relative to the "official" time source that this one has. */
- float offset;
-
- // TODO: evaluate() operation needed
-
- void tag_update(Depsgraph *graph);
-
- DEG_DEPSNODE_DECLARE;
-};
-
-/* ID-Block Reference */
-struct IDDepsNode : public DepsNode {
- struct ComponentIDKey {
- ComponentIDKey(eDepsNode_Type type, const char *name = "");
- bool operator==(const ComponentIDKey &other) const;
-
- eDepsNode_Type type;
- const char *name;
- };
-
- void init(const ID *id, const char *subdata);
- void init_copy_on_write(ID *id_cow_hint = NULL);
- ~IDDepsNode();
- void destroy();
-
- ComponentDepsNode *find_component(eDepsNode_Type type,
- const char *name = "") const;
- ComponentDepsNode *add_component(eDepsNode_Type type,
- const char *name = "");
-
- void tag_update(Depsgraph *graph);
-
- void finalize_build(Depsgraph *graph);
-
- /* ID Block referenced. */
- ID *id_orig;
- ID *id_cow;
-
- /* Hash to make it faster to look up components. */
- GHash *components;
-
- /* Additional flags needed for scene evaluation.
- * TODO(sergey): Only needed for until really granular updates
- * of all the entities.
- */
- int eval_flags;
-
- eDepsNode_LinkedState_Type linked_state;
-
- DEG_DEPSNODE_DECLARE;
-};
-
void deg_register_base_depsnodes();
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 01181453982..1f56edd1f87 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -42,6 +42,7 @@ extern "C" {
#include "BKE_action.h"
} /* extern "C" */
+#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
@@ -227,7 +228,7 @@ OperationDepsNode *ComponentDepsNode::add_operation(const DepsEvalOperationCb& o
{
OperationDepsNode *op_node = find_operation(opcode, name, name_tag);
if (!op_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_OPERATION);
+ DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id_orig, "", name);
/* register opnode in this component's operation set */
@@ -355,30 +356,6 @@ void ComponentDepsNode::finalize_build(Depsgraph * /*graph*/)
operations_map = NULL;
}
-/* Register all components. =============================== */
-
-#define DEG_COMPONENT_DEFINE(name, NAME) \
- DEG_DEPSNODE_DEFINE(name ## ComponentDepsNode, \
- DEG_NODE_TYPE_ ## NAME, \
- #name " Component"); \
-static DepsNodeFactoryImpl<name ## ComponentDepsNode> DNTI_ ## NAME
-
-
-DEG_COMPONENT_DEFINE(Animation, ANIMATION);
-DEG_COMPONENT_DEFINE(BatchCache, BATCH_CACHE);
-DEG_COMPONENT_DEFINE(Cache, CACHE);
-DEG_COMPONENT_DEFINE(CopyOnWrite, COPY_ON_WRITE);
-DEG_COMPONENT_DEFINE(Geometry, GEOMETRY);
-DEG_COMPONENT_DEFINE(LayerCollections, LAYER_COLLECTIONS);
-DEG_COMPONENT_DEFINE(Parameters, PARAMETERS);
-DEG_COMPONENT_DEFINE(Particles, EVAL_PARTICLES);
-DEG_COMPONENT_DEFINE(Proxy, PROXY);
-DEG_COMPONENT_DEFINE(Pose, EVAL_POSE);
-DEG_COMPONENT_DEFINE(Sequencer, SEQUENCER);
-DEG_COMPONENT_DEFINE(Shading, SHADING);
-DEG_COMPONENT_DEFINE(ShadingParameters, SHADING_PARAMETERS);
-DEG_COMPONENT_DEFINE(Transform, TRANSFORM);
-
/* Bone Component ========================================= */
/* Initialize 'bone component' node - from pointer data given */
@@ -398,7 +375,23 @@ void BoneComponentDepsNode::init(const ID *id, const char *subdata)
this->pchan = BKE_pose_channel_find_name(object->pose, subdata);
}
-DEG_COMPONENT_DEFINE(Bone, BONE);
+/* Register all components. =============================== */
+
+DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION);
+DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_DRAW_CACHE);
+DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_WRITE, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, ID_RECALC_COLLECTIONS);
+DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(Particles, EVAL_PARTICLES, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_DRAW);
+DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_DRAW);
+DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM);
/* Node Types Register =================================== */
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index ba4f8551fea..b8009cc0a7f 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -46,6 +46,7 @@ namespace DEG {
struct Depsgraph;
struct OperationDepsNode;
struct BoneComponentDepsNode;
+struct IDDepsNode;
/* ID Component - Base type for all components */
struct ComponentDepsNode : public DepsNode {
@@ -123,19 +124,6 @@ struct ComponentDepsNode : public DepsNode {
void tag_update(Depsgraph *graph);
- /* Evaluation Context Management .................. */
-
- /* Initialize component's evaluation context used for the specified
- * purpose.
- */
- virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
- /* Free data in component's evaluation context which is used for
- * the specified purpose
- *
- * NOTE: this does not free the actual context in question
- */
- virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
-
OperationDepsNode *get_entry_operation();
OperationDepsNode *get_exit_operation();
@@ -164,25 +152,38 @@ struct ComponentDepsNode : public DepsNode {
/* ---------------------------------------- */
-#define DEG_COMPONENT_DECLARE_GENERIC(name) \
+#define DEG_COMPONENT_NODE_DEFINE_TYPEINFO(NodeType, type_, tname_, id_recalc_tag) \
+ const DepsNode::TypeInfo NodeType::typeinfo = \
+ DepsNode::TypeInfo(type_, tname_, id_recalc_tag)
+
+#define DEG_COMPONENT_NODE_DECLARE DEG_DEPSNODE_DECLARE
+
+#define DEG_COMPONENT_NODE_DEFINE(name, NAME, id_recalc_tag) \
+ DEG_COMPONENT_NODE_DEFINE_TYPEINFO(name ## ComponentDepsNode, \
+ DEG_NODE_TYPE_ ## NAME, \
+ #name " Component", \
+ id_recalc_tag) ; \
+ static DepsNodeFactoryImpl<name ## ComponentDepsNode> DNTI_ ## NAME
+
+#define DEG_COMPONENT_NODE_DECLARE_GENERIC(name) \
struct name ## ComponentDepsNode : public ComponentDepsNode { \
- DEG_DEPSNODE_DECLARE; \
+ DEG_COMPONENT_NODE_DECLARE; \
}
-DEG_COMPONENT_DECLARE_GENERIC(Animation);
-DEG_COMPONENT_DECLARE_GENERIC(BatchCache);
-DEG_COMPONENT_DECLARE_GENERIC(Cache);
-DEG_COMPONENT_DECLARE_GENERIC(CopyOnWrite);
-DEG_COMPONENT_DECLARE_GENERIC(Geometry);
-DEG_COMPONENT_DECLARE_GENERIC(LayerCollections);
-DEG_COMPONENT_DECLARE_GENERIC(Parameters);
-DEG_COMPONENT_DECLARE_GENERIC(Particles);
-DEG_COMPONENT_DECLARE_GENERIC(Proxy);
-DEG_COMPONENT_DECLARE_GENERIC(Pose);
-DEG_COMPONENT_DECLARE_GENERIC(Sequencer);
-DEG_COMPONENT_DECLARE_GENERIC(Shading);
-DEG_COMPONENT_DECLARE_GENERIC(ShadingParameters);
-DEG_COMPONENT_DECLARE_GENERIC(Transform);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(BatchCache);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Parameters);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Proxy);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Sequencer);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Shading);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform);
/* Bone Component */
struct BoneComponentDepsNode : public ComponentDepsNode {
@@ -190,7 +191,7 @@ struct BoneComponentDepsNode : public ComponentDepsNode {
struct bPoseChannel *pchan; /* the bone that this component represents */
- DEG_DEPSNODE_DECLARE;
+ DEG_COMPONENT_NODE_DECLARE;
};
void deg_register_component_depsnodes();
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.cc b/source/blender/depsgraph/intern/nodes/deg_node_id.cc
new file mode 100644
index 00000000000..edc5c0114f9
--- /dev/null
+++ b/source/blender/depsgraph/intern/nodes/deg_node_id.cc
@@ -0,0 +1,217 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/nodes/deg_node_id.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/nodes/deg_node_id.h"
+
+#include <stdio.h>
+#include <cstring> /* required for STREQ later on. */
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+extern "C" {
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_library.h"
+}
+
+#include "DEG_depsgraph.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
+#include "intern/nodes/deg_node_time.h"
+#include "intern/depsgraph_intern.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type,
+ const char *name)
+ : type(type), name(name)
+{
+}
+
+bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const
+{
+ return type == other.type &&
+ STREQ(name, other.name);
+}
+
+static unsigned int id_deps_node_hash_key(const void *key_v)
+{
+ const IDDepsNode::ComponentIDKey *key =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type),
+ BLI_ghashutil_strhash_p(key->name));
+}
+
+static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
+{
+ const IDDepsNode::ComponentIDKey *key_a =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a);
+ const IDDepsNode::ComponentIDKey *key_b =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void id_deps_node_hash_key_free(void *key_v)
+{
+ typedef IDDepsNode::ComponentIDKey ComponentIDKey;
+ ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, ComponentIDKey);
+}
+
+static void id_deps_node_hash_value_free(void *value_v)
+{
+ ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+}
+
+/* Initialize 'id' node - from pointer data given. */
+void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
+{
+ BLI_assert(id != NULL);
+ /* Store ID-pointer. */
+ id_orig = (ID *)id;
+ eval_flags = 0;
+ linked_state = DEG_ID_LINKED_INDIRECTLY;
+
+ components = BLI_ghash_new(id_deps_node_hash_key,
+ id_deps_node_hash_key_cmp,
+ "Depsgraph id components hash");
+}
+
+void IDDepsNode::init_copy_on_write(ID *id_cow_hint)
+{
+ /* Early output for non-copy-on-write case: we keep CoW pointer same as
+ * an original one.
+ */
+ if (!DEG_depsgraph_use_copy_on_write()) {
+ UNUSED_VARS(id_cow_hint);
+ id_cow = id_orig;
+ return;
+ }
+ /* Create pointer as early as possible, so we can use it for function
+ * bindings. Rest of data we'll be copying to the new datablock when
+ * it is actually needed.
+ */
+ if (id_cow_hint != NULL) {
+ // BLI_assert(deg_copy_on_write_is_needed(id_orig));
+ if (deg_copy_on_write_is_needed(id_orig)) {
+ id_cow = id_cow_hint;
+ }
+ else {
+ id_cow = id_orig;
+ }
+ }
+ else if (deg_copy_on_write_is_needed(id_orig)) {
+ id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name));
+ DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+ deg_tag_copy_on_write_id(id_cow, id_orig);
+ }
+ else {
+ id_cow = id_orig;
+ }
+}
+
+/* Free 'id' node. */
+IDDepsNode::~IDDepsNode()
+{
+ destroy();
+}
+
+void IDDepsNode::destroy()
+{
+ if (id_orig == NULL) {
+ return;
+ }
+
+ BLI_ghash_free(components,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
+
+ /* Free memory used by this CoW ID. */
+ if (id_cow != id_orig && id_cow != NULL) {
+ deg_free_copy_on_write_datablock(id_cow);
+ MEM_freeN(id_cow);
+ DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+ }
+
+ /* Tag that the node is freed. */
+ id_orig = NULL;
+}
+
+ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
+ const char *name) const
+{
+ ComponentIDKey key(type, name);
+ return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
+}
+
+ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
+ const char *name)
+{
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (!comp_node) {
+ DepsNodeFactory *factory = deg_type_get_factory(type);
+ comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name);
+
+ /* Register. */
+ ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
+ BLI_ghash_insert(components, key, comp_node);
+ comp_node->owner = this;
+ }
+ return comp_node;
+}
+
+void IDDepsNode::tag_update(Depsgraph *graph)
+{
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
+ {
+ comp_node->tag_update(graph);
+ }
+ GHASH_FOREACH_END();
+}
+
+void IDDepsNode::finalize_build(Depsgraph *graph)
+{
+ /* Finalize build of all components. */
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
+ {
+ comp_node->finalize_build(graph);
+ }
+ GHASH_FOREACH_END();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.h b/source/blender/depsgraph/intern/nodes/deg_node_id.h
new file mode 100644
index 00000000000..505a1129192
--- /dev/null
+++ b/source/blender/depsgraph/intern/nodes/deg_node_id.h
@@ -0,0 +1,81 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file depsgraph/intern/nodes/deg_node_id.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/nodes/deg_node.h"
+
+namespace DEG {
+
+struct ComponentDepsNode;
+
+/* ID-Block Reference */
+struct IDDepsNode : public DepsNode {
+ struct ComponentIDKey {
+ ComponentIDKey(eDepsNode_Type type, const char *name = "");
+ bool operator==(const ComponentIDKey &other) const;
+
+ eDepsNode_Type type;
+ const char *name;
+ };
+
+ void init(const ID *id, const char *subdata);
+ void init_copy_on_write(ID *id_cow_hint = NULL);
+ ~IDDepsNode();
+ void destroy();
+
+ ComponentDepsNode *find_component(eDepsNode_Type type,
+ const char *name = "") const;
+ ComponentDepsNode *add_component(eDepsNode_Type type,
+ const char *name = "");
+
+ void tag_update(Depsgraph *graph);
+
+ void finalize_build(Depsgraph *graph);
+
+ /* ID Block referenced. */
+ ID *id_orig;
+ ID *id_cow;
+
+ /* Hash to make it faster to look up components. */
+ GHash *components;
+
+ /* Additional flags needed for scene evaluation.
+ * TODO(sergey): Only needed for until really granular updates
+ * of all the entities.
+ */
+ int eval_flags;
+
+ eDepsNode_LinkedState_Type linked_state;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 7467264f612..cbc0fbb4241 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -37,6 +37,7 @@
#include "intern/depsgraph.h"
#include "intern/depsgraph_intern.h"
+#include "intern/nodes/deg_node_id.h"
namespace DEG {
@@ -44,7 +45,6 @@ namespace DEG {
/* Inner Nodes */
OperationDepsNode::OperationDepsNode() :
- eval_priority(0.0f),
flag(0),
customdata_mask(0)
{
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index d8203540fc5..c172f73be5f 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -38,6 +38,8 @@ struct Depsgraph;
namespace DEG {
+struct ComponentDepsNode;
+
/* Flags for Depsgraph Nodes */
typedef enum eDepsOperation_Flag {
/* node needs to be updated */
@@ -74,7 +76,6 @@ struct OperationDepsNode : public DepsNode {
/* How many inlinks are we still waiting on before we can be evaluated. */
uint32_t num_links_pending;
- float eval_priority;
bool scheduled;
/* Identifier for the operation being performed. */
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.cc b/source/blender/depsgraph/intern/nodes/deg_node_time.cc
new file mode 100644
index 00000000000..230488b2328
--- /dev/null
+++ b/source/blender/depsgraph/intern/nodes/deg_node_time.cc
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/nodes/deg_node_time.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/nodes/deg_node_time.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void TimeSourceDepsNode::tag_update(Depsgraph *graph)
+{
+ foreach (DepsRelation *rel, outlinks) {
+ DepsNode *node = rel->to;
+ node->tag_update(graph);
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.h b/source/blender/depsgraph/intern/nodes/deg_node_time.h
new file mode 100644
index 00000000000..93f3edef9cf
--- /dev/null
+++ b/source/blender/depsgraph/intern/nodes/deg_node_time.h
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file depsgraph/intern/nodes/deg_node_time.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/nodes/deg_node.h"
+
+namespace DEG {
+
+/* Time Source Node. */
+struct TimeSourceDepsNode : public DepsNode {
+ /* New "current time". */
+ float cfra;
+
+ /* time-offset relative to the "official" time source that this one has. */
+ float offset;
+
+ // TODO: evaluate() operation needed
+
+ void tag_update(Depsgraph *graph);
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+} // namespace DEG
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 8339b6b8720..1bff4b875ce 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_common.c
+ intern/draw_instance_data.c
intern/draw_manager.c
intern/draw_manager_text.c
intern/draw_manager_profiling.c
@@ -93,6 +94,7 @@ set(SRC
engines/eevee/eevee_materials.c
engines/eevee/eevee_motion_blur.c
engines/eevee/eevee_occlusion.c
+ engines/eevee/eevee_render.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
@@ -104,6 +106,7 @@ set(SRC
intern/draw_cache.h
intern/draw_cache_impl.h
intern/draw_common.h
+ intern/draw_instance_data.h
intern/draw_manager_text.h
intern/draw_manager_profiling.h
intern/draw_view.h
@@ -133,6 +136,7 @@ data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/concentric_samples_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
@@ -181,6 +185,7 @@ data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_geom.glsl SRC)
@@ -202,6 +207,7 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_frag.glsl SRC)
+data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_lattice_overlay_loosevert_vert.glsl SRC)
@@ -216,7 +222,6 @@ data_to_c_simple(modes/shaders/object_grid_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_lightprobe_grid_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_prim_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC)
data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index ba0f8681f10..c4946e2a4b8 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -30,6 +30,7 @@ struct ARegion;
struct CollectionEngineSettings;
struct Depsgraph;
struct DRWPass;
+struct DRWInstanceDataList;
struct Main;
struct Material;
struct Scene;
@@ -44,6 +45,8 @@ struct ViewportEngineData;
struct View3D;
struct rcti;
struct GPUOffScreen;
+struct GPUViewport;
+struct RenderEngine;
struct RenderEngineType;
struct WorkSpace;
@@ -65,6 +68,7 @@ typedef struct DefaultTextureList {
void DRW_engines_register(void);
void DRW_engines_free(void);
+bool DRW_engine_render_support(struct DrawEngineType *draw_engine_type);
void DRW_engine_register(struct DrawEngineType *draw_engine_type);
void DRW_engine_viewport_data_size_get(
const void *engine_type,
@@ -72,6 +76,7 @@ void DRW_engine_viewport_data_size_get(
typedef struct DRWUpdateContext {
struct Main *bmain;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct ViewLayer *view_layer;
struct ARegion *ar;
@@ -84,28 +89,32 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id);
void DRW_draw_view(const struct bContext *C);
void DRW_draw_render_loop_ex(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *ar, struct View3D *v3d,
const struct bContext *evil_C);
void DRW_draw_render_loop(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d);
void DRW_draw_render_loop_offscreen(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *ar, struct View3D *v3d,
- struct GPUOffScreen *ofs);
+ const bool draw_background,
+ struct GPUOffScreen *ofs,
+ struct GPUViewport *viewport);
void DRW_draw_select_loop(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d,
bool use_obedit_skip, bool use_nearest, const struct rcti *rect);
void DRW_draw_depth_loop(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d);
/* This is here because GPUViewport needs it */
void DRW_pass_free(struct DRWPass *pass);
+struct DRWInstanceDataList *DRW_instance_data_list_create(void);
+void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist);
/* Mode engines initialization */
void OBJECT_collection_settings_create(struct IDProperty *properties);
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 10dfe7b5996..31a431e3001 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -264,6 +264,7 @@ DrawEngineType draw_engine_basic_type = {
&basic_draw_scene,
NULL,
NULL,
+ NULL,
};
/* Note: currently unused, we may want to register so we can see this when debugging the view. */
diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c
index 01f89ae6b1c..d2bf164efdc 100644
--- a/source/blender/draw/engines/clay/clay_engine.c
+++ b/source/blender/draw/engines/clay/clay_engine.c
@@ -183,6 +183,7 @@ typedef struct CLAY_PrivateData {
DRWShadingGroup *depth_shgrp_cull;
DRWShadingGroup *depth_shgrp_cull_select;
DRWShadingGroup *depth_shgrp_cull_active;
+ bool enable_ao;
} CLAY_PrivateData; /* Transient data */
/* Functions */
@@ -317,7 +318,7 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
jitter[i][2] = bn * num_samples_inv;
}
- UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx);
+ UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
return DRW_texture_create_2D(64, 64, DRW_TEX_RGB_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
}
@@ -607,7 +608,7 @@ static int hair_mat_in_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *
return id;
}
-static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo)
+static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_needs_ao)
{
IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
@@ -622,6 +623,12 @@ static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo)
float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation");
int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
+ if (((ssao_factor_cavity > 0.0) || (ssao_factor_edge > 0.0)) &&
+ (ssao_distance > 0.0))
+ {
+ *r_needs_ao = true;
+ }
+
memset(r_ubo, 0x0, sizeof(*r_ubo));
r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
@@ -667,7 +674,7 @@ static DRWShadingGroup *CLAY_object_shgrp_get(
DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps;
CLAY_UBO_Material mat_ubo_test;
- ubo_mat_from_object(ob, &mat_ubo_test);
+ ubo_mat_from_object(ob, &mat_ubo_test, &stl->g_data->enable_ao);
int id = mat_in_ubo(stl->storage, &mat_ubo_test);
@@ -712,6 +719,9 @@ static void clay_cache_init(void *vedata)
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
}
+ /* Disable AO unless a material needs it. */
+ stl->g_data->enable_ao = false;
+
/* Depth Pass */
{
psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
@@ -746,12 +756,45 @@ static void clay_cache_init(void *vedata)
}
}
+static void clay_cache_populate_particles(void *vedata, Object *ob)
+{
+ CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
+ CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+
+ Scene *scene = draw_ctx->scene;
+ Object *obedit = scene->obedit;
+
+ if (ob != obedit) {
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys_check_enabled(ob, psys, false)) {
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
+ draw_as = PART_DRAW_DOT;
+ }
+
+ static float mat[4][4];
+ unit_m4(mat);
+
+ if (draw_as == PART_DRAW_PATH) {
+ struct Gwn_Batch *geom = DRW_cache_particles_get_hair(psys, NULL);
+ DRWShadingGroup *hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl);
+ DRW_shgroup_call_add(hair_shgrp, geom, mat);
+ }
+ }
+ }
+ }
+}
+
static void clay_cache_populate(void *vedata, Object *ob)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
- DRWShadingGroup *clay_shgrp, *hair_shgrp;
+ DRWShadingGroup *clay_shgrp;
if (!DRW_object_is_renderable(ob))
return;
@@ -764,6 +807,15 @@ static void clay_cache_populate(void *vedata, Object *ob)
}
}
+ /* Handle particles first in case the emitter itself shouldn't be rendered. */
+ if (ob->type == OB_MESH) {
+ clay_cache_populate_particles(vedata, ob);
+ }
+
+ if (DRW_check_object_visible_within_active_context(ob) == false) {
+ return;
+ }
+
struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
@@ -797,33 +849,6 @@ static void clay_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat);
}
}
-
- if (ob->type == OB_MESH) {
- Scene *scene = draw_ctx->scene;
- Object *obedit = scene->obedit;
-
- if (ob != obedit) {
- for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys_check_enabled(ob, psys, false)) {
- ParticleSettings *part = psys->part;
- int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
-
- if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
- draw_as = PART_DRAW_DOT;
- }
-
- static float mat[4][4];
- unit_m4(mat);
-
- if (draw_as == PART_DRAW_PATH) {
- geom = DRW_cache_particles_get_hair(psys, NULL);
- hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl);
- DRW_shgroup_call_add(hair_shgrp, geom, mat);
- }
- }
- }
- }
- }
}
static void clay_cache_finish(void *vedata)
@@ -836,18 +861,25 @@ static void clay_cache_finish(void *vedata)
static void clay_draw_scene(void *vedata)
{
-
+ CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
/* Pass 1 : Depth pre-pass */
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
+ if (stl->g_data->enable_ao) {
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+ }
+ else {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ DRW_pass_state_set(psl->clay_pass, state);
+ DRW_pass_state_set(psl->clay_pass_flat, state);
+ }
/* Pass 2 : Duplicate depth */
/* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */
- if (DRW_state_is_fbo()) {
+ if (DRW_state_is_fbo() && stl->g_data->enable_ao) {
/* attach temp textures */
DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0);
@@ -917,6 +949,7 @@ DrawEngineType draw_engine_clay_type = {
&clay_draw_scene,
NULL,
NULL,
+ NULL,
};
RenderEngineType DRW_engine_viewport_clay_type = {
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index d5582a498a4..c6e5f645f10 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -45,13 +45,17 @@ static void eevee_view_layer_data_free(void *storage)
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
- BLI_freelistN(&sldata->shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
/* Probes */
MEM_SAFE_FREE(sldata->probes);
DRW_UBO_FREE_SAFE(sldata->probe_ubo);
DRW_UBO_FREE_SAFE(sldata->grid_ubo);
DRW_UBO_FREE_SAFE(sldata->planar_ubo);
+ DRW_UBO_FREE_SAFE(sldata->common_ubo);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
@@ -59,24 +63,6 @@ static void eevee_view_layer_data_free(void *storage)
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
-
- /* Volumetrics */
- MEM_SAFE_FREE(sldata->volumetrics);
-}
-
-static void eevee_lamp_data_free(void *storage)
-{
- EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)storage;
-
- MEM_SAFE_FREE(led->storage);
- BLI_freelistN(&led->shadow_caster_list);
-}
-
-static void eevee_lightprobe_data_free(void *storage)
-{
- EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)storage;
-
- BLI_freelistN(&ped->captured_object_list);
}
EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void)
@@ -97,59 +83,95 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void)
return *sldata;
}
+/* Object data. */
+
+static void eevee_object_data_init(ObjectEngineData *engine_data)
+{
+ EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)engine_data;
+ eevee_data->shadow_caster_id = -1;
+}
+
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob)
{
+ if (ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)) {
+ return NULL;
+ }
return (EEVEE_ObjectEngineData *)DRW_object_engine_data_get(
ob, &draw_engine_eevee_type);
}
EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob)
{
- EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_ensure(
- ob, &draw_engine_eevee_type, NULL);
+ BLI_assert(!ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP));
+ return (EEVEE_ObjectEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_ObjectEngineData),
+ eevee_object_data_init,
+ NULL);
+}
- if (*oedata == NULL) {
- *oedata = MEM_callocN(sizeof(**oedata), "EEVEE_ObjectEngineData");
- }
+/* Light probe data. */
+
+static void eevee_lightprobe_data_init(ObjectEngineData *engine_data)
+{
+ EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data;
+ ped->need_full_update = true;
+ ped->need_update = true;
+}
- return *oedata;
+static void eevee_lightprobe_data_free(ObjectEngineData *engine_data)
+{
+ EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data;
+
+ BLI_freelistN(&ped->captured_object_list);
}
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
{
+ if (ob->type != OB_LIGHTPROBE) {
+ return NULL;
+ }
return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_get(
ob, &draw_engine_eevee_type);
}
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob)
{
- EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_ensure(
- ob, &draw_engine_eevee_type, &eevee_lightprobe_data_free);
+ BLI_assert(ob->type == OB_LIGHTPROBE);
+ return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_LightProbeEngineData),
+ &eevee_lightprobe_data_init,
+ &eevee_lightprobe_data_free);
+}
- if (*pedata == NULL) {
- *pedata = MEM_callocN(sizeof(**pedata), "EEVEE_LightProbeEngineData");
- (*pedata)->need_full_update = true;
- (*pedata)->need_update = true;
- }
+/* Lamp data. */
- return *pedata;
+static void eevee_lamp_data_init(ObjectEngineData *engine_data)
+{
+ EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)engine_data;
+ led->need_update = true;
+ led->prev_cube_shadow_id = -1;
}
EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob)
{
+ if (ob->type != OB_LAMP) {
+ return NULL;
+ }
return (EEVEE_LampEngineData *)DRW_object_engine_data_get(
ob, &draw_engine_eevee_type);
}
EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob)
{
- EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_ensure(
- ob, &draw_engine_eevee_type, &eevee_lamp_data_free);
-
- if (*ledata == NULL) {
- *ledata = MEM_callocN(sizeof(**ledata), "EEVEE_LampEngineData");
- (*ledata)->need_update = true;
- }
-
- return *ledata;
+ BLI_assert(ob->type == OB_LAMP);
+ return (EEVEE_LampEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_LampEngineData),
+ eevee_lamp_data_init,
+ NULL);
}
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
index ef7e6412fc4..f5fc79aba4f 100644
--- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -45,6 +45,7 @@
#include "BKE_screen.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "eevee_private.h"
#include "GPU_extensions.h"
@@ -74,7 +75,7 @@ static void eevee_create_shader_depth_of_field(void)
datatoc_effect_dof_frag_glsl, "#define STEP_RESOLVE\n");
}
-int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera)
{
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
@@ -87,16 +88,15 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
if (BKE_collection_engine_property_value_get_bool(props, "dof_enable")) {
Scene *scene = draw_ctx->scene;
- View3D *v3d = draw_ctx->v3d;
RegionView3D *rv3d = draw_ctx->rv3d;
if (!e_data.dof_downsample_sh) {
eevee_create_shader_depth_of_field();
}
- if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ if (camera) {
const float *viewport_size = DRW_viewport_size_get();
- Camera *cam = (Camera *)v3d->camera->data;
+ Camera *cam = (Camera *)camera->data;
/* Retreive Near and Far distance */
effects->dof_near_far[0] = -cam->clipsta;
@@ -125,12 +125,15 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
&fbl->dof_down_fb, &draw_engine_eevee_type,
buffer_size[0], buffer_size[1], tex_down, 3);
- DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER};
+ /* Go full 32bits for rendering and reduce the color artifacts. */
+ DRWTextureFormat fb_format = DRW_state_is_image_render() ? DRW_TEX_RGBA_32 : DRW_TEX_RGBA_16;
+
+ DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, fb_format, DRW_TEX_FILTER};
DRW_framebuffer_init(
&fbl->dof_scatter_far_fb, &draw_engine_eevee_type,
buffer_size[0], buffer_size[1], &tex_scatter_far, 1);
- DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER};
+ DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, fb_format, DRW_TEX_FILTER};
DRW_framebuffer_init(
&fbl->dof_scatter_near_fb, &draw_engine_eevee_type,
buffer_size[0], buffer_size[1], &tex_scatter_near, 1);
@@ -142,7 +145,7 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
float rotation = cam->gpu_dof.rotation;
float ratio = 1.0f / cam->gpu_dof.ratio;
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
- float focus_dist = BKE_camera_object_dof_distance(v3d->camera);
+ float focus_dist = BKE_camera_object_dof_distance(camera);
float focal_len = cam->lens;
UNUSED_VARS(rotation, ratio);
@@ -158,9 +161,13 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
float focal_len_scaled = scale_camera * focal_len;
float sensor_scaled = scale_camera * sensor;
+ if (rv3d != NULL) {
+ sensor_scaled *= rv3d->viewcamtexcofac[0];
+ }
+
effects->dof_params[0] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
effects->dof_params[1] = -focus_dist;
- effects->dof_params[2] = viewport_size[0] / (rv3d->viewcamtexcofac[0] * sensor_scaled);
+ effects->dof_params[2] = viewport_size[0] / sensor_scaled;
effects->dof_bokeh[0] = blades;
effects->dof_bokeh[1] = rotation;
effects->dof_bokeh[2] = ratio;
@@ -213,7 +220,7 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_
DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1);
DRW_shgroup_call_add(grp, quad, NULL);
- psl->dof_scatter = DRW_pass_create("DoF Scatter", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+ psl->dof_scatter = DRW_pass_create("DoF Scatter", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE_FULL);
/* This create an empty batch of N triangles to be positioned
* by the vertex shader 0.4ms against 6ms with instancing */
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 703369a86ee..c1ac085230e 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -27,10 +27,9 @@
#include "DRW_render.h"
-#include "BKE_global.h" /* for G.debug_value */
-
#include "eevee_private.h"
#include "GPU_texture.h"
+#include "GPU_extensions.h"
static struct {
/* Downsample Depth */
@@ -77,36 +76,31 @@ static void eevee_create_shader_downsample(void)
"#define MAX_PASS\n");
e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(
datatoc_effect_minmaxz_frag_glsl,
- "#define MIN_PASS\n"
- "#define INPUT_DEPTH\n");
+ "#define MIN_PASS\n");
e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(
datatoc_effect_minmaxz_frag_glsl,
- "#define MAX_PASS\n"
- "#define INPUT_DEPTH\n");
+ "#define MAX_PASS\n");
e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(
datatoc_effect_minmaxz_frag_glsl,
"#define MIN_PASS\n"
- "#define LAYERED\n"
- "#define INPUT_DEPTH\n");
+ "#define LAYERED\n");
e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(
datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n"
- "#define LAYERED\n"
- "#define INPUT_DEPTH\n");
+ "#define LAYERED\n");
e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(
datatoc_effect_minmaxz_frag_glsl,
"#define MIN_PASS\n"
- "#define INPUT_DEPTH\n"
"#define COPY_DEPTH\n");
e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(
datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n"
- "#define INPUT_DEPTH\n"
"#define COPY_DEPTH\n");
}
-void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
@@ -126,9 +120,9 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
effects = stl->effects;
effects->enabled_effects = 0;
- effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera);
effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata);
- effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera);
effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata);
effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata);
effects->enabled_effects |= EEVEE_subsurface_init(sldata, vedata);
@@ -154,10 +148,17 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
* MinMax Pyramid
*/
DRWFboTexture texmax = {&txl->maxzbuffer, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP};
+
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ /* Intel gpu seems to have problem rendering to only depth format */
+ texmax.format = DRW_TEX_R_32;
+ }
+
DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type,
- (int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
+ max_ii((int)viewport_size[0] / 2, 1), max_ii((int)viewport_size[1] / 2, 1),
&texmax, 1);
+
/**
* Compute Mipmap texel alignement.
*/
@@ -167,8 +168,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
mip_size[0] = floorf(fmaxf(1.0f, mip_size[0] / 2.0f));
mip_size[1] = floorf(fmaxf(1.0f, mip_size[1] / 2.0f));
}
- stl->g_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, floorf(log2f(floorf(viewport_size[0] / mip_size[0])))));
- stl->g_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1])))));
+ common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, floorf(log2f(floorf(viewport_size[0] / mip_size[0])))));
+ common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1])))));
}
@@ -207,12 +208,17 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
- EEVEE_EffectsInfo *effects = stl->effects;
+ int downsample_write = DRW_STATE_WRITE_DEPTH;
+
+ /* Intel gpu seems to have problem rendering to only depth format.
+ * Use color texture instead. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ downsample_write = DRW_STATE_WRITE_COLOR;
+ }
struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
@@ -220,7 +226,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps);
DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src);
- DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
DRW_shgroup_call_add(grp, quad, NULL);
}
@@ -239,39 +245,39 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
DRWShadingGroup *grp;
#if 0 /* Not used for now */
- psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minzbuffer);
DRW_shgroup_call_add(grp, quad, NULL);
#endif
- psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &txl->maxzbuffer);
DRW_shgroup_call_add(grp, quad, NULL);
/* Copy depth buffer to halfres top level of HiZ */
#if 0 /* Not used for now */
- psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.minz_downdepth_sh, psl->minz_downdepth_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
#endif
- psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
#if 0 /* Not used for now */
- psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.minz_downdepth_layer_sh, psl->minz_downdepth_layer_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
DRW_shgroup_call_add(grp, quad, NULL);
#endif
- psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
@@ -279,13 +285,13 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
/* Copy depth buffer to halfres top level of HiZ */
#if 0 /* Not used for now */
- psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.minz_copydepth_sh, psl->minz_copydepth_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
#endif
- psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
@@ -392,13 +398,12 @@ void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_
DRW_stats_group_end();
}
-void EEVEE_draw_effects(EEVEE_Data *vedata)
+void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_TextureList *txl = vedata->txl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
/* only once per frame after the first post process */
@@ -419,39 +424,9 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
EEVEE_depth_of_field_draw(vedata);
EEVEE_bloom_draw(vedata);
- /* Restore default framebuffer */
- DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
- DRW_framebuffer_bind(dfbl->default_fb);
-
- /* Tonemapping */
- DRW_transform_to_display(effects->source_buffer);
-
- /* Debug : Ouput buffer to view. */
- switch (G.debug_value) {
- case 1:
- if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer);
- break;
- case 2:
- if (stl->g_data->ssr_hit_output[0]) DRW_transform_to_display(stl->g_data->ssr_hit_output[0]);
- break;
- case 3:
- if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input);
- break;
- case 4:
- if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input);
- break;
- case 5:
- if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer);
- break;
- case 6:
- if (stl->g_data->gtao_horizons_debug) DRW_transform_to_display(stl->g_data->gtao_horizons_debug);
- break;
- case 7:
- if (txl->sss_data) DRW_transform_to_display(txl->sss_data);
- break;
- default:
- break;
- }
+ /* Save the final texture and framebuffer for final transformation or read. */
+ effects->final_tx = effects->source_buffer;
+ effects->final_fb = (effects->target_buffer != fbl->main) ? fbl->main : fbl->effect_fb;
/* If no post processes is enabled, buffers are still not swapped, do it now. */
SWAP_DOUBLE_BUFFERS();
@@ -466,7 +441,7 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
}
/* Record pers matrix for the next frame. */
- DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_get(sldata->common_data.prev_persmat, DRW_MAT_PERS);
/* Update double buffer status if render mode. */
if (DRW_state_is_image_render()) {
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index a20b1afe3d4..8e74f3344dd 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -29,9 +29,13 @@
#include "BLI_rand.h"
#include "BKE_object.h"
+#include "BKE_global.h" /* for G.debug_value */
+#include "BKE_screen.h"
#include "DNA_world_types.h"
+#include "ED_screen.h"
+
#include "GPU_material.h"
#include "GPU_glew.h"
@@ -52,11 +56,16 @@ static void eevee_engine_init(void *ved)
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Object *camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+
if (!stl->g_data) {
/* Alloc transient pointers */
stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
}
- stl->g_data->background_alpha = 1.0f;
+ stl->g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f;
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
@@ -66,14 +75,17 @@ static void eevee_engine_init(void *ved)
(int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
- /* EEVEE_effects_init needs to go first for TAA */
- EEVEE_effects_init(sldata, vedata);
+ if (sldata->common_ubo == NULL) {
+ sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
+ }
- EEVEE_materials_init(stl);
+ /* EEVEE_effects_init needs to go first for TAA */
+ EEVEE_effects_init(sldata, vedata, camera);
+ EEVEE_materials_init(sldata, stl, fbl);
EEVEE_lights_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
- if (stl->effects->taa_current_sample > 1) {
+ if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) {
/* XXX otherwise it would break the other engines. */
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
@@ -113,22 +125,17 @@ static void eevee_cache_populate(void *vedata, Object *ob)
}
}
- if (ELEM(ob->type, OB_MESH)) {
- if (!BKE_object_is_visible(ob)) {
- return;
- }
+ if (DRW_check_object_visible_within_active_context(ob) == false) {
+ return;
+ }
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
EEVEE_materials_cache_populate(vedata, sldata, ob);
const bool cast_shadow = true;
if (cast_shadow) {
- if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
- /* TODO: Special case for dupli objects because we cannot save the object pointer. */
- }
- else {
- BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob));
- }
+ EEVEE_lights_cache_shcaster_object_add(sldata, ob);
}
}
else if (ob->type == OB_LIGHTPROBE) {
@@ -140,12 +147,7 @@ static void eevee_cache_populate(void *vedata, Object *ob)
}
}
else if (ob->type == OB_LAMP) {
- if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
- /* TODO: Special case for dupli objects because we cannot save the object pointer. */
- }
- else {
- EEVEE_lights_cache_add(sldata, ob);
- }
+ EEVEE_lights_cache_add(sldata, ob);
}
}
@@ -158,46 +160,47 @@ static void eevee_cache_finish(void *vedata)
EEVEE_lightprobes_cache_finish(sldata, vedata);
}
-static void eevee_draw_scene(void *vedata)
+/* As renders in an HDR offscreen buffer, we need draw everything once
+ * during the background pass. This way the other drawing callback between
+ * the background and the scene pass are visible.
+ * Note: we could break it up in two passes using some depth test
+ * to reduce the fillrate */
+static void eevee_draw_background(void *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
/* Default framebuffer and texture */
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
/* Number of iteration: needed for all temporal effect (SSR, TAA)
* when using opengl render. */
int loop_ct = DRW_state_is_image_render() ? 4 : 1;
- static float rand = 0.0f;
-
- /* XXX temp for denoising render. TODO plug number of samples here */
- if (DRW_state_is_image_render()) {
- rand += 1.0f / 16.0f;
- rand = rand - floorf(rand);
-
- /* Set jitter offset */
- EEVEE_update_util_texture(rand);
- }
- else if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && (stl->effects->taa_current_sample > 1)) {
- double r;
- BLI_halton_1D(2, 0.0, stl->effects->taa_current_sample - 1, &r);
-
- /* Set jitter offset */
- /* PERF This is killing perf ! */
- EEVEE_update_util_texture((float)r);
- }
-
while (loop_ct--) {
+ unsigned int primes[3] = {2, 3, 7};
+ double offset[3] = {0.0, 0.0, 0.0};
+ double r[3];
+
+ if (DRW_state_is_image_render() ||
+ ((stl->effects->enabled_effects & EFFECT_TAA) != 0))
+ {
+ BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r);
+ EEVEE_update_noise(psl, fbl, r);
+ }
/* Refresh Probes */
DRW_stats_group_start("Probes Refresh");
EEVEE_lightprobes_refresh(sldata, vedata);
DRW_stats_group_end();
+ /* Update common buffer after probe rendering. */
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
/* Refresh shadows */
DRW_stats_group_start("Shadows");
EEVEE_draw_shadows(sldata, psl);
@@ -207,9 +210,19 @@ static void eevee_draw_scene(void *vedata)
DRW_framebuffer_texture_detach(dtxl->depth);
DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
DRW_framebuffer_bind(fbl->main);
- DRW_framebuffer_clear(false, true, true, NULL, 1.0f);
+ if (DRW_state_draw_background()) {
+ DRW_framebuffer_clear(false, true, true, NULL, 1.0f);
+ }
+ else {
+ /* We need to clear the alpha chanel in this case. */
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ DRW_framebuffer_clear(true, true, true, clear_col, 1.0f);
+ }
- if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && stl->effects->taa_current_sample > 1) {
+ if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) &&
+ (stl->effects->taa_current_sample > 1) &&
+ !DRW_state_is_image_render())
+ {
DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS);
DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV);
DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN);
@@ -227,12 +240,14 @@ static void eevee_draw_scene(void *vedata)
EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
DRW_stats_group_end();
- EEVEE_occlusion_compute(sldata, vedata);
+ EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
EEVEE_volumes_compute(sldata, vedata);
/* Shading pass */
DRW_stats_group_start("Shading");
- DRW_draw_pass(psl->background_pass);
+ if (DRW_state_draw_background()) {
+ DRW_draw_pass(psl->background_pass);
+ }
EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->material_pass);
EEVEE_subsurface_data_render(sldata, vedata);
@@ -261,10 +276,10 @@ static void eevee_draw_scene(void *vedata)
/* Post Process */
DRW_stats_group_start("Post FX");
- EEVEE_draw_effects(vedata);
+ EEVEE_draw_effects(sldata, vedata);
DRW_stats_group_end();
- if (stl->effects->taa_current_sample > 1) {
+ if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) {
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
@@ -272,6 +287,43 @@ static void eevee_draw_scene(void *vedata)
}
}
+ /* Restore default framebuffer */
+ DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ DRW_framebuffer_bind(dfbl->default_fb);
+
+ /* Tonemapping */
+ DRW_transform_to_display(stl->effects->final_tx);
+
+ /* Debug : Ouput buffer to view. */
+ switch (G.debug_value) {
+ case 1:
+ if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer);
+ break;
+ case 2:
+ if (stl->g_data->ssr_pdf_output) DRW_transform_to_display(stl->g_data->ssr_pdf_output);
+ break;
+ case 3:
+ if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input);
+ break;
+ case 4:
+ if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input);
+ break;
+ case 5:
+ if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer);
+ break;
+ case 6:
+ if (stl->g_data->gtao_horizons_debug) DRW_transform_to_display(stl->g_data->gtao_horizons_debug);
+ break;
+ case 7:
+ if (txl->gtao_horizons) DRW_transform_to_display(txl->gtao_horizons);
+ break;
+ case 8:
+ if (txl->sss_data) DRW_transform_to_display(txl->sss_data);
+ break;
+ default:
+ break;
+ }
+
EEVEE_volumes_free_smoke_textures();
stl->g_data->view_updated = false;
@@ -285,24 +337,50 @@ static void eevee_view_update(void *vedata)
}
}
-static void eevee_id_update(void *UNUSED(vedata), ID *id)
+static void eevee_id_object_update(void *UNUSED(vedata), Object *object)
{
- const ID_Type id_type = GS(id->name);
- if (id_type == ID_OB) {
- Object *object = (Object *)id;
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object);
- if (ped != NULL) {
- ped->need_full_update = true;
- }
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object);
- if (led != NULL) {
- led->need_update = true;
- }
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object);
- if (oedata != NULL) {
- oedata->need_update = true;
- }
+ /* This is a bit mask of components which update is to be ignored. */
+ const int ignore_updates = ID_RECALC_COLLECTIONS;
+ const int allowed_updates = ~ignore_updates;
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object);
+ if (ped != NULL && (ped->engine_data.recalc & allowed_updates) != 0) {
+ ped->need_full_update = true;
+ ped->engine_data.recalc = 0;
}
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object);
+ if (led != NULL && (led->engine_data.recalc & allowed_updates) != 0) {
+ led->need_update = true;
+ led->engine_data.recalc = 0;
+ }
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object);
+ if (oedata != NULL && (oedata->engine_data.recalc & allowed_updates) != 0) {
+ oedata->need_update = true;
+ oedata->engine_data.recalc = 0;
+ }
+}
+
+static void eevee_id_update(void *vedata, ID *id)
+{
+ /* Handle updates based on ID type. */
+ switch (GS(id->name)) {
+ case ID_OB:
+ eevee_id_object_update(vedata, (Object *)id);
+ break;
+ default:
+ /* pass */
+ break;
+ }
+}
+
+static void eevee_render_to_image(void *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ EEVEE_render_init(vedata, engine, depsgraph);
+
+ DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache);
+ /* Actually do the rendering. */
+ EEVEE_render_draw(vedata, engine, depsgraph);
+ /* Write outputs to RenderResult. */
+ EEVEE_render_output(vedata, engine, depsgraph);
}
static void eevee_engine_free(void)
@@ -340,7 +418,8 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_int(props, "gi_cubemap_resolution", 512);
BKE_collection_engine_property_add_int(props, "gi_visibility_resolution", 32);
- BKE_collection_engine_property_add_int(props, "taa_samples", 8);
+ BKE_collection_engine_property_add_int(props, "taa_samples", 16);
+ BKE_collection_engine_property_add_int(props, "taa_render_samples", 64);
BKE_collection_engine_property_add_bool(props, "sss_enable", false);
BKE_collection_engine_property_add_int(props, "sss_samples", 7);
@@ -350,7 +429,6 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_bool(props, "ssr_enable", false);
BKE_collection_engine_property_add_bool(props, "ssr_refraction", false);
BKE_collection_engine_property_add_bool(props, "ssr_halfres", true);
- BKE_collection_engine_property_add_int(props, "ssr_ray_count", 1);
BKE_collection_engine_property_add_float(props, "ssr_quality", 0.25f);
BKE_collection_engine_property_add_float(props, "ssr_max_roughness", 0.5f);
BKE_collection_engine_property_add_float(props, "ssr_thickness", 0.2f);
@@ -371,12 +449,10 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_bool(props, "gtao_enable", false);
BKE_collection_engine_property_add_bool(props, "gtao_use_bent_normals", true);
- BKE_collection_engine_property_add_bool(props, "gtao_denoise", true);
BKE_collection_engine_property_add_bool(props, "gtao_bounce", true);
BKE_collection_engine_property_add_float(props, "gtao_distance", 0.2f);
BKE_collection_engine_property_add_float(props, "gtao_factor", 1.0f);
BKE_collection_engine_property_add_float(props, "gtao_quality", 0.25f);
- BKE_collection_engine_property_add_int(props, "gtao_samples", 2);
BKE_collection_engine_property_add_bool(props, "dof_enable", false);
BKE_collection_engine_property_add_float(props, "bokeh_max_size", 100.0f);
@@ -411,16 +487,17 @@ DrawEngineType draw_engine_eevee_type = {
&eevee_cache_init,
&eevee_cache_populate,
&eevee_cache_finish,
- &eevee_draw_scene,
- NULL, //&EEVEE_draw_scene
+ &eevee_draw_background,
+ NULL, /* Everything is drawn in the background pass (see comment on function) */
&eevee_view_update,
&eevee_id_update,
+ &eevee_render_to_image,
};
RenderEngineType DRW_engine_viewport_eevee_type = {
NULL, NULL,
EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL, NULL,
&eevee_layer_collection_settings_create,
&eevee_view_layer_settings_create,
&draw_engine_eevee_type,
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index d7ccc1a5336..7403da737dd 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -26,7 +26,7 @@
#include "DRW_render.h"
#include "BLI_utildefines.h"
-#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "BLI_rand.h"
#include "DNA_world_types.h"
@@ -83,7 +83,6 @@ static struct {
struct GPUTexture *cube_face_minmaxz;
int update_world;
- bool world_ready_to_shade;
} e_data = {NULL}; /* Engine data */
extern char datatoc_background_vert_glsl[];
@@ -107,6 +106,7 @@ extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lightprobe_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern GlobalsUboStorage ts;
@@ -204,12 +204,11 @@ static void lightprobe_shaders_init(void)
char *shader_str = NULL;
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ shader_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_lightprobe_filter_glossy_frag_glsl);
e_data.probe_filter_glossy_sh = DRW_shader_create(
datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines);
@@ -219,36 +218,33 @@ static void lightprobe_shaders_init(void)
MEM_freeN(shader_str);
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ shader_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_lightprobe_filter_diffuse_frag_glsl);
e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
MEM_freeN(shader_str);
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_visibility_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ shader_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_lightprobe_filter_visibility_frag_glsl);
e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
MEM_freeN(shader_str);
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ shader_str = BLI_string_joinN(
+ datatoc_octahedron_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_lightprobe_grid_display_frag_glsl);
e_data.probe_grid_display_sh = DRW_shader_create(
datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str, filter_defines);
@@ -258,13 +254,12 @@ static void lightprobe_shaders_init(void)
e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(
datatoc_lightprobe_grid_fill_frag_glsl, filter_defines);
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ shader_str = BLI_string_joinN(
+ datatoc_octahedron_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_lightprobe_cube_display_frag_glsl);
e_data.probe_cube_display_sh = DRW_shader_create(
datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL);
@@ -286,6 +281,7 @@ static void lightprobe_shaders_init(void)
void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
bool update_all = false;
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
@@ -298,15 +294,16 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
if (!sldata->probes) {
sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
- sldata->probes->specular_toggle = true;
- sldata->probes->ssr_toggle = true;
- sldata->probes->sss_toggle = true;
sldata->probes->grid_initialized = false;
sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
}
+ common_data->spec_toggle = true;
+ common_data->ssr_toggle = true;
+ common_data->sss_toggle = true;
+
int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces");
if (sldata->probes->num_bounce != prop_bounce_num) {
sldata->probes->num_bounce = prop_bounce_num;
@@ -325,8 +322,8 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
}
int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution");
- if (sldata->probes->irradiance_vis_size != visibility_res) {
- sldata->probes->irradiance_vis_size = visibility_res;
+ if (common_data->prb_irradiance_vis_size != visibility_res) {
+ common_data->prb_irradiance_vis_size = visibility_res;
update_all = true;
}
@@ -370,6 +367,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ pinfo->do_cube_update = false;
pinfo->num_cube = 1; /* at least one for the world */
pinfo->num_grid = 1;
pinfo->num_planar = 0;
@@ -391,7 +389,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
float *col = ts.colorBackground;
if (wo) {
col = &wo->horr;
- if (wo->update_flag != 0) {
+ if (wo->update_flag != 0 || pinfo->prev_world != wo) {
e_data.update_world |= PROBE_UPDATE_ALL;
pinfo->updated_bounce = 0;
pinfo->grid_initialized = false;
@@ -413,6 +411,14 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
col = pink;
}
}
+
+ pinfo->prev_world = wo;
+ }
+ else if (pinfo->prev_world) {
+ pinfo->prev_world = NULL;
+ e_data.update_world |= PROBE_UPDATE_ALL;
+ pinfo->updated_bounce = 0;
+ pinfo->grid_initialized = false;
}
/* Fallback if shader fails or if not using nodetree. */
@@ -430,14 +436,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute, geom);
- DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
- DRW_shgroup_uniform_float(grp, "roughnessSquared", &sldata->probes->roughness, 1);
- DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1);
- DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1);
- DRW_shgroup_uniform_float(grp, "texelSize", &sldata->probes->texel_size, 1);
- DRW_shgroup_uniform_float(grp, "paddingSize", &sldata->probes->padding_size, 1);
- DRW_shgroup_uniform_int(grp, "Layer", &sldata->probes->layer, 1);
+ DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
+ DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1);
+ DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
// DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
@@ -450,14 +457,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute);
#ifdef IRRADIANCE_SH_L2
- DRW_shgroup_uniform_int(grp, "probeSize", &sldata->probes->shres, 1);
+ DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1);
#else
- DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
- DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1);
- DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
#endif
+ DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
@@ -468,14 +476,14 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute);
- DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1);
- DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1);
- DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1);
- DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
- DRW_shgroup_uniform_float(grp, "storedTexelSize", &sldata->probes->texel_size, 1);
- DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1);
- DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1);
+ DRW_shgroup_uniform_int(grp, "outputSize", &pinfo->shres, 1);
+ DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1);
+ DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1);
+ DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt);
@@ -502,8 +510,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_attrib_float(grp, "probe_id", 1); /* XXX this works because we are still uploading 4bytes and using the right stride */
DRW_shgroup_attrib_float(grp, "probe_location", 3);
DRW_shgroup_attrib_float(grp, "sphere_size", 1);
- DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
geom = DRW_cache_quad_get();
grp = stl->g_data->planar_display_shgrp = DRW_shgroup_instance_create(e_data.probe_planar_display_sh, psl->probe_display, geom);
@@ -518,7 +526,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom);
DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool);
- DRW_shgroup_uniform_float(grp, "fireflyFactor", &stl->effects->ssr_firefly_fac, 1);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
}
}
@@ -551,7 +559,6 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
ped->need_update = true;
ped->probe_id = 0;
-
if (probe->type == LIGHTPROBE_TYPE_GRID) {
ped->updated_cells = 0;
ped->updated_lvl = 0;
@@ -567,6 +574,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
ped->probe_id = 0;
}
+ pinfo->do_cube_update |= ped->need_update;
+
if (probe->type == LIGHTPROBE_TYPE_CUBE) {
pinfo->probes_cube_ref[pinfo->num_cube] = ob;
pinfo->num_cube++;
@@ -685,8 +694,7 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_
eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
/* Debug Display */
- if (BKE_object_is_visible(ob) &&
- DRW_state_draw_support() &&
+ if (DRW_state_draw_support() &&
(probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
{
DRW_shgroup_call_dynamic_add(stl->g_data->planar_display_shgrp, &ped->probe_id, ob->obmat);
@@ -734,8 +742,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
invert_m4(eprobe->parallaxmat);
/* Debug Display */
- if (BKE_object_is_visible(ob) &&
- DRW_state_draw_support() &&
+ if (DRW_state_draw_support() &&
(probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
{
ped->probe_size = probe->data_draw_size * 0.1f;
@@ -816,8 +823,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
len_v3(egrid->increment_z)) + 1.0f;
/* Debug Display */
- if (BKE_object_is_visible(ob) &&
- DRW_state_draw_support() &&
+ if (DRW_state_draw_support() &&
(probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
{
struct Gwn_Batch *geom = DRW_cache_sphere_get();
@@ -837,6 +843,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
Object *ob;
@@ -854,7 +861,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
}
int irr_size[3];
- irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, irr_size);
+ irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, irr_size);
if ((irr_size[0] != pinfo->cache_irradiance_size[0]) ||
(irr_size[1] != pinfo->cache_irradiance_size[1]) ||
@@ -880,8 +887,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
/* Tag probes to refresh */
e_data.update_world |= PROBE_UPDATE_CUBE;
- e_data.world_ready_to_shade = false;
- pinfo->num_render_cube = 0;
+ common_data->prb_num_render_cube = 0;
pinfo->cache_num_cube = pinfo->num_cube;
for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
@@ -913,7 +919,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2],
irradiance_format, DRW_TEX_FILTER, NULL);
}
- pinfo->num_render_grid = 0;
+ common_data->prb_num_render_grid = 0;
pinfo->updated_bounce = 0;
pinfo->grid_initialized = false;
e_data.update_world |= PROBE_UPDATE_GRID;
@@ -925,9 +931,9 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
}
}
- if (pinfo->num_render_grid > pinfo->num_grid) {
+ if (common_data->prb_num_render_grid > pinfo->num_grid) {
/* This can happen when deleting a probe. */
- pinfo->num_render_grid = pinfo->num_grid;
+ common_data->prb_num_render_grid = pinfo->num_grid;
}
EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl);
@@ -944,23 +950,26 @@ static void downsample_planar(void *vedata, int level)
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
const float *size = DRW_viewport_size_get();
- copy_v2_v2(stl->g_data->texel_size, size);
+ copy_v2_v2(stl->g_data->planar_texel_size, size);
for (int i = 0; i < level - 1; ++i) {
- stl->g_data->texel_size[0] /= 2.0f;
- stl->g_data->texel_size[1] /= 2.0f;
- min_ff(floorf(stl->g_data->texel_size[0]), 1.0f);
- min_ff(floorf(stl->g_data->texel_size[1]), 1.0f);
+ stl->g_data->planar_texel_size[0] /= 2.0f;
+ stl->g_data->planar_texel_size[1] /= 2.0f;
+ min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f);
+ min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f);
}
- invert_v2(stl->g_data->texel_size);
+ invert_v2(stl->g_data->planar_texel_size);
DRW_draw_pass(psl->probe_planar_downsample_ps);
}
/* Glossy filter probe_rt to probe_pool at index probe_idx */
-static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx)
+static void glossy_filter_probe(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx, float intensity)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ pinfo->intensity_fac = intensity;
+
/* Max lod used from the render target probe */
pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f;
@@ -1023,7 +1032,7 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
CLAMP_MIN(mipsize, 1);
}
/* For shading, save max level of the octahedron map */
- pinfo->lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f;
+ sldata->common_data.prb_lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f;
/* reattach to have a valid framebuffer. */
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
@@ -1032,12 +1041,15 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
/* Diffuse filter probe_rt to irradiance_pool at index probe_idx */
static void diffuse_filter_probe(
EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset,
- float clipsta, float clipend, float vis_range, float vis_blur)
+ float clipsta, float clipend, float vis_range, float vis_blur, float intensity)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ pinfo->intensity_fac = intensity;
+
int pool_size[3];
- irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, pool_size);
+ irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, pool_size);
/* find cell position on the virtual 3D texture */
/* NOTE : Keep in sync with load_irradiance_cell() */
@@ -1081,23 +1093,24 @@ static void diffuse_filter_probe(
/* Compute visibility */
pinfo->samples_ct = 512.0f; /* TODO refine */
pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
- pinfo->shres = pinfo->irradiance_vis_size;
+ pinfo->shres = common_data->prb_irradiance_vis_size;
pinfo->visibility_range = vis_range;
pinfo->visibility_blur = vis_blur;
pinfo->near_clip = -clipsta;
pinfo->far_clip = -clipend;
- pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size;
+ pinfo->texel_size = 1.0f / (float)common_data->prb_irradiance_vis_size;
- int cell_per_col = pool_size[1] / pinfo->irradiance_vis_size;
- cell_per_row = pool_size[0] / pinfo->irradiance_vis_size;
- x = pinfo->irradiance_vis_size * (offset % cell_per_row);
- y = pinfo->irradiance_vis_size * ((offset / cell_per_row) % cell_per_col);
+ int cell_per_col = pool_size[1] / common_data->prb_irradiance_vis_size;
+ cell_per_row = pool_size[0] / common_data->prb_irradiance_vis_size;
+ x = common_data->prb_irradiance_vis_size * (offset % cell_per_row);
+ y = common_data->prb_irradiance_vis_size * ((offset / cell_per_row) % cell_per_col);
int layer = 1 + ((offset / cell_per_row) / cell_per_col);
DRW_framebuffer_texture_detach(sldata->irradiance_rt);
DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, layer, 0);
- DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size);
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, common_data->prb_irradiance_vis_size,
+ common_data->prb_irradiance_vis_size);
DRW_draw_pass(psl->probe_visibility_compute);
}
@@ -1116,24 +1129,13 @@ static void render_scene_to_probe(
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- float winmat[4][4], wininv[4][4], posmat[4][4], tmp_ao_dist, tmp_ao_samples, tmp_ao_settings;
+ float winmat[4][4], wininv[4][4], posmat[4][4];
unit_m4(posmat);
/* Move to capture position */
negate_v3_v3(posmat[3], pos);
- /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
- sldata->probes->specular_toggle = false;
- sldata->probes->ssr_toggle = false;
- sldata->probes->sss_toggle = false;
-
- /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */
- tmp_ao_dist = stl->effects->ao_dist;
- tmp_ao_samples = stl->effects->ao_samples;
- tmp_ao_settings = stl->effects->ao_settings;
- stl->effects->ao_settings = 0.0f; /* Disable AO */
-
/* 1 - Render to each cubeface individually.
* We do this instead of using geometry shader because a) it's faster,
* b) it's easier than fixing the nodetree shaders (for view dependant effects). */
@@ -1149,6 +1151,9 @@ static void render_scene_to_probe(
stl->g_data->minzbuffer = e_data.depth_placeholder;
txl->maxzbuffer = e_data.depth_placeholder;
+ /* Update common uniforms */
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
/* Detach to rebind the right cubeface. */
DRW_framebuffer_bind(sldata->probe_fb);
DRW_framebuffer_texture_detach(sldata->probe_rt);
@@ -1210,15 +1215,9 @@ static void render_scene_to_probe(
DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
/* Restore */
- pinfo->specular_toggle = true;
- pinfo->ssr_toggle = true;
- pinfo->sss_toggle = true;
txl->planar_pool = tmp_planar_pool;
stl->g_data->minzbuffer = tmp_minz;
txl->maxzbuffer = tmp_maxz;
- stl->effects->ao_dist = tmp_ao_dist;
- stl->effects->ao_samples = tmp_ao_samples;
- stl->effects->ao_settings = tmp_ao_settings;
}
static void render_scene_to_planar(
@@ -1257,11 +1256,6 @@ static void render_scene_to_planar(
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
- /* Turn off ssr to avoid black specular */
- /* TODO : Enable SSR in planar reflections? (Would be very heavy) */
- sldata->probes->ssr_toggle = false;
- sldata->probes->sss_toggle = false;
-
/* Avoid using the texture attached to framebuffer when rendering. */
/* XXX */
GPUTexture *tmp_planar_pool = txl->planar_pool;
@@ -1279,7 +1273,7 @@ static void render_scene_to_planar(
EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
/* Compute GTAO Horizons */
- EEVEE_occlusion_compute(sldata, vedata);
+ EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer);
/* Rebind Planar FB */
DRW_framebuffer_bind(fbl->planarref_fb);
@@ -1293,8 +1287,6 @@ static void render_scene_to_planar(
DRW_state_clip_planes_reset();
/* Restore */
- sldata->probes->ssr_toggle = true;
- sldata->probes->sss_toggle = true;
txl->planar_pool = tmp_planar_pool;
txl->planar_depth = tmp_planar_depth;
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
@@ -1380,27 +1372,25 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc
static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_PassList *psl = vedata->psl;
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
render_world_to_probe(sldata, psl);
if (e_data.update_world & PROBE_UPDATE_CUBE) {
- glossy_filter_probe(sldata, vedata, psl, 0);
+ glossy_filter_probe(sldata, vedata, psl, 0, 1.0);
+ common_data->prb_num_render_cube = 1;
}
if (e_data.update_world & PROBE_UPDATE_GRID) {
- diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0);
+ diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0);
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
DRW_framebuffer_texture_detach(sldata->probe_pool);
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
DRW_draw_pass(psl->probe_grid_fill);
DRW_framebuffer_texture_detach(sldata->irradiance_rt);
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+ common_data->prb_num_render_grid = 1;
}
e_data.update_world = 0;
- if (!e_data.world_ready_to_shade) {
- e_data.world_ready_to_shade = true;
- pinfo->num_render_cube = 1;
- pinfo->num_render_grid = 1;
- }
DRW_viewport_request_redraw();
}
@@ -1432,36 +1422,53 @@ static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEV
static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_TextureList *txl = vedata->txl;
Object *ob;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ if (pinfo->num_planar == 0) {
+ return;
+ }
+
+ /* Temporary Remove all planar reflections (avoid lag effect). */
+ common_data->prb_num_planar = 0;
+ /* Turn off ssr to avoid black specular */
+ /* TODO : Enable SSR in planar reflections? (Would be very heavy) */
+ common_data->ssr_toggle = false;
+ common_data->sss_toggle = false;
+
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
if (!ped->need_update) {
continue;
}
- /* Temporary Remove all planar reflections (avoid lag effect). */
- int tmp_num_planar = pinfo->num_planar;
- pinfo->num_planar = 0;
render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
- /* Restore */
- pinfo->num_planar = tmp_num_planar;
ped->need_update = false;
ped->probe_id = i;
}
+
+ /* Restore */
+ common_data->prb_num_planar = pinfo->num_planar;
+ common_data->ssr_toggle = true;
+ common_data->sss_toggle = true;
+
/* If there is at least one planar probe */
if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) {
const int max_lod = 9;
DRW_stats_group_start("Planar Probe Downsample");
DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
/* For shading, save max level of the planar map */
- pinfo->lod_planar_max = (float)(max_lod);
+ common_data->prb_lod_planar_max = (float)(max_lod);
DRW_stats_group_end();
}
}
static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
@@ -1473,11 +1480,11 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
}
LightProbe *prb = (LightProbe *)ob->data;
render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend);
- glossy_filter_probe(sldata, vedata, psl, i);
+ glossy_filter_probe(sldata, vedata, psl, i, prb->intensity);
ped->need_update = false;
ped->probe_id = i;
if (!ped->ready_to_shade) {
- pinfo->num_render_cube++;
+ common_data->prb_num_render_cube++;
ped->ready_to_shade = true;
}
#if 0
@@ -1488,13 +1495,13 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
stl->effects->taa_current_sample = 1;
/* Only do one probe per frame */
- lightprobes_refresh_planar(sldata, vedata);
return;
}
}
static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
@@ -1506,7 +1513,6 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
/* Only compute probes if not navigating or in playback */
struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) {
- lightprobes_refresh_planar(sldata, vedata);
return;
}
}
@@ -1515,7 +1521,7 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
/* Reflection probes depend on diffuse lighting thus on irradiance grid,
* so update them first. */
while (pinfo->updated_bounce < pinfo->num_bounce) {
- pinfo->num_render_grid = pinfo->num_grid;
+ common_data->prb_num_render_grid = pinfo->num_grid;
/* TODO(sergey): This logic can be split into smaller functions. */
for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
@@ -1559,16 +1565,16 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
lightprobe_cell_world_location_get(egrid, grid_loc, pos);
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
/* Temporary Remove all probes. */
- int tmp_num_render_grid = pinfo->num_render_grid;
- int tmp_num_render_cube = pinfo->num_render_cube;
- int tmp_num_planar = pinfo->num_planar;
+ int tmp_num_render_grid = common_data->prb_num_render_grid;
+ int tmp_num_render_cube = common_data->prb_num_render_cube;
+ int tmp_num_planar = common_data->prb_num_planar;
float tmp_level_bias = egrid->level_bias;
- pinfo->num_render_cube = 0;
- pinfo->num_planar = 0;
+ common_data->prb_num_render_cube = 0;
+ common_data->prb_num_planar = 0;
/* Use light from previous bounce when capturing radiance. */
if (pinfo->updated_bounce == 0) {
/* But not on first bounce. */
- pinfo->num_render_grid = 0;
+ common_data->prb_num_render_grid = 0;
}
else {
/* Remove bias */
@@ -1577,14 +1583,15 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
}
render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend);
diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id,
- prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur);
+ prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur,
+ prb->intensity);
/* To see what is going on. */
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
/* Restore */
- pinfo->num_render_cube = tmp_num_render_cube;
+ common_data->prb_num_render_cube = tmp_num_render_cube;
pinfo->num_planar = tmp_num_planar;
if (pinfo->updated_bounce == 0) {
- pinfo->num_render_grid = tmp_num_render_grid;
+ common_data->prb_num_render_grid = tmp_num_render_grid;
}
else {
egrid->level_bias = tmp_level_bias;
@@ -1608,12 +1615,11 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
DRW_viewport_request_redraw();
/* Do not let this frame accumulate. */
stl->effects->taa_current_sample = 1;
- lightprobes_refresh_planar(sldata, vedata);
return;
}
pinfo->updated_bounce++;
- pinfo->num_render_grid = pinfo->num_grid;
+ common_data->prb_num_render_grid = pinfo->num_grid;
if (pinfo->updated_bounce < pinfo->num_bounce) {
/* Retag all grids to update for next bounce */
@@ -1641,13 +1647,39 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+
+ /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
+ common_data->spec_toggle = false;
+ common_data->ssr_toggle = false;
+ common_data->sss_toggle = false;
+
+ /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */
+ float tmp_ao_dist = common_data->ao_dist;
+ float tmp_ao_settings = common_data->ao_settings;
+ common_data->ao_settings = 0.0f;
+ common_data->ao_dist = 0.0f;
+
/* Render world in priority */
if (e_data.update_world) {
lightprobes_refresh_world(sldata, vedata);
}
- else if (true) { /* TODO if at least one probe needs refresh */
+ else if (pinfo->do_cube_update || (pinfo->updated_bounce < pinfo->num_bounce)) {
lightprobes_refresh_all_no_world(sldata, vedata);
}
+
+ /* Restore */
+ common_data->spec_toggle = true;
+ common_data->ssr_toggle = true;
+ common_data->sss_toggle = true;
+ common_data->ao_dist = tmp_ao_dist;
+ common_data->ao_settings = tmp_ao_settings;
+
+ lightprobes_refresh_planar(sldata, vedata);
+
+ /* Disable SSR if we cannot read previous frame */
+ common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer;
}
void EEVEE_lightprobes_free(void)
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 22465c04cfa..69b58bf9670 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -32,28 +32,7 @@
#include "eevee_engine.h"
#include "eevee_private.h"
-/* Theses are the structs stored inside Objects.
- * It works with even if the object is in multiple layers
- * because we don't get the same "Object *" for each layer. */
-typedef struct EEVEE_LightData {
- short light_id, shadow_id;
-} EEVEE_LightData;
-
-typedef struct EEVEE_ShadowCubeData {
- short light_id, shadow_id, cube_id, layer_id;
-} EEVEE_ShadowCubeData;
-
-typedef struct EEVEE_ShadowCascadeData {
- short light_id, shadow_id, cascade_id, layer_id;
- float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
- float radius[MAX_CASCADE_NUM];
-} EEVEE_ShadowCascadeData;
-
-typedef struct ShadowCaster {
- struct ShadowCaster *next, *prev;
- void *ob;
- bool prune;
-} ShadowCaster;
+#define SHADOW_CASTER_ALLOC_CHUNK 16
static struct {
struct GPUShader *shadow_sh;
@@ -70,6 +49,48 @@ extern char datatoc_shadow_store_frag_glsl[];
extern char datatoc_shadow_copy_frag_glsl[];
extern char datatoc_concentric_samples_lib_glsl[];
+/* Prototype */
+static void eevee_light_setup(Object *ob, EEVEE_Light *evli);
+
+/* *********** LIGHT BITS *********** */
+static void lightbits_set_single(EEVEE_LightBits *bitf, unsigned int idx, bool val)
+{
+ if (val) {
+ bitf->fields[idx / 8] |= (1 << (idx % 8));
+ }
+ else {
+ bitf->fields[idx / 8] &= ~(1 << (idx % 8));
+ }
+}
+
+static void lightbits_set_all(EEVEE_LightBits *bitf, bool val)
+{
+ memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits));
+}
+
+static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v)
+{
+ for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) {
+ r->fields[i] |= v->fields[i];
+ }
+}
+
+static bool lightbits_get(const EEVEE_LightBits *r, unsigned int idx)
+{
+ return r->fields[idx / 8] & (1 << (idx % 8));
+}
+
+static void lightbits_convert(EEVEE_LightBits *r, const EEVEE_LightBits *bitf, const int *light_bit_conv_table, unsigned int table_length)
+{
+ for (int i = 0; i < table_length; ++i) {
+ if (lightbits_get(bitf, i) != 0) {
+ if (light_bit_conv_table[i] >= 0) {
+ r->fields[i / 8] |= (1 << (i % 8));
+ }
+ }
+ }
+}
+
/* *********** FUNCTIONS *********** */
void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
@@ -96,7 +117,8 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
store_shadow_shader_str,
"#define ESM\n");
e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
- store_shadow_shader_str, "#define ESM\n"
+ store_shadow_shader_str,
+ "#define ESM\n"
"#define CSM\n");
e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(
@@ -114,7 +136,8 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
"#define ESM\n"
"#define COPY\n");
e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
- datatoc_shadow_copy_frag_glsl, "#define ESM\n"
+ datatoc_shadow_copy_frag_glsl,
+ "#define ESM\n"
"#define COPY\n"
"#define CSM\n");
@@ -134,8 +157,21 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
+
+ for (int i = 0; i < 2; ++i) {
+ sldata->shcasters_buffers[i].shadow_casters = MEM_callocN(sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf");
+ sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_shcast_buffer flags buf");
+ sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK;
+ sldata->shcasters_buffers[i].count = 0;
+ }
+
+ sldata->lamps->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
+ sldata->lamps->shcaster_backbuffer = &sldata->shcasters_buffers[1];
}
+ /* Flip buffers */
+ SWAP(EEVEE_ShadowCasterBuffer *, sldata->lamps->shcaster_frontbuffer, sldata->lamps->shcaster_backbuffer);
+
int sh_method = BKE_collection_engine_property_value_get_int(props, "shadow_method");
int sh_size = BKE_collection_engine_property_value_get_int(props, "shadow_size");
int sh_high_bitdepth = BKE_collection_engine_property_value_get_int(props, "shadow_high_bitdepth");
@@ -173,6 +209,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
+ linfo->shcaster_frontbuffer->count = 0;
linfo->num_light = 0;
linfo->num_layer = 0;
linfo->gpu_cube_ct = linfo->gpu_cascade_ct = linfo->gpu_shadow_ct = 0;
@@ -180,6 +217,11 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
+ memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id));
+
+ /* Shadow Casters: Reset flags. */
+ memset(linfo->shcaster_backbuffer->flags, (char)SHADOW_CASTER_PRUNED, linfo->shcaster_backbuffer->alloc_count);
+ memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count);
{
psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
@@ -239,9 +281,6 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
"Shadow Cascade Pass",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
}
-
- /* Reset shadow casters list */
- BLI_freelistN(&sldata->shadow_casters);
}
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
@@ -250,14 +289,27 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Step 1 find all lamps in the scene and setup them */
if (linfo->num_light >= MAX_LIGHT) {
- printf("Too much lamps in the scene !!!\n");
- linfo->num_light = MAX_LIGHT - 1;
+ printf("Too many lamps in the scene !!!\n");
}
else {
Lamp *la = (Lamp *)ob->data;
+ EEVEE_Light *evli = linfo->light_data + linfo->num_light;
+ eevee_light_setup(ob, evli);
+
+ /* We do not support shadowmaps for dupli lamps. */
+ if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ linfo->num_light++;
+ return;
+ }
+
EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- MEM_SAFE_FREE(led->storage);
+ /* Save previous shadow id. */
+ int prev_cube_sh_id = led->prev_cube_shadow_id;
+
+ /* Default light without shadows */
+ led->data.ld.shadow_id = -1;
+ led->prev_cube_shadow_id = -1;
if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
if (la->type == LA_SUN) {
@@ -268,13 +320,11 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Save Light object. */
linfo->shadow_cascade_ref[linfo->cpu_cascade_ct] = ob;
- /* Create storage and store indices. */
- EEVEE_ShadowCascadeData *data = MEM_mallocN(
- sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData");
+ /* Store indices. */
+ EEVEE_ShadowCascadeData *data = &led->data.scad;
data->shadow_id = linfo->gpu_shadow_ct;
data->cascade_id = linfo->gpu_cascade_ct;
data->layer_id = linfo->num_layer;
- led->storage = data;
/* Increment indices. */
linfo->gpu_shadow_ct += 1;
@@ -291,13 +341,24 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Save Light object. */
linfo->shadow_cube_ref[linfo->cpu_cube_ct] = ob;
- /* Create storage and store indices. */
- EEVEE_ShadowCubeData *data = MEM_mallocN(
- sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
+ /* For light update tracking. */
+ if ((prev_cube_sh_id >= 0) &&
+ (prev_cube_sh_id < linfo->shcaster_backbuffer->count))
+ {
+ linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_ct;
+ }
+ led->prev_cube_shadow_id = linfo->cpu_cube_ct;
+
+ /* Saving lamp bounds for later. */
+ BLI_assert(linfo->cpu_cube_ct >= 0 && linfo->cpu_cube_ct < MAX_LIGHT);
+ copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_ct].center, ob->obmat[3]);
+ linfo->shadow_bounds[linfo->cpu_cube_ct].radius = la->clipend;
+
+ EEVEE_ShadowCubeData *data = &led->data.scd;
+ /* Store indices. */
data->shadow_id = linfo->gpu_shadow_ct;
data->cube_id = linfo->gpu_cube_ct;
data->layer_id = linfo->num_layer;
- led->storage = data;
/* Increment indices. */
linfo->gpu_shadow_ct += 1;
@@ -309,13 +370,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
}
}
- /* Default light without shadows */
- if (!led->storage) {
- led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData");
- ((EEVEE_LightData *)led->storage)->shadow_id = -1;
- }
-
- ((EEVEE_LightData *)led->storage)->light_id = linfo->num_light;
+ led->data.ld.light_id = linfo->num_light;
linfo->light_ref[linfo->num_light] = ob;
linfo->num_light++;
}
@@ -362,11 +417,75 @@ void EEVEE_lights_cache_shcaster_material_add(
DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM);
}
+/* Make that object update shadow casting lamps inside its influence bounding box. */
+void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ /* TODO: Special case for dupli objects because we cannot save the object pointer. */
+ return;
+ }
+
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ int past_id = oedata->shadow_caster_id;
+
+ /* Update flags in backbuffer. */
+ if (past_id > -1 && past_id < backbuffer->count) {
+ backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED;
+
+ if (oedata->need_update) {
+ backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED;
+ }
+ }
+
+ /* Update id. */
+ oedata->shadow_caster_id = frontbuffer->count++;
+
+ /* Make sure shadow_casters is big enough. */
+ if (oedata->shadow_caster_id >= frontbuffer->alloc_count) {
+ frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK;
+ frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ }
+
+ EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id;
+
+ if (oedata->need_update) {
+ frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED;
+ }
+
+ /* Update World AABB in frontbuffer. */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; ++i) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(ob->obmat, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ EEVEE_BoundBox *aabb = &shcaster->bbox;
+ add_v3_v3v3(aabb->center, min, max);
+ mul_v3_fl(aabb->center, 0.5f);
+ sub_v3_v3v3(aabb->halfdim, aabb->center, max);
+
+ aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
+ aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
+ aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
+
+ oedata->need_update = false;
+}
+
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
DRWTextureFormat shadow_pool_format = DRW_TEX_R_32;
+ sldata->common_data.la_num_light = linfo->num_light;
+
/* Setup enough layers. */
/* Free textures if number mismatch. */
if (linfo->num_layer != linfo->cache_num_layer) {
@@ -428,11 +547,8 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata)
}
/* Update buffer with lamp data */
-static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
{
- /* TODO only update if data changes */
- EEVEE_LightData *evld = led->storage;
- EEVEE_Light *evli = linfo->light_data + evld->light_id;
Lamp *la = (Lamp *)ob->data;
float mat[4][4], scale[3], power;
@@ -485,13 +601,14 @@ static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngi
}
else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */
- M_PI * M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
+ M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
/* for point lights (a.k.a radius == 0.0) */
// power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */
}
else {
- power = 1.0f;
+ power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(r²*Pi) */
+ 12.5f; /* XXX : Empirical, Fit cycles power */
}
mul_v3_fl(evli->color, power * la->energy);
@@ -504,7 +621,7 @@ static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngi
static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
{
- EEVEE_ShadowCubeData *sh_data = (EEVEE_ShadowCubeData *)led->storage;
+ EEVEE_ShadowCubeData *sh_data = &led->data.scd;
EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id;
@@ -598,7 +715,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
int sh_nbr = 1; /* TODO : MSM */
int cascade_nbr = la->cascade_count;
- EEVEE_ShadowCascadeData *sh_data = (EEVEE_ShadowCascadeData *)led->storage;
+ EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
@@ -783,128 +900,86 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
}
/* Used for checking if object is inside the shadow volume. */
-static bool cube_bbox_intersect(const float cube_center[3], float cube_half_dim, const BoundBox *bb, float (*obmat)[4])
+static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb)
{
- float min[3], max[4], tmp[4][4];
- unit_m4(tmp);
- translate_m4(tmp, -cube_center[0], -cube_center[1], -cube_center[2]);
- mul_m4_m4m4(tmp, tmp, obmat);
-
- /* Just simple AABB intersection test in world space. */
- INIT_MINMAX(min, max);
- for (int i = 0; i < 8; ++i) {
- float vec[3];
- copy_v3_v3(vec, bb->vec[i]);
- mul_m4_v3(tmp, vec);
- minmax_v3v3_v3(min, max, vec);
- }
+ /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
+ /* TODO test speed with AABB vs Sphere. */
+ bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
+ bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
+ bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
- if (MAX3(max[0], max[1], max[2]) < -cube_half_dim) return false;
- if (MIN3(min[0], min[1], min[2]) > cube_half_dim) return false;
-
- return true;
+ return x && y && z;
}
-static ShadowCaster *search_object_in_list(ListBase *list, Object *ob)
+void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
{
- for (ShadowCaster *ldata = list->first; ldata; ldata = ldata->next) {
- if (ldata->ob == ob)
- return ldata;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ Object *ob;
+ int i;
+ char *flag;
+ EEVEE_ShadowCaster *shcaster;
+ EEVEE_BoundSphere *bsphere;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+
+ EEVEE_LightBits update_bits = {{0}};
+ if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
+ /* Update all lights. */
+ lightbits_set_all(&update_bits, true);
}
-
- return NULL;
-}
-
-static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led)
-{
- ShadowCaster *next;
- for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = next) {
- next = ldata->next;
- if (ldata->prune == true) {
- led->need_update = true;
- BLI_freelinkN(&led->shadow_caster_list, ldata);
+ else {
+ /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */
+ /* No need to run this if we already update all lamps. */
+ EEVEE_LightBits past_bits = {{0}};
+ EEVEE_LightBits curr_bits = {{0}};
+ shcaster = backbuffer->shadow_casters;
+ flag = backbuffer->flags;
+ for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) {
+ /* If the shadowcaster has been deleted or updated. */
+ if (*flag != 0) {
+ /* Add the lamps that were intersecting with its BBox. */
+ lightbits_or(&past_bits, &shcaster->bits);
+ }
}
+ /* Convert old bits to new bits and add result to final update bits. */
+ /* NOTE: This might be overkill since all lights are tagged to refresh if
+ * the light count changes. */
+ lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT);
+ lightbits_or(&update_bits, &curr_bits);
}
-}
-static void light_tag_shadow_update(Object *lamp, Object *ob)
-{
- Lamp *la = lamp->data;
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp);
-
- bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat);
- ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob);
-
- if (is_inside_range) {
- if (ldata == NULL) {
- /* Object was not a shadow caster previously but is now. Add it. */
- ldata = MEM_callocN(sizeof(ShadowCaster), "ShadowCaster");
- ldata->ob = ob;
- BLI_addtail(&led->shadow_caster_list, ldata);
- led->need_update = true;
+ /* Search for updates in current shadow casters. */
+ shcaster = frontbuffer->shadow_casters;
+ flag = frontbuffer->flags;
+ for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) {
+ /* Run intersection checks to fill the bitfields. */
+ bsphere = linfo->shadow_bounds;
+ for (int j = 0; j < linfo->cpu_cube_ct; j++, bsphere++) {
+ bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox);
+ lightbits_set_single(&shcaster->bits, j, iter);
}
- else {
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
- if (oedata->need_update) {
- led->need_update = true;
- }
+ /* Only add to final bits if objects has been updated. */
+ if (*flag != 0) {
+ lightbits_or(&update_bits, &shcaster->bits);
}
- ldata->prune = false;
}
- else if (ldata != NULL) {
- /* Object was a shadow caster previously and is not anymore. Remove it. */
- led->need_update = true;
- BLI_freelinkN(&led->shadow_caster_list, ldata);
- }
-}
-
-static void eevee_lights_shcaster_updated(EEVEE_ViewLayerData *sldata, Object *ob)
-{
- Object *lamp;
- EEVEE_LampsInfo *linfo = sldata->lamps;
-
- /* Iterate over all shadow casting lamps to see if
- * each of them needs update because of this object */
- for (int i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- light_tag_shadow_update(lamp, ob);
- }
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
- oedata->need_update = false;
-}
-
-void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
-{
- EEVEE_LampsInfo *linfo = sldata->lamps;
- Object *ob;
- int i;
- /* Prune shadow casters to remove if object does not exists anymore (unprune them if object exists) */
- Object *lamp;
- for (i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp);
+ /* Setup shadow cube in UBO and tag for update if necessary. */
+ for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
+ eevee_shadow_cube_setup(ob, linfo, led);
+ if (lightbits_get(&update_bits, i) != 0) {
led->need_update = true;
}
-
- for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = ldata->next) {
- ldata->prune = true;
- }
}
- for (LinkData *ldata = sldata->shadow_casters.first; ldata; ldata = ldata->next) {
- eevee_lights_shcaster_updated(sldata, ldata->data);
- }
-
- for (i = 0; (ob = linfo->light_ref[i]) && (i < MAX_LIGHT); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- eevee_light_setup(ob, linfo, led);
- }
-
- for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- eevee_shadow_cube_setup(ob, linfo, led);
- delete_pruned_shadowcaster(led);
+ /* Resize shcasters buffers if too big. */
+ if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) {
+ frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) * SHADOW_CASTER_ALLOC_CHUNK;
+ frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ? SHADOW_CASTER_ALLOC_CHUNK : 0;
+ frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
}
}
@@ -932,7 +1007,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
}
EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
- EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
+ EEVEE_ShadowCubeData *evscd = &led->data.scd;
srd->clip_near = la->clipsta;
srd->clip_far = la->clipend;
@@ -1010,7 +1085,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
Lamp *la = (Lamp *)ob->data;
- EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage;
+ EEVEE_ShadowCascadeData *evscd = &led->data.scad;
EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
eevee_shadow_cascade_setup(ob, linfo, led);
diff --git a/source/blender/draw/engines/eevee/eevee_lut.h b/source/blender/draw/engines/eevee/eevee_lut.h
index d706110351e..3c2ffeb11a7 100644
--- a/source/blender/draw/engines/eevee/eevee_lut.h
+++ b/source/blender/draw/engines/eevee/eevee_lut.h
@@ -3345,6 +3345,521 @@ static float bsdf_split_sum_ggx[64 * 64 * 2] = {
0.626953f, 0.023544f, 0.616699f, 0.022186f, 0.605957f, 0.020920f, 0.594727f, 0.019730f
};
+static float ltc_disk_integral[64 * 64] = {
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.015873f, 0.047619f, 0.079365f, 0.111111f, 0.142857f, 0.174603f, 0.206349f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000148f, 0.002454f, 0.008675f, 0.019560f,
+ 0.035433f, 0.056294f, 0.081819f, 0.111259f, 0.142857f, 0.174603f, 0.206349f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000002f, 0.000761f, 0.003673f, 0.009403f, 0.018333f, 0.030683f,
+ 0.046556f, 0.065952f, 0.088768f, 0.114784f, 0.143618f, 0.174606f, 0.206349f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000039f, 0.000969f, 0.003703f, 0.008684f, 0.016189f, 0.026395f, 0.039409f,
+ 0.055282f, 0.074014f, 0.095554f, 0.119795f, 0.146560f, 0.175573f, 0.206388f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000047f, 0.000895f, 0.003265f, 0.007514f, 0.013873f, 0.022495f, 0.033483f, 0.046897f,
+ 0.062770f, 0.081102f, 0.101860f, 0.124985f, 0.150372f, 0.177868f, 0.207245f, 0.238143f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000028f,
+ 0.000695f, 0.002655f, 0.006230f, 0.011623f, 0.018976f, 0.028384f, 0.039915f, 0.053606f,
+ 0.069479f, 0.087534f, 0.107749f, 0.130087f, 0.154481f, 0.180833f, 0.209005f, 0.238791f,
+ 0.269869f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000465f,
+ 0.002017f, 0.004975f, 0.009533f, 0.015821f, 0.023934f, 0.033937f, 0.045874f, 0.059772f,
+ 0.075645f, 0.093493f, 0.113302f, 0.135045f, 0.158678f, 0.184136f, 0.211325f, 0.240113f,
+ 0.270306f, 0.301594f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000260f, 0.001426f,
+ 0.003823f, 0.007642f, 0.013012f, 0.020025f, 0.028745f, 0.039218f, 0.051475f, 0.065535f,
+ 0.081408f, 0.099094f, 0.118583f, 0.139856f, 0.162882f, 0.187615f, 0.213991f, 0.241918f,
+ 0.271267f, 0.301847f, 0.333333f, 0.365079f, 0.396826f, 0.428572f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000109f, 0.000921f, 0.002807f,
+ 0.005966f, 0.010528f, 0.016585f, 0.024200f, 0.033420f, 0.044278f, 0.056796f, 0.070988f,
+ 0.086861f, 0.104415f, 0.123643f, 0.144531f, 0.167057f, 0.191188f, 0.216878f, 0.244062f,
+ 0.272649f, 0.302509f, 0.333442f, 0.365079f, 0.396826f, 0.428572f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000024f, 0.000524f, 0.001947f, 0.004511f,
+ 0.008351f, 0.013561f, 0.020206f, 0.028332f, 0.037974f, 0.049155f, 0.061892f, 0.076194f,
+ 0.092067f, 0.109511f, 0.128520f, 0.149085f, 0.171189f, 0.194809f, 0.219910f, 0.246447f,
+ 0.274352f, 0.303535f, 0.333857f, 0.365104f, 0.396826f, 0.428572f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000242f, 0.001250f, 0.003275f, 0.006463f,
+ 0.010913f, 0.016693f, 0.023849f, 0.032418f, 0.042423f, 0.053881f, 0.066805f, 0.081201f,
+ 0.097074f, 0.114424f, 0.133246f, 0.153534f, 0.175275f, 0.198453f, 0.223042f, 0.249009f,
+ 0.276304f, 0.304862f, 0.334584f, 0.365322f, 0.396826f, 0.428571f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000074f, 0.000716f, 0.002252f, 0.004848f, 0.008610f,
+ 0.013608f, 0.019894f, 0.027502f, 0.036458f, 0.046780f, 0.058480f, 0.071567f, 0.086045f,
+ 0.101918f, 0.119186f, 0.137845f, 0.157891f, 0.179316f, 0.202106f, 0.226243f, 0.251704f,
+ 0.278451f, 0.306436f, 0.335586f, 0.365796f, 0.396900f, 0.428571f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000006f, 0.000342f, 0.001437f, 0.003492f, 0.006624f, 0.010911f,
+ 0.016406f, 0.023146f, 0.031157f, 0.040457f, 0.051059f, 0.062972f, 0.076203f, 0.090753f,
+ 0.106626f, 0.123822f, 0.142337f, 0.162170f, 0.183314f, 0.205760f, 0.229496f, 0.254502f,
+ 0.280753f, 0.308212f, 0.336825f, 0.366517f, 0.397167f, 0.428578f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000114f, 0.000820f, 0.002381f, 0.004935f, 0.008569f, 0.013339f,
+ 0.019286f, 0.026437f, 0.034810f, 0.044418f, 0.055271f, 0.067375f, 0.080733f, 0.095348f,
+ 0.111221f, 0.128352f, 0.146740f, 0.166382f, 0.187276f, 0.209413f, 0.232786f, 0.257382f,
+ 0.283181f, 0.310156f, 0.338269f, 0.367461f, 0.397646f, 0.428685f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000014f, 0.000390f, 0.001503f, 0.003525f, 0.006554f, 0.010655f, 0.015872f,
+ 0.022233f, 0.029758f, 0.038460f, 0.048347f, 0.059427f, 0.071702f, 0.085175f, 0.099848f,
+ 0.115721f, 0.132794f, 0.151067f, 0.170538f, 0.191204f, 0.213063f, 0.236107f, 0.260329f,
+ 0.285714f, 0.312243f, 0.339887f, 0.368604f, 0.398329f, 0.428961f, 0.460331f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000130f, 0.000845f, 0.002376f, 0.004845f, 0.008325f, 0.012864f, 0.018495f,
+ 0.025237f, 0.033105f, 0.042107f, 0.052249f, 0.063534f, 0.075965f, 0.089543f, 0.104269f,
+ 0.120142f, 0.137163f, 0.155330f, 0.174645f, 0.195106f, 0.216710f, 0.239454f, 0.263332f,
+ 0.288336f, 0.314451f, 0.341658f, 0.369924f, 0.399202f, 0.429416f, 0.460447f, 0.492064f,
+ 0.523809f, 0.555555f, 0.587301f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000016f, 0.000391f, 0.001475f, 0.003423f, 0.006322f, 0.010230f, 0.015179f, 0.021195f,
+ 0.028290f, 0.036474f, 0.045752f, 0.056128f, 0.067602f, 0.080176f, 0.093850f, 0.108623f,
+ 0.124496f, 0.141469f, 0.159541f, 0.178713f, 0.198985f, 0.220355f, 0.242823f, 0.266385f,
+ 0.291036f, 0.316767f, 0.343563f, 0.371402f, 0.400248f, 0.430047f, 0.460709f, 0.492079f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000123f, 0.000807f, 0.002272f, 0.004628f, 0.007942f, 0.012253f, 0.017589f, 0.023963f,
+ 0.031387f, 0.039864f, 0.049398f, 0.059990f, 0.071638f, 0.084344f, 0.098106f, 0.112923f,
+ 0.128796f, 0.145725f, 0.163709f, 0.182749f, 0.202847f, 0.224001f, 0.246214f, 0.269482f,
+ 0.293805f, 0.319176f, 0.345587f, 0.373021f, 0.401454f, 0.430844f, 0.461125f, 0.492187f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f,
+ 0.000356f, 0.001378f, 0.003225f, 0.005979f, 0.009689f, 0.014384f, 0.020083f, 0.026795f,
+ 0.034525f, 0.043276f, 0.053047f, 0.063839f, 0.075649f, 0.088476f, 0.102320f, 0.117178f,
+ 0.133051f, 0.149939f, 0.167841f, 0.186760f, 0.206696f, 0.227650f, 0.249625f, 0.272620f,
+ 0.296636f, 0.321671f, 0.347718f, 0.374768f, 0.402804f, 0.431796f, 0.461695f, 0.492420f,
+ 0.523822f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000100f,
+ 0.000725f, 0.002097f, 0.004323f, 0.007463f, 0.011553f, 0.016613f, 0.022655f, 0.029684f,
+ 0.037702f, 0.046708f, 0.056701f, 0.067680f, 0.079640f, 0.092581f, 0.106501f, 0.121397f,
+ 0.137270f, 0.154120f, 0.171946f, 0.190751f, 0.210537f, 0.231305f, 0.253057f, 0.275797f,
+ 0.299525f, 0.324242f, 0.349947f, 0.376633f, 0.404289f, 0.432895f, 0.462415f, 0.492788f,
+ 0.523909f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000005f, 0.000296f,
+ 0.001231f, 0.002960f, 0.005558f, 0.009072f, 0.013526f, 0.018933f, 0.025299f, 0.032627f,
+ 0.040916f, 0.050162f, 0.060364f, 0.071517f, 0.083619f, 0.096666f, 0.110656f, 0.125588f,
+ 0.141461f, 0.158275f, 0.176031f, 0.194730f, 0.214374f, 0.234967f, 0.256512f, 0.279011f,
+ 0.302468f, 0.326887f, 0.352266f, 0.378605f, 0.405897f, 0.434130f, 0.463277f, 0.493295f,
+ 0.524106f, 0.555561f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000068f, 0.000613f,
+ 0.001874f, 0.003958f, 0.006921f, 0.010796f, 0.015599f, 0.021336f, 0.028011f, 0.035623f,
+ 0.044167f, 0.053640f, 0.064038f, 0.075355f, 0.087589f, 0.100736f, 0.114793f, 0.129759f,
+ 0.145632f, 0.162412f, 0.180101f, 0.198700f, 0.218213f, 0.238641f, 0.259989f, 0.282262f,
+ 0.305464f, 0.329599f, 0.354670f, 0.380678f, 0.407622f, 0.435493f, 0.464275f, 0.493938f,
+ 0.524422f, 0.555624f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000223f, 0.001054f,
+ 0.002649f, 0.005086f, 0.008406f, 0.012629f, 0.017766f, 0.023820f, 0.030789f, 0.038669f,
+ 0.047455f, 0.057143f, 0.067726f, 0.079199f, 0.091558f, 0.104798f, 0.118918f, 0.133915f,
+ 0.149788f, 0.166537f, 0.184164f, 0.202669f, 0.222056f, 0.242329f, 0.263492f, 0.285551f,
+ 0.308510f, 0.332376f, 0.357153f, 0.382845f, 0.409454f, 0.436977f, 0.465404f, 0.494713f,
+ 0.524864f, 0.555779f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000037f, 0.000486f, 0.001621f,
+ 0.003553f, 0.006338f, 0.010004f, 0.014565f, 0.020024f, 0.026380f, 0.033629f, 0.041765f,
+ 0.050782f, 0.060673f, 0.071431f, 0.083052f, 0.095529f, 0.108859f, 0.123038f, 0.138065f,
+ 0.153938f, 0.170657f, 0.188224f, 0.206640f, 0.225909f, 0.246035f, 0.267022f, 0.288878f,
+ 0.311607f, 0.335216f, 0.359713f, 0.385103f, 0.411390f, 0.438576f, 0.466656f, 0.495617f,
+ 0.525431f, 0.556041f, 0.587338f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000149f, 0.000861f, 0.002312f,
+ 0.004581f, 0.007709f, 0.011713f, 0.016599f, 0.022367f, 0.029014f, 0.036531f, 0.044912f,
+ 0.054148f, 0.064233f, 0.075158f, 0.086918f, 0.099507f, 0.112922f, 0.127157f, 0.142212f,
+ 0.158085f, 0.174776f, 0.192287f, 0.210619f, 0.229775f, 0.249761f, 0.270582f, 0.292243f,
+ 0.314753f, 0.338118f, 0.362347f, 0.387447f, 0.413424f, 0.440284f, 0.468027f, 0.496645f,
+ 0.526122f, 0.556417f, 0.587451f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f, 0.000355f, 0.001353f, 0.003126f,
+ 0.005730f, 0.009194f, 0.013526f, 0.018728f, 0.024795f, 0.031720f, 0.039494f, 0.048109f,
+ 0.057555f, 0.067824f, 0.078909f, 0.090802f, 0.103499f, 0.116993f, 0.131282f, 0.146364f,
+ 0.162237f, 0.178902f, 0.196358f, 0.214610f, 0.233660f, 0.253512f, 0.274174f, 0.295650f,
+ 0.317950f, 0.341081f, 0.365053f, 0.389874f, 0.415553f, 0.442098f, 0.469512f, 0.497794f,
+ 0.526935f, 0.556908f, 0.587657f, 0.619060f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000083f, 0.000665f, 0.001962f, 0.004059f,
+ 0.006997f, 0.010790f, 0.015442f, 0.020949f, 0.027304f, 0.034497f, 0.042518f, 0.051358f,
+ 0.061005f, 0.071451f, 0.082688f, 0.094709f, 0.107507f, 0.121078f, 0.135419f, 0.150526f,
+ 0.166399f, 0.183038f, 0.200443f, 0.218618f, 0.237566f, 0.257291f, 0.277800f, 0.299100f,
+ 0.321199f, 0.344106f, 0.367830f, 0.392383f, 0.417774f, 0.444013f, 0.471107f, 0.499060f,
+ 0.527869f, 0.557517f, 0.587966f, 0.619130f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000233f, 0.001082f, 0.002688f, 0.005111f,
+ 0.008377f, 0.012493f, 0.017456f, 0.023260f, 0.029893f, 0.037345f, 0.045604f, 0.054659f,
+ 0.064499f, 0.075115f, 0.086498f, 0.098641f, 0.111537f, 0.125182f, 0.139571f, 0.154703f,
+ 0.170576f, 0.187190f, 0.204547f, 0.222648f, 0.241498f, 0.261101f, 0.281465f, 0.302595f,
+ 0.324501f, 0.347192f, 0.370679f, 0.394973f, 0.420085f, 0.446027f, 0.472810f, 0.500441f,
+ 0.528921f, 0.558244f, 0.588384f, 0.619281f, 0.650795f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000033f, 0.000477f, 0.001611f, 0.003532f, 0.006280f,
+ 0.009869f, 0.014301f, 0.019568f, 0.025659f, 0.032563f, 0.040265f, 0.048753f, 0.058016f,
+ 0.068042f, 0.078821f, 0.090344f, 0.102604f, 0.115594f, 0.129309f, 0.143745f, 0.158901f,
+ 0.174774f, 0.191365f, 0.208674f, 0.226705f, 0.245461f, 0.264947f, 0.285170f, 0.306137f,
+ 0.327857f, 0.350341f, 0.373598f, 0.397642f, 0.422485f, 0.448139f, 0.474619f, 0.501933f,
+ 0.530089f, 0.559087f, 0.588913f, 0.619525f, 0.650826f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000130f, 0.000821f, 0.002252f, 0.004491f, 0.007562f,
+ 0.011472f, 0.016213f, 0.021776f, 0.028147f, 0.035312f, 0.043256f, 0.051966f, 0.061430f,
+ 0.071635f, 0.082571f, 0.094229f, 0.106602f, 0.119682f, 0.133465f, 0.147947f, 0.163125f,
+ 0.178998f, 0.195566f, 0.212830f, 0.230793f, 0.249459f, 0.268832f, 0.288920f, 0.309730f,
+ 0.331271f, 0.353554f, 0.376590f, 0.400391f, 0.424973f, 0.450347f, 0.476531f, 0.503535f,
+ 0.531372f, 0.560047f, 0.589554f, 0.619869f, 0.650923f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000005f, 0.000309f, 0.001270f, 0.003008f, 0.005566f, 0.008959f,
+ 0.013183f, 0.018228f, 0.024080f, 0.030723f, 0.038142f, 0.046321f, 0.055246f, 0.064903f,
+ 0.075281f, 0.086369f, 0.098158f, 0.110639f, 0.123806f, 0.137655f, 0.152180f, 0.167380f,
+ 0.183253f, 0.199799f, 0.217020f, 0.234918f, 0.253496f, 0.272761f, 0.292719f, 0.313377f,
+ 0.334745f, 0.356833f, 0.379654f, 0.403221f, 0.427548f, 0.452651f, 0.478545f, 0.505246f,
+ 0.532768f, 0.561122f, 0.590309f, 0.620318f, 0.651102f, 0.682545f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000053f, 0.000579f, 0.001828f, 0.003878f, 0.006757f, 0.010468f,
+ 0.015002f, 0.020344f, 0.026479f, 0.033388f, 0.041054f, 0.049461f, 0.058594f, 0.068440f,
+ 0.078985f, 0.090220f, 0.102134f, 0.114721f, 0.127972f, 0.141884f, 0.156451f, 0.171672f,
+ 0.187545f, 0.204070f, 0.221249f, 0.239083f, 0.257578f, 0.276738f, 0.296569f, 0.317080f,
+ 0.338281f, 0.360181f, 0.382794f, 0.406133f, 0.430213f, 0.455050f, 0.480662f, 0.507065f,
+ 0.534278f, 0.562313f, 0.591180f, 0.620875f, 0.651373f, 0.682593f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000169f, 0.000949f, 0.002497f, 0.004864f, 0.008063f, 0.012089f,
+ 0.016929f, 0.022563f, 0.028974f, 0.036142f, 0.044049f, 0.052678f, 0.062014f, 0.072042f,
+ 0.082750f, 0.094127f, 0.106164f, 0.118852f, 0.132185f, 0.146157f, 0.160766f, 0.176007f,
+ 0.191880f, 0.208385f, 0.225523f, 0.243296f, 0.261709f, 0.280767f, 0.300476f, 0.320845f,
+ 0.341883f, 0.363601f, 0.386011f, 0.409128f, 0.432967f, 0.457545f, 0.482881f, 0.508992f,
+ 0.535899f, 0.563619f, 0.592165f, 0.621544f, 0.651743f, 0.682709f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000010f, 0.000368f, 0.001423f, 0.003279f, 0.005966f, 0.009485f, 0.013824f,
+ 0.018964f, 0.024886f, 0.031567f, 0.038988f, 0.047130f, 0.055975f, 0.065508f, 0.075714f,
+ 0.086580f, 0.098095f, 0.110251f, 0.123038f, 0.136450f, 0.150482f, 0.165129f, 0.180390f,
+ 0.196263f, 0.212748f, 0.229847f, 0.247561f, 0.265895f, 0.284854f, 0.304445f, 0.324675f,
+ 0.345555f, 0.367095f, 0.389309f, 0.412210f, 0.435814f, 0.460138f, 0.485203f, 0.511028f,
+ 0.537634f, 0.565041f, 0.593268f, 0.622327f, 0.652217f, 0.682907f, 0.714296f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000068f, 0.000658f, 0.002006f, 0.004178f, 0.007186f, 0.011024f, 0.015672f,
+ 0.021109f, 0.027312f, 0.034259f, 0.041928f, 0.050300f, 0.059356f, 0.069081f, 0.079460f,
+ 0.090480f, 0.102130f, 0.114400f, 0.127284f, 0.140772f, 0.154862f, 0.169548f, 0.184828f,
+ 0.200701f, 0.217167f, 0.234227f, 0.251884f, 0.270141f, 0.289004f, 0.308479f, 0.328575f,
+ 0.349301f, 0.370668f, 0.392689f, 0.415379f, 0.438754f, 0.462830f, 0.487630f, 0.513173f,
+ 0.539482f, 0.566579f, 0.594488f, 0.623226f, 0.652800f, 0.683198f, 0.714354f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000196f, 0.001048f, 0.002702f, 0.005194f, 0.008526f, 0.012680f, 0.017635f,
+ 0.023365f, 0.029846f, 0.037053f, 0.044965f, 0.053561f, 0.062824f, 0.072737f, 0.083284f,
+ 0.094454f, 0.106236f, 0.118619f, 0.131595f, 0.145159f, 0.159305f, 0.174028f, 0.189327f,
+ 0.205200f, 0.221647f, 0.238670f, 0.256270f, 0.274453f, 0.293222f, 0.312585f, 0.332550f,
+ 0.353126f, 0.374324f, 0.396158f, 0.418641f, 0.441790f, 0.465624f, 0.490163f, 0.515429f,
+ 0.541445f, 0.568236f, 0.595828f, 0.624242f, 0.653496f, 0.683588f, 0.714482f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000012f, 0.000407f, 0.001545f, 0.003514f, 0.006332f, 0.009987f, 0.014457f, 0.019715f,
+ 0.025734f, 0.032488f, 0.039952f, 0.048102f, 0.056919f, 0.066384f, 0.076480f, 0.087193f,
+ 0.098509f, 0.110419f, 0.122912f, 0.135980f, 0.149617f, 0.163817f, 0.178577f, 0.193894f,
+ 0.209767f, 0.226196f, 0.243182f, 0.260728f, 0.278837f, 0.297515f, 0.316768f, 0.336605f,
+ 0.357034f, 0.378067f, 0.399717f, 0.421998f, 0.444928f, 0.468523f, 0.492806f, 0.517798f,
+ 0.543525f, 0.570012f, 0.597288f, 0.625379f, 0.654307f, 0.684084f, 0.714693f, 0.746044f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000074f, 0.000713f, 0.002152f, 0.004446f, 0.007592f, 0.011571f, 0.016356f, 0.021915f,
+ 0.028220f, 0.035243f, 0.042959f, 0.051344f, 0.060377f, 0.070040f, 0.080316f, 0.091191f,
+ 0.102651f, 0.114686f, 0.127286f, 0.140443f, 0.154151f, 0.168405f, 0.183201f, 0.198536f,
+ 0.214409f, 0.230820f, 0.247770f, 0.265263f, 0.283301f, 0.301889f, 0.321035f, 0.340746f,
+ 0.361032f, 0.381904f, 0.403374f, 0.425457f, 0.448169f, 0.471530f, 0.495561f, 0.520284f,
+ 0.545725f, 0.571911f, 0.598873f, 0.626640f, 0.655239f, 0.684692f, 0.714999f, 0.746106f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000208f, 0.001121f, 0.002877f, 0.005501f, 0.008979f, 0.013283f, 0.018380f, 0.024238f,
+ 0.030826f, 0.038115f, 0.046079f, 0.054695f, 0.063941f, 0.073799f, 0.084252f, 0.095285f,
+ 0.106886f, 0.119044f, 0.131749f, 0.144994f, 0.158772f, 0.173078f, 0.187908f, 0.203261f,
+ 0.219134f, 0.235527f, 0.252443f, 0.269883f, 0.287851f, 0.306352f, 0.325393f, 0.344981f,
+ 0.365126f, 0.385839f, 0.407132f, 0.429020f, 0.451520f, 0.474651f, 0.498433f, 0.522890f,
+ 0.548048f, 0.573936f, 0.600584f, 0.628027f, 0.656295f, 0.685417f, 0.715406f, 0.746240f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000011f,
+ 0.000427f, 0.001638f, 0.003724f, 0.006685f, 0.010497f, 0.015125f, 0.020534f, 0.026688f,
+ 0.033557f, 0.041109f, 0.049318f, 0.058161f, 0.067617f, 0.077666f, 0.088293f, 0.099482f,
+ 0.111221f, 0.123499f, 0.136308f, 0.149639f, 0.163485f, 0.177843f, 0.192707f, 0.208077f,
+ 0.223950f, 0.240326f, 0.257208f, 0.274596f, 0.292496f, 0.310911f, 0.329849f, 0.349316f,
+ 0.369323f, 0.389880f, 0.410999f, 0.432696f, 0.454987f, 0.477890f, 0.501426f, 0.525620f,
+ 0.550498f, 0.576089f, 0.602427f, 0.629544f, 0.657479f, 0.686264f, 0.715924f, 0.746459f,
+ 0.777789f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000071f,
+ 0.000744f, 0.002274f, 0.004698f, 0.008002f, 0.012149f, 0.017102f, 0.022822f, 0.029271f,
+ 0.036417f, 0.044229f, 0.052681f, 0.061749f, 0.071411f, 0.081649f, 0.092447f, 0.103790f,
+ 0.115665f, 0.128062f, 0.140972f, 0.154387f, 0.168301f, 0.182709f, 0.197608f, 0.212994f,
+ 0.228867f, 0.245227f, 0.262074f, 0.279412f, 0.297244f, 0.315575f, 0.334412f, 0.353760f,
+ 0.373631f, 0.394034f, 0.414983f, 0.436491f, 0.458575f, 0.481253f, 0.504547f, 0.528481f,
+ 0.553081f, 0.578377f, 0.604404f, 0.631197f, 0.658795f, 0.687238f, 0.716559f, 0.746776f,
+ 0.777849f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000205f,
+ 0.001168f, 0.003033f, 0.005806f, 0.009456f, 0.013942f, 0.019220f, 0.025250f, 0.031992f,
+ 0.039414f, 0.047484f, 0.056176f, 0.065466f, 0.075333f, 0.085757f, 0.096724f, 0.108218f,
+ 0.120227f, 0.132741f, 0.145751f, 0.159249f, 0.173230f, 0.187687f, 0.202619f, 0.218021f,
+ 0.233894f, 0.250238f, 0.267052f, 0.284341f, 0.302106f, 0.320354f, 0.339090f, 0.358322f,
+ 0.378059f, 0.398311f, 0.419090f, 0.440412f, 0.462292f, 0.484748f, 0.507802f, 0.531477f,
+ 0.555802f, 0.580805f, 0.606522f, 0.632990f, 0.660250f, 0.688346f, 0.717319f, 0.747200f,
+ 0.777982f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000427f,
+ 0.001710f, 0.003925f, 0.007054f, 0.011055f, 0.015881f, 0.021485f, 0.027824f, 0.034859f,
+ 0.042554f, 0.050881f, 0.059811f, 0.069321f, 0.079390f, 0.089998f, 0.101132f, 0.112775f,
+ 0.124917f, 0.137547f, 0.150655f, 0.164236f, 0.178281f, 0.192788f, 0.207752f, 0.223171f,
+ 0.239044f, 0.255371f, 0.272153f, 0.289393f, 0.307093f, 0.325259f, 0.343896f, 0.363012f,
+ 0.382617f, 0.402719f, 0.423332f, 0.444469f, 0.466146f, 0.488383f, 0.511199f, 0.534618f,
+ 0.558668f, 0.583380f, 0.608787f, 0.634929f, 0.661849f, 0.689594f, 0.718211f, 0.747742f,
+ 0.778205f, 0.809530f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000059f, 0.000754f,
+ 0.002379f, 0.004956f, 0.008449f, 0.012806f, 0.017974f, 0.023905f, 0.030553f, 0.037879f,
+ 0.045847f, 0.054429f, 0.063595f, 0.073323f, 0.083592f, 0.094384f, 0.105682f, 0.117474f,
+ 0.129747f, 0.142491f, 0.155697f, 0.169358f, 0.183469f, 0.198024f, 0.213020f, 0.228455f,
+ 0.244329f, 0.260639f, 0.277389f, 0.294580f, 0.312216f, 0.330300f, 0.348840f, 0.367842f,
+ 0.387315f, 0.407270f, 0.427717f, 0.448671f, 0.470149f, 0.492167f, 0.514746f, 0.537911f,
+ 0.561688f, 0.586108f, 0.611206f, 0.637022f, 0.663599f, 0.690989f, 0.719242f, 0.748411f,
+ 0.778531f, 0.809583f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000187f, 0.001196f,
+ 0.003184f, 0.006136f, 0.010000f, 0.014716f, 0.020230f, 0.026488f, 0.033445f, 0.041062f,
+ 0.049303f, 0.058138f, 0.067540f, 0.077485f, 0.087953f, 0.098926f, 0.110388f, 0.122327f,
+ 0.134729f, 0.147587f, 0.160889f, 0.174631f, 0.188806f, 0.203409f, 0.218437f, 0.233888f,
+ 0.249761f, 0.266056f, 0.282774f, 0.299917f, 0.317488f, 0.335493f, 0.353936f, 0.372825f,
+ 0.392168f, 0.411976f, 0.432259f, 0.453032f, 0.474310f, 0.496111f, 0.518456f, 0.541367f,
+ 0.564872f, 0.589001f, 0.613789f, 0.639277f, 0.665510f, 0.692539f, 0.720422f, 0.749216f,
+ 0.778974f, 0.809711f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000409f, 0.001767f,
+ 0.004137f, 0.007474f, 0.011716f, 0.016797f, 0.022657f, 0.029244f, 0.036512f, 0.044420f,
+ 0.052933f, 0.062021f, 0.071657f, 0.081819f, 0.092485f, 0.103638f, 0.115263f, 0.127348f,
+ 0.139880f, 0.152849f, 0.166248f, 0.180070f, 0.194308f, 0.208958f, 0.224018f, 0.239485f,
+ 0.255359f, 0.271638f, 0.288324f, 0.305419f, 0.322927f, 0.340851f, 0.359199f, 0.377975f,
+ 0.397189f, 0.416851f, 0.436971f, 0.457564f, 0.478644f, 0.500229f, 0.522339f, 0.544997f,
+ 0.568230f, 0.592068f, 0.616546f, 0.641705f, 0.667590f, 0.694255f, 0.721760f, 0.750168f,
+ 0.779545f, 0.809933f, 0.841272f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000041f, 0.000744f, 0.002481f,
+ 0.005248f, 0.008982f, 0.013608f, 0.019058f, 0.025269f, 0.032188f, 0.039767f, 0.047967f,
+ 0.056752f, 0.066093f, 0.075963f, 0.086340f, 0.097203f, 0.108537f, 0.120325f, 0.132554f,
+ 0.145215f, 0.158296f, 0.171790f, 0.185691f, 0.199993f, 0.214691f, 0.229782f, 0.245265f,
+ 0.261138f, 0.277401f, 0.294056f, 0.311104f, 0.328548f, 0.346394f, 0.364645f, 0.383310f,
+ 0.402396f, 0.421912f, 0.441870f, 0.462283f, 0.483165f, 0.504535f, 0.526410f, 0.548816f,
+ 0.571776f, 0.595323f, 0.619489f, 0.644317f, 0.669852f, 0.696148f, 0.723267f, 0.751280f,
+ 0.780258f, 0.810268f, 0.841311f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000156f, 0.001209f, 0.003349f,
+ 0.006531f, 0.010672f, 0.015691f, 0.021515f, 0.028080f, 0.035332f, 0.043225f, 0.051717f,
+ 0.060775f, 0.070370f, 0.080474f, 0.091067f, 0.102128f, 0.113641f, 0.125591f, 0.137965f,
+ 0.150754f, 0.163947f, 0.177537f, 0.191516f, 0.205881f, 0.220626f, 0.235749f, 0.251248f,
+ 0.267121f, 0.283368f, 0.299992f, 0.316992f, 0.334374f, 0.352140f, 0.370296f, 0.388849f,
+ 0.407807f, 0.427178f, 0.446974f, 0.467207f, 0.487892f, 0.509046f, 0.530687f, 0.552839f,
+ 0.575527f, 0.598780f, 0.622634f, 0.647128f, 0.672308f, 0.698231f, 0.724958f, 0.752563f,
+ 0.781127f, 0.810733f, 0.841426f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000374f, 0.001821f, 0.004389f,
+ 0.008001f, 0.012559f, 0.017979f, 0.024182f, 0.031106f, 0.038695f, 0.046903f, 0.055690f,
+ 0.065023f, 0.074872f, 0.085211f, 0.096020f, 0.107279f, 0.118971f, 0.131084f, 0.143604f,
+ 0.156521f, 0.169825f, 0.183510f, 0.197569f, 0.211997f, 0.226789f, 0.241944f, 0.257458f,
+ 0.273331f, 0.289563f, 0.306154f, 0.323108f, 0.340426f, 0.358113f, 0.376175f, 0.394616f,
+ 0.413445f, 0.432671f, 0.452305f, 0.472358f, 0.492845f, 0.513783f, 0.535189f, 0.557087f,
+ 0.579500f, 0.602459f, 0.625997f, 0.650154f, 0.674976f, 0.700518f, 0.726845f, 0.754032f,
+ 0.782167f, 0.811344f, 0.841644f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000020f, 0.000719f, 0.002598f, 0.005618f,
+ 0.009675f, 0.014663f, 0.020490f, 0.027080f, 0.034367f, 0.042297f, 0.050824f, 0.059909f,
+ 0.069517f, 0.079622f, 0.090198f, 0.101224f, 0.112682f, 0.124555f, 0.136831f, 0.149496f,
+ 0.162542f, 0.175958f, 0.189739f, 0.203877f, 0.218368f, 0.233208f, 0.248393f, 0.263923f,
+ 0.279796f, 0.296012f, 0.312573f, 0.329479f, 0.346734f, 0.364342f, 0.382307f, 0.400637f,
+ 0.419337f, 0.438418f, 0.457889f, 0.477761f, 0.498050f, 0.518770f, 0.539940f, 0.561581f,
+ 0.583718f, 0.606380f, 0.629599f, 0.653415f, 0.677874f, 0.703030f, 0.728948f, 0.755706f,
+ 0.783396f, 0.812121f, 0.841989f, 0.873035f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000114f, 0.001215f, 0.003561f, 0.007056f,
+ 0.011574f, 0.017003f, 0.023248f, 0.030232f, 0.037888f, 0.046164f, 0.055014f, 0.064399f,
+ 0.074287f, 0.084650f, 0.095464f, 0.106709f, 0.118367f, 0.130423f, 0.142862f, 0.155674f,
+ 0.168849f, 0.182378f, 0.196255f, 0.210473f, 0.225027f, 0.239915f, 0.255132f, 0.270678f,
+ 0.286551f, 0.302751f, 0.319280f, 0.336138f, 0.353330f, 0.370858f, 0.388728f, 0.406944f,
+ 0.425515f, 0.444449f, 0.463756f, 0.483447f, 0.503535f, 0.524036f, 0.544968f, 0.566350f,
+ 0.588208f, 0.610569f, 0.633466f, 0.656936f, 0.681025f, 0.705788f, 0.731289f, 0.757606f,
+ 0.784834f, 0.813085f, 0.842485f, 0.873130f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000324f, 0.001887f, 0.004735f, 0.008727f,
+ 0.013724f, 0.019607f, 0.026280f, 0.033666f, 0.041699f, 0.050326f, 0.059504f, 0.069194f,
+ 0.079365f, 0.089989f, 0.101045f, 0.112512f, 0.124372f, 0.136611f, 0.149216f, 0.162176f,
+ 0.175482f, 0.189125f, 0.203098f, 0.217396f, 0.232015f, 0.246950f, 0.262200f, 0.277761f,
+ 0.293634f, 0.309819f, 0.326315f, 0.343126f, 0.360254f, 0.377701f, 0.395474f, 0.413577f,
+ 0.432018f, 0.450804f, 0.469944f, 0.489451f, 0.509337f, 0.529617f, 0.550307f, 0.571428f,
+ 0.593003f, 0.615059f, 0.637628f, 0.660746f, 0.684460f, 0.708820f, 0.733893f, 0.759756f,
+ 0.786505f, 0.814259f, 0.843157f, 0.873340f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000683f, 0.002764f, 0.006148f, 0.010661f,
+ 0.016155f, 0.022506f, 0.029620f, 0.037417f, 0.045835f, 0.054821f, 0.064333f, 0.074333f,
+ 0.084792f, 0.095683f, 0.106984f, 0.118675f, 0.130741f, 0.143166f, 0.155939f, 0.169049f,
+ 0.182487f, 0.196245f, 0.210317f, 0.224697f, 0.239380f, 0.254364f, 0.269646f, 0.285223f,
+ 0.301096f, 0.317265f, 0.333729f, 0.350491f, 0.367554f, 0.384920f, 0.402594f, 0.420582f,
+ 0.438891f, 0.457527f, 0.476499f, 0.495820f, 0.515500f, 0.535555f, 0.556000f, 0.576855f,
+ 0.598143f, 0.619888f, 0.642123f, 0.664883f, 0.688211f, 0.712160f, 0.736792f, 0.762186f,
+ 0.788439f, 0.815672f, 0.844034f, 0.873699f, 0.904765f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000066f, 0.001228f, 0.003880f, 0.007835f, 0.012895f,
+ 0.018905f, 0.025742f, 0.033309f, 0.041530f, 0.050342f, 0.059696f, 0.069550f, 0.079868f,
+ 0.090620f, 0.101783f, 0.113333f, 0.125254f, 0.137529f, 0.150144f, 0.163088f, 0.176351f,
+ 0.189924f, 0.203799f, 0.217970f, 0.232433f, 0.247182f, 0.262216f, 0.277530f, 0.293124f,
+ 0.308997f, 0.325149f, 0.341581f, 0.358294f, 0.375290f, 0.392573f, 0.410148f, 0.428019f,
+ 0.446192f, 0.464676f, 0.483478f, 0.502608f, 0.522079f, 0.541905f, 0.562100f, 0.582684f,
+ 0.603677f, 0.625106f, 0.646998f, 0.669390f, 0.692324f, 0.715849f, 0.740028f, 0.764937f,
+ 0.790673f, 0.817358f, 0.845150f, 0.874244f, 0.904828f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000260f, 0.002001f, 0.005278f, 0.009840f, 0.015475f,
+ 0.022025f, 0.029365f, 0.037402f, 0.046060f, 0.055280f, 0.065013f, 0.075218f, 0.085861f,
+ 0.096916f, 0.108356f, 0.120163f, 0.132319f, 0.144808f, 0.157618f, 0.170737f, 0.184155f,
+ 0.197866f, 0.211861f, 0.226134f, 0.240682f, 0.255499f, 0.270583f, 0.285931f, 0.301542f,
+ 0.317415f, 0.333550f, 0.349948f, 0.366610f, 0.383539f, 0.400738f, 0.418210f, 0.435961f,
+ 0.453997f, 0.472324f, 0.490951f, 0.509887f, 0.529144f, 0.548735f, 0.568674f, 0.588979f,
+ 0.609671f, 0.630773f, 0.652314f, 0.674328f, 0.696854f, 0.719942f, 0.743651f, 0.768057f,
+ 0.793253f, 0.819363f, 0.846547f, 0.875017f, 0.905021f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000642f, 0.003053f, 0.007010f, 0.012219f, 0.018462f,
+ 0.025577f, 0.033444f, 0.041970f, 0.051082f, 0.060724f, 0.070849f, 0.081417f, 0.092397f,
+ 0.103763f, 0.115491f, 0.127562f, 0.139960f, 0.152670f, 0.165679f, 0.178979f, 0.192558f,
+ 0.206410f, 0.220529f, 0.234907f, 0.249542f, 0.264428f, 0.279564f, 0.294947f, 0.310575f,
+ 0.326448f, 0.342566f, 0.358929f, 0.375540f, 0.392399f, 0.409511f, 0.426878f, 0.444506f,
+ 0.462400f, 0.480566f, 0.499013f, 0.517749f, 0.536785f, 0.556134f, 0.575809f, 0.595827f,
+ 0.616207f, 0.636973f, 0.658150f, 0.679772f, 0.701876f, 0.724509f, 0.747730f, 0.771609f,
+ 0.796240f, 0.821743f, 0.848280f, 0.876069f, 0.905404f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000020f, 0.001278f, 0.004450f, 0.009147f, 0.015050f, 0.021937f,
+ 0.029649f, 0.038068f, 0.047106f, 0.056694f, 0.066777f, 0.077310f, 0.088257f, 0.099588f,
+ 0.111277f, 0.123304f, 0.135650f, 0.148299f, 0.161237f, 0.174455f, 0.187941f, 0.201687f,
+ 0.215687f, 0.229933f, 0.244420f, 0.259145f, 0.274103f, 0.289293f, 0.304711f, 0.320357f,
+ 0.336230f, 0.352330f, 0.368658f, 0.385214f, 0.402002f, 0.419023f, 0.436282f, 0.453782f,
+ 0.471529f, 0.489528f, 0.507788f, 0.526317f, 0.545124f, 0.564221f, 0.583621f, 0.603341f,
+ 0.623397f, 0.643812f, 0.664611f, 0.685824f, 0.707488f, 0.729646f, 0.752354f, 0.775680f,
+ 0.799715f, 0.824574f, 0.850417f, 0.877466f, 0.906040f, 0.936528f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000183f, 0.002253f, 0.006282f, 0.011786f, 0.018436f, 0.026011f,
+ 0.034358f, 0.043364f, 0.052944f, 0.063033f, 0.073580f, 0.084544f, 0.095889f, 0.107588f,
+ 0.119617f, 0.131957f, 0.144591f, 0.157503f, 0.170682f, 0.184117f, 0.197799f, 0.211720f,
+ 0.225873f, 0.240253f, 0.254854f, 0.269673f, 0.284707f, 0.299953f, 0.315408f, 0.331073f,
+ 0.346946f, 0.363028f, 0.379318f, 0.395818f, 0.412530f, 0.429457f, 0.446602f, 0.463968f,
+ 0.481561f, 0.499386f, 0.517450f, 0.535761f, 0.554328f, 0.573162f, 0.592275f, 0.611681f,
+ 0.631398f, 0.651445f, 0.671845f, 0.692628f, 0.713827f, 0.735484f, 0.757650f, 0.780390f,
+ 0.803789f, 0.827960f, 0.853056f, 0.879298f, 0.907014f, 0.936691f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000617f, 0.003679f, 0.008674f, 0.015068f, 0.022531f, 0.030851f,
+ 0.039880f, 0.049515f, 0.059675f, 0.070300f, 0.081343f, 0.092764f, 0.104533f, 0.116624f,
+ 0.129015f, 0.141687f, 0.154626f, 0.167818f, 0.181252f, 0.194918f, 0.208807f, 0.222913f,
+ 0.237229f, 0.251750f, 0.266473f, 0.281392f, 0.296505f, 0.311811f, 0.327306f, 0.342991f,
+ 0.358864f, 0.374925f, 0.391176f, 0.407616f, 0.424249f, 0.441076f, 0.458100f, 0.475324f,
+ 0.492754f, 0.510394f, 0.528251f, 0.546331f, 0.564644f, 0.583198f, 0.602005f, 0.621078f,
+ 0.640434f, 0.660089f, 0.680066f, 0.700390f, 0.721094f, 0.742215f, 0.763800f, 0.785912f,
+ 0.808628f, 0.832055f, 0.856338f, 0.881690f, 0.908441f, 0.937125f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.001477f, 0.005732f, 0.011826f, 0.019212f, 0.027573f, 0.036710f,
+ 0.046487f, 0.056807f, 0.067598f, 0.078806f, 0.090386f, 0.102304f, 0.114532f, 0.127047f,
+ 0.139828f, 0.152861f, 0.166130f, 0.179624f, 0.193332f, 0.207247f, 0.221360f, 0.235666f,
+ 0.250158f, 0.264832f, 0.279684f, 0.294711f, 0.309911f, 0.325280f, 0.340819f, 0.356524f,
+ 0.372397f, 0.388438f, 0.404645f, 0.421022f, 0.437569f, 0.454287f, 0.471181f, 0.488253f,
+ 0.505507f, 0.522947f, 0.540580f, 0.558412f, 0.576449f, 0.594701f, 0.613178f, 0.631892f,
+ 0.650856f, 0.670088f, 0.689606f, 0.709434f, 0.729600f, 0.750138f, 0.771093f, 0.792519f,
+ 0.814488f, 0.837097f, 0.860481f, 0.884842f, 0.910494f, 0.937985f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000096f, 0.003012f, 0.008704f, 0.016071f, 0.024590f, 0.033968f, 0.044025f,
+ 0.054641f, 0.065728f, 0.077225f, 0.089081f, 0.101260f, 0.113731f, 0.126469f, 0.139454f,
+ 0.152670f, 0.166101f, 0.179736f, 0.193565f, 0.207578f, 0.221769f, 0.236130f, 0.250656f,
+ 0.265343f, 0.280187f, 0.295183f, 0.310330f, 0.325624f, 0.341065f, 0.356650f, 0.372380f,
+ 0.388253f, 0.404269f, 0.420430f, 0.436735f, 0.453187f, 0.469786f, 0.486536f, 0.503439f,
+ 0.520498f, 0.537717f, 0.555102f, 0.572657f, 0.590390f, 0.608307f, 0.626419f, 0.644733f,
+ 0.663264f, 0.682025f, 0.701032f, 0.720308f, 0.739875f, 0.759764f, 0.780014f, 0.800673f,
+ 0.821803f, 0.843492f, 0.865860f, 0.889087f, 0.913466f, 0.939520f, 0.968350f, 1.000000f,
+ 0.000000f, 0.000727f, 0.005696f, 0.013170f, 0.022074f, 0.031940f, 0.042520f, 0.053660f,
+ 0.065258f, 0.077243f, 0.089562f, 0.102175f, 0.115050f, 0.128164f, 0.141495f, 0.155026f,
+ 0.168745f, 0.182639f, 0.196699f, 0.210915f, 0.225282f, 0.239792f, 0.254440f, 0.269223f,
+ 0.284135f, 0.299174f, 0.314337f, 0.329622f, 0.345026f, 0.360549f, 0.376189f, 0.391946f,
+ 0.407819f, 0.423808f, 0.439914f, 0.456137f, 0.472479f, 0.488940f, 0.505523f, 0.522230f,
+ 0.539064f, 0.556028f, 0.573125f, 0.590361f, 0.607741f, 0.625270f, 0.642957f, 0.660809f,
+ 0.678836f, 0.697050f, 0.715465f, 0.734098f, 0.752968f, 0.772101f, 0.791529f, 0.811290f,
+ 0.831438f, 0.852044f, 0.873210f, 0.895090f, 0.917932f, 0.942204f, 0.968981f, 1.000000f,
+ 0.000000f, 0.002796f, 0.010764f, 0.020645f, 0.031576f, 0.043202f, 0.055340f, 0.067877f,
+ 0.080740f, 0.093877f, 0.107250f, 0.120832f, 0.134598f, 0.148533f, 0.162620f, 0.176849f,
+ 0.191210f, 0.205694f, 0.220294f, 0.235005f, 0.249820f, 0.264737f, 0.279751f, 0.294859f,
+ 0.310058f, 0.325346f, 0.340721f, 0.356181f, 0.371725f, 0.387353f, 0.403063f, 0.418854f,
+ 0.434727f, 0.450682f, 0.466718f, 0.482837f, 0.499038f, 0.515324f, 0.531695f, 0.548153f,
+ 0.564700f, 0.581338f, 0.598070f, 0.614900f, 0.631830f, 0.648865f, 0.666011f, 0.683273f,
+ 0.700659f, 0.718176f, 0.735834f, 0.753646f, 0.771625f, 0.789790f, 0.808162f, 0.826771f,
+ 0.845654f, 0.864863f, 0.884472f, 0.904592f, 0.925407f, 0.947271f, 0.971050f, 1.000000f,
+ 0.000000f, 0.015873f, 0.031746f, 0.047619f, 0.063492f, 0.079365f, 0.095238f, 0.111111f,
+ 0.126984f, 0.142857f, 0.158730f, 0.174603f, 0.190476f, 0.206349f, 0.222222f, 0.238095f,
+ 0.253968f, 0.269841f, 0.285714f, 0.301587f, 0.317460f, 0.333333f, 0.349206f, 0.365079f,
+ 0.380952f, 0.396825f, 0.412698f, 0.428571f, 0.444444f, 0.460317f, 0.476190f, 0.492063f,
+ 0.507937f, 0.523810f, 0.539683f, 0.555556f, 0.571429f, 0.587302f, 0.603175f, 0.619048f,
+ 0.634921f, 0.650794f, 0.666667f, 0.682540f, 0.698413f, 0.714286f, 0.730159f, 0.746032f,
+ 0.761905f, 0.777778f, 0.793651f, 0.809524f, 0.825397f, 0.841270f, 0.857143f, 0.873016f,
+ 0.888889f, 0.904762f, 0.920635f, 0.936508f, 0.952381f, 0.968254f, 0.984127f, 1.000000f
+};
+
static float btdf_split_sum_ggx[32][64 * 64] = {
{
0.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f,
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index c25ab1e7859..84627e03137 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -28,6 +28,8 @@
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_alloca.h"
+#include "BLI_rand.h"
+#include "BLI_string_utils.h"
#include "BKE_particle.h"
#include "BKE_paint.h"
@@ -51,16 +53,18 @@ static struct {
struct GPUShader *default_prepass_sh;
struct GPUShader *default_prepass_clip_sh;
struct GPUShader *default_lit[VAR_MAT_MAX];
-
struct GPUShader *default_background;
+ struct GPUShader *update_noise_sh;
/* 64*64 array texture containing all LUTs and other utilitarian arrays.
* Packing enables us to same precious textures slots. */
struct GPUTexture *util_tex;
+ struct GPUTexture *noise_tex;
unsigned int sss_count;
- float viewvecs[2][4];
+ float alpha_hash_offset;
+ float noise_offsets[3];
} e_data = {NULL}; /* Engine data */
extern char datatoc_lamps_lib_glsl[];
@@ -76,6 +80,7 @@ extern char datatoc_btdf_lut_frag_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_direct_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_lit_surface_frag_glsl[];
@@ -87,6 +92,7 @@ extern char datatoc_shadow_geom_glsl[];
extern char datatoc_lightprobe_geom_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_background_vert_glsl[];
+extern char datatoc_update_noise_frag_glsl[];
extern char datatoc_volumetric_vert_glsl[];
extern char datatoc_volumetric_geom_glsl[];
extern char datatoc_volumetric_frag_glsl[];
@@ -105,13 +111,9 @@ static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h))
static float samples_ct = 8192.0f;
static float inv_samples_ct = 1.0f / 8192.0f;
- char *lib_str = NULL;
-
- DynStr *ds_vert = BLI_dynstr_new();
- BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_vert, datatoc_bsdf_sampling_lib_glsl);
- lib_str = BLI_dynstr_get_cstring(ds_vert);
- BLI_dynstr_free(ds_vert);
+ char *lib_str = BLI_string_joinN(
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl);
struct GPUShader *sh = DRW_shader_create_with_lib(
datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, datatoc_bsdf_lut_frag_glsl, lib_str,
@@ -167,14 +169,10 @@ static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h)
static float a2 = 0.0f;
static float inv_samples_ct = 1.0f / 8192.0f;
- char *frag_str = NULL;
-
- DynStr *ds_vert = BLI_dynstr_new();
- BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_vert, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_vert, datatoc_btdf_lut_frag_glsl);
- frag_str = BLI_dynstr_get_cstring(ds_vert);
- BLI_dynstr_free(ds_vert);
+ char *frag_str = BLI_string_joinN(
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_btdf_lut_frag_glsl);
struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str,
"#define HAMMERSLEY_SIZE 8192\n"
@@ -352,77 +350,67 @@ static char *eevee_get_volume_defines(int options)
**/
static void add_standard_uniforms(
DRWShadingGroup *shgrp, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
- int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend, bool use_sss)
+ int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend)
{
- if (ssr_id == NULL || !vedata->stl->g_data->valid_double_buffer) {
+ if (ssr_id == NULL) {
static int no_ssr = -1.0f;
ssr_id = &no_ssr;
}
+
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_int(shgrp, "light_count", &sldata->lamps->num_light, 1);
- DRW_shgroup_uniform_int(shgrp, "probe_count", &sldata->probes->num_render_cube, 1);
- DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1);
- DRW_shgroup_uniform_int(shgrp, "planar_count", &sldata->probes->num_planar, 1);
- DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 1);
- DRW_shgroup_uniform_bool(shgrp, "ssrToggle", &sldata->probes->ssr_toggle, 1);
- DRW_shgroup_uniform_float(shgrp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
- DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
- DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
- DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool);
- DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
- DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1);
- DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool);
- DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
- DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2);
- DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer);
- DRW_shgroup_uniform_vec2(shgrp, "mipRatio[0]", (float *)vedata->stl->g_data->mip_ratio, 10);
- DRW_shgroup_uniform_vec4(shgrp, "ssrParameters", &vedata->stl->effects->ssr_quality, 1);
-
- if (refract_depth != NULL) {
- DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1);
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+
+ /* TODO if glossy or diffuse bsdf */
+ if (true) {
+ DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
+ DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer);
+
+ if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) != 0) {
+ DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons);
+ }
+ else {
+ /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */
+ DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer);
+ }
}
- if (use_ssrefraction) {
- DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color);
- DRW_shgroup_uniform_float(shgrp, "borderFadeFactor", &vedata->stl->effects->ssr_border_fac, 1);
- DRW_shgroup_uniform_float(shgrp, "maxRoughness", &vedata->stl->effects->ssr_max_roughness, 1);
- DRW_shgroup_uniform_int(shgrp, "rayCount", &vedata->stl->effects->ssr_ray_count, 1);
+ /* TODO if diffuse bsdf */
+ if (true) {
+ DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
}
- if (vedata->stl->effects->use_ao) {
- DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons);
- DRW_shgroup_uniform_ivec2(shgrp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1);
+ /* TODO if glossy bsdf */
+ if (true) {
+ DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
}
- else {
- /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */
- DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &sldata->shadow_pool);
+
+ if (use_ssrefraction) {
+ BLI_assert(refract_depth != NULL);
+ DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1);
+ DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color);
}
- if (vedata->stl->effects->use_volumetrics && use_alpha_blend) {
+ if ((vedata->stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0 &&
+ use_alpha_blend)
+ {
/* Do not use history buffers as they already have been swapped */
DRW_shgroup_uniform_buffer(shgrp, "inScattering", &vedata->txl->volume_scatter);
DRW_shgroup_uniform_buffer(shgrp, "inTransmittance", &vedata->txl->volume_transmittance);
- DRW_shgroup_uniform_vec2(shgrp, "volume_uv_ratio", (float *)sldata->volumetrics->volume_coord_scale, 1);
- DRW_shgroup_uniform_vec3(shgrp, "volume_param", (float *)sldata->volumetrics->depth_param, 1);
- }
-
- if (use_sss) {
- DRW_shgroup_uniform_bool(shgrp, "sssToggle", &sldata->probes->sss_toggle, 1);
}
}
static void create_default_shader(int options)
{
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
- BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl);
- char *frag_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ char *frag_str = BLI_string_joinN(
+ e_data.frag_shader_lib,
+ datatoc_default_frag_glsl);
char *defines = eevee_get_defines(options);
@@ -432,11 +420,13 @@ static void create_default_shader(int options)
MEM_freeN(frag_str);
}
-void EEVEE_update_util_texture(float offset)
+static void eevee_init_noise_texture(void)
{
+ e_data.noise_tex = DRW_texture_create_2D(64, 64, DRW_TEX_RGBA_16, 0, (float *)blue_noise);
+}
- /* TODO: split this into 2 functions : one for init,
- * and the other one that updates the noise with the offset. */
+static void eevee_init_util_texture(void)
+{
const int layers = 3 + 16;
float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * 64 * 64 * layers, "utils texels");
float (*texels_layer)[4] = texels;
@@ -451,19 +441,16 @@ void EEVEE_update_util_texture(float offset)
texels_layer[i][0] = bsdf_split_sum_ggx[i * 2 + 0];
texels_layer[i][1] = bsdf_split_sum_ggx[i * 2 + 1];
texels_layer[i][2] = ltc_mag_ggx[i];
+ texels_layer[i][3] = ltc_disk_integral[i];
}
texels_layer += 64 * 64;
/* Copy blue noise in 3rd layer */
for (int i = 0; i < 64 * 64; i++) {
- float noise;
- noise = fmod(blue_noise[i][0] + offset, 1.0f);
- texels_layer[i][0] = noise;
-
- noise = fmod(blue_noise[i][1] + offset, 1.0f);
- texels_layer[i][1] = noise * 0.5f + 0.5f;
- texels_layer[i][2] = cosf(noise * 2.0f * M_PI);
- texels_layer[i][3] = sinf(noise * 2.0f * M_PI);
+ texels_layer[i][0] = blue_noise[i][0];
+ texels_layer[i][1] = blue_noise[i][1];
+ texels_layer[i][2] = cosf(blue_noise[i][1] * 2.0f * M_PI);
+ texels_layer[i][3] = sinf(blue_noise[i][1] * 2.0f * M_PI);
}
texels_layer += 64 * 64;
@@ -478,62 +465,72 @@ void EEVEE_update_util_texture(float offset)
texels_layer += 64 * 64;
}
- if (e_data.util_tex == NULL) {
- e_data.util_tex = DRW_texture_create_2D_array(
- 64, 64, layers, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels);
- }
- else {
- DRW_texture_update(e_data.util_tex, (float *)texels);
- }
+ e_data.util_tex = DRW_texture_create_2D_array(
+ 64, 64, layers, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels);
MEM_freeN(texels);
}
-void EEVEE_materials_init(EEVEE_StorageList *stl)
+void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double offsets[3])
+{
+ e_data.noise_offsets[0] = offsets[0];
+ e_data.noise_offsets[1] = offsets[1];
+ e_data.noise_offsets[2] = offsets[2];
+
+ /* Attach & detach because we don't currently support multiple FB per texture,
+ * and this would be the case for multiple viewport. */
+ DRW_framebuffer_texture_layer_attach(fbl->update_noise_fb, e_data.util_tex, 0, 2, 0);
+ DRW_framebuffer_bind(fbl->update_noise_fb);
+ DRW_draw_pass(psl->update_noise_pass);
+ DRW_framebuffer_texture_detach(e_data.util_tex);
+}
+
+void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl)
{
if (!e_data.frag_shader_lib) {
char *frag_str = NULL;
/* Shaders */
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ssr_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
- for (int i = 0; i < 7; ++i) {
- /* Add one for each Closure */
- BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl);
- }
- BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
- e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_volumetric_frag_glsl);
- e_data.volume_shader_lib = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
- BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl);
- frag_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ e_data.frag_shader_lib = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_ssr_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ltc_lib_glsl,
+ datatoc_bsdf_direct_lib_glsl,
+ datatoc_lamps_lib_glsl,
+ /* Add one for each Closure */
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_volumetric_lib_glsl);
+
+ e_data.volume_shader_lib = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ltc_lib_glsl,
+ datatoc_bsdf_direct_lib_glsl,
+ datatoc_lamps_lib_glsl,
+ datatoc_volumetric_lib_glsl,
+ datatoc_volumetric_frag_glsl);
+
+ frag_str = BLI_string_joinN(
+ e_data.frag_shader_lib,
+ datatoc_default_frag_glsl);
e_data.default_background = DRW_shader_create(
datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl,
@@ -549,16 +546,32 @@ void EEVEE_materials_init(EEVEE_StorageList *stl)
MEM_freeN(frag_str);
- EEVEE_update_util_texture(0.0f);
+ e_data.update_noise_sh = DRW_shader_create_fullscreen(
+ datatoc_update_noise_frag_glsl, NULL);
+
+ eevee_init_util_texture();
+ eevee_init_noise_texture();
}
+ /* Alpha hash scale: Non-flickering size if we are not refining the render. */
+ if (!DRW_state_is_image_render() &&
+ (((stl->effects->enabled_effects & EFFECT_TAA) == 0) ||
+ (stl->effects->taa_current_sample == 1)))
{
- /* Update viewvecs */
- const bool is_persp = DRW_viewport_is_persp_get();
+ e_data.alpha_hash_offset = 0.0f;
+ }
+ else {
+ double r;
+ BLI_halton_1D(5, 0.0, stl->effects->taa_current_sample, &r);
+ e_data.alpha_hash_offset = (float)r;
+ }
+
+ {
+ /* Update view_vecs */
float invproj[4][4], winmat[4][4];
/* view vectors for the corners of the view frustum.
* Can be used to recreate the world space position easily */
- float viewvecs[3][4] = {
+ float view_vecs[3][4] = {
{-1.0f, -1.0f, -1.0f, 1.0f},
{1.0f, -1.0f, -1.0f, 1.0f},
{-1.0f, 1.0f, -1.0f, 1.0f}
@@ -567,31 +580,39 @@ void EEVEE_materials_init(EEVEE_StorageList *stl)
/* invert the view matrix */
DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
invert_m4_m4(invproj, winmat);
+ const bool is_persp = (winmat[3][3] == 0.0f);
/* convert the view vectors to view space */
for (int i = 0; i < 3; i++) {
- mul_m4_v4(invproj, viewvecs[i]);
+ mul_m4_v4(invproj, view_vecs[i]);
/* normalized trick see:
* http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
+ mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][3]);
if (is_persp)
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
- viewvecs[i][3] = 1.0;
+ mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
+ view_vecs[i][3] = 1.0;
}
- copy_v4_v4(stl->g_data->viewvecs[0], viewvecs[0]);
- copy_v4_v4(stl->g_data->viewvecs[1], viewvecs[1]);
+ copy_v4_v4(sldata->common_data.view_vecs[0], view_vecs[0]);
+ copy_v4_v4(sldata->common_data.view_vecs[1], view_vecs[1]);
/* we need to store the differences */
- stl->g_data->viewvecs[1][0] -= viewvecs[0][0];
- stl->g_data->viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1];
+ sldata->common_data.view_vecs[1][0] -= view_vecs[0][0];
+ sldata->common_data.view_vecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
/* calculate a depth offset as well */
if (!is_persp) {
float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
mul_m4_v4(invproj, vec_far);
mul_v3_fl(vec_far, 1.0f / vec_far[3]);
- stl->g_data->viewvecs[1][2] = vec_far[2] - viewvecs[0][2];
+ sldata->common_data.view_vecs[1][2] = vec_far[2] - view_vecs[0][2];
+ }
+ }
+
+ {
+ /* Update noise Framebuffer. */
+ if (fbl->update_noise_fb == NULL) {
+ fbl->update_noise_fb = DRW_framebuffer_create();
}
}
}
@@ -652,6 +673,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(
struct Scene *scene, Material *ma, EEVEE_Data *vedata,
bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method)
{
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH;
@@ -659,9 +681,9 @@ struct GPUMaterial *EEVEE_material_mesh_get(
if (use_multiply) options |= VAR_MAT_MULT;
if (use_refract) options |= VAR_MAT_REFRACT;
if (use_sss) options |= VAR_MAT_SSS;
- if (use_sss && vedata->stl->effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED;
+ if (use_sss && effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED;
if (use_translucency) options |= VAR_MAT_TRANSLUC;
- if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME;
+ if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME;
options |= eevee_material_shadow_option(shadow_method);
@@ -728,11 +750,9 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(
char *defines = eevee_get_defines(options);
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
- BLI_dynstr_append(ds_frag, datatoc_prepass_frag_glsl);
- char *frag_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ char *frag_str = BLI_string_joinN(
+ e_data.frag_shader_lib,
+ datatoc_prepass_frag_glsl);
mat = GPU_material_from_nodetree(
scene, ma->nodetree, &ma->gpumaterial, engine, options,
@@ -779,6 +799,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass,
bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method)
{
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
int options = VAR_MAT_MESH;
@@ -786,7 +807,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
if (is_hair) options |= VAR_MAT_HAIR;
if (is_flat_normal) options |= VAR_MAT_FLAT;
if (use_blend) options |= VAR_MAT_BLEND;
- if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME;
+ if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME;
options |= eevee_material_shadow_option(shadow_method);
@@ -795,7 +816,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
}
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass);
- add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend, false);
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend);
return shgrp;
}
@@ -825,7 +846,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(
vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state);
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
- add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false, false);
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false);
}
return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
@@ -836,19 +857,6 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
- /* Global AO Switch*/
- stl->effects->use_ao = BKE_collection_engine_property_value_get_bool(props, "gtao_enable");
- stl->effects->use_bent_normals = BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals");
- /* SSR switch */
- stl->effects->use_ssr = BKE_collection_engine_property_value_get_bool(props, "ssr_enable");
- /* Volumetrics */
- stl->effects->use_volumetrics = BKE_collection_engine_property_value_get_bool(props, "volumetric_enable");
- }
-
/* Create Material Ghash */
{
stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash");
@@ -951,6 +959,15 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
psl->transparent_pass = DRW_pass_create("Material Transparent Pass", state);
}
+
+ {
+ psl->update_noise_pass = DRW_pass_create("Update Noise Pass", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass);
+ DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex);
+ DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
}
#define ADD_SHGROUP_CALL(shgrp, ob, geom) do { \
@@ -979,6 +996,7 @@ static void material_opaque(
bool do_cull, bool use_flat_nor, struct GPUMaterial **gpumat, struct GPUMaterial **gpumat_depth,
struct DRWShadingGroup **shgrp, struct DRWShadingGroup **shgrp_depth, struct DRWShadingGroup **shgrp_depth_clip)
{
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
@@ -991,9 +1009,11 @@ static void material_opaque(
float *rough_p = &ma->gloss_mir;
const bool use_gpumat = (ma->use_nodes && ma->nodetree);
- const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0);
- const bool use_sss = ((ma->blend_flag & MA_BL_SS_SUBSURFACE) != 0) && ((stl->effects->enabled_effects & EFFECT_SSS) != 0);
- const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0) && ((stl->effects->enabled_effects & EFFECT_SSS) != 0);
+ const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
+ ((effects->enabled_effects & EFFECT_REFRACT) != 0);
+ const bool use_sss = ((ma->blend_flag & MA_BL_SS_SUBSURFACE) != 0) &&
+ ((effects->enabled_effects & EFFECT_SSS) != 0);
+ const bool use_translucency = use_sss && ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0);
EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma);
@@ -1021,8 +1041,8 @@ static void material_opaque(
if (*shgrp) {
static int no_ssr = -1;
static int first_ssr = 1;
- int *ssr_id = (stl->effects->use_ssr && !use_refract) ? &first_ssr : &no_ssr;
- add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false, use_sss);
+ int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr;
+ add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false);
if (use_sss) {
struct GPUTexture *sss_tex_profile = NULL;
@@ -1037,7 +1057,7 @@ static void material_opaque(
}
DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
- EEVEE_subsurface_add_pass(vedata, e_data.sss_count + 1, sss_profile);
+ EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
e_data.sss_count++;
}
}
@@ -1067,19 +1087,24 @@ static void material_opaque(
}
if (*shgrp_depth != NULL) {
- add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false, false);
+ add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false);
if (ma->blend_method == MA_BM_CLIP) {
DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1);
DRW_shgroup_uniform_float(*shgrp_depth_clip, "alphaThreshold", &ma->alpha_threshold, 1);
}
+ else if (ma->blend_method == MA_BM_HASHED) {
+ DRW_shgroup_uniform_float(*shgrp_depth, "hashAlphaOffset", &e_data.alpha_hash_offset, 1);
+ DRW_shgroup_uniform_float(*shgrp_depth_clip, "hashAlphaOffset", &e_data.alpha_hash_offset, 1);
+ }
}
}
}
/* Fallback to default shader */
if (*shgrp == NULL) {
- *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, stl->effects->use_ssr, linfo->shadow_method);
+ bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
+ *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, use_ssr, linfo->shadow_method);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
@@ -1131,7 +1156,7 @@ static void material_transparent(
if (*shgrp) {
static int ssr_id = -1; /* TODO transparent SSR */
bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
- add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend, false);
+ add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend);
}
else {
/* Shader failed : pink color */
@@ -1217,7 +1242,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
const bool is_default_mode_shader = is_sculpt_mode;
/* First get materials for this mesh. */
- if (ELEM(ob->type, OB_MESH)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
const int materials_len = MAX2(1, (is_sculpt_mode_draw ? 1 : ob->totcol));
struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len);
@@ -1335,7 +1360,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
}
/* Volumetrics */
- if (vedata->stl->effects->use_volumetrics && use_volume_material) {
+ if (((stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_volume_material) {
EEVEE_volumes_cache_object_add(sldata, vedata, scene, ob);
}
}
@@ -1383,7 +1408,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
if (shgrp) {
- add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false, false);
+ add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false);
BLI_ghash_insert(material_hash, ma, shgrp);
@@ -1401,7 +1426,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
/* Fallback to default shader */
if (shgrp == NULL) {
- shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, stl->effects->use_ssr, sldata->lamps->shadow_method);
+ bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0);
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, use_ssr,
+ sldata->lamps->shadow_method);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
@@ -1438,7 +1465,9 @@ void EEVEE_materials_free(void)
DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh);
DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh);
DRW_SHADER_FREE_SAFE(e_data.default_background);
+ DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
+ DRW_TEXTURE_FREE_SAFE(e_data.noise_tex);
}
void EEVEE_draw_default_passes(EEVEE_PassList *psl)
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index d5e0a05f9ed..037bbe3b6c9 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -40,6 +40,7 @@
#include "ED_screen.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "eevee_private.h"
#include "GPU_texture.h"
@@ -52,7 +53,11 @@ static struct {
extern char datatoc_effect_motion_blur_frag_glsl[];
static void eevee_motion_blur_camera_get_matrix_at_time(
- const bContext *C, Scene *scene, ARegion *ar, RegionView3D *rv3d, View3D *v3d, Object *camera, float time, float r_mat[4][4])
+ Scene *scene,
+ ARegion *ar, RegionView3D *rv3d, View3D *v3d,
+ Object *camera,
+ float time,
+ float r_mat[4][4])
{
EvaluationContext eval_ctx;
float obmat[4][4];
@@ -63,7 +68,19 @@ static void eevee_motion_blur_camera_get_matrix_at_time(
memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy));
cam_cpy.data = &camdata_cpy;
- CTX_data_eval_ctx(C, &eval_ctx);
+ /* NOTE: Mode corresponds to old usage of eval_ctx from viewport (which was
+ * actually coming from bmain). It was always DAG_EVAL_VIEWPORT. For F12
+ * render this should be DAG_EVAL_RENDER, but the whole hack is to be
+ * reconsidered first anyway.
+ */
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DEG_evaluation_context_init_from_scene(
+ &eval_ctx,
+ scene,
+ draw_ctx->view_layer,
+ draw_ctx->engine_type,
+ DAG_EVAL_VIEWPORT);
+ eval_ctx.ctime = time;
/* Past matrix */
/* FIXME : This is a temporal solution that does not take care of parent animations */
@@ -76,27 +93,15 @@ static void eevee_motion_blur_camera_get_matrix_at_time(
CameraParams params;
BKE_camera_params_init(&params);
- /* copy of BKE_camera_params_from_view3d */
- {
- params.lens = v3d->lens;
- params.clipsta = v3d->near;
- params.clipend = v3d->far;
-
- /* camera view */
+ if (v3d != NULL) {
+ BKE_camera_params_from_view3d(&params, draw_ctx->depsgraph, v3d, rv3d);
+ BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
+ }
+ else {
BKE_camera_params_from_object(&params, &cam_cpy);
-
- params.zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
-
- params.offsetx = 2.0f * rv3d->camdx * params.zoom;
- params.offsety = 2.0f * rv3d->camdy * params.zoom;
-
- params.shiftx *= params.zoom;
- params.shifty *= params.zoom;
-
- params.zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params.zoom;
+ BKE_camera_params_compute_viewplane(&params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
}
- BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
BKE_camera_params_compute_matrix(&params);
/* FIXME Should be done per view (MULTIVIEW) */
@@ -110,7 +115,7 @@ static void eevee_create_shader_motion_blur(void)
e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
}
-int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera)
{
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
@@ -121,34 +126,51 @@ int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
View3D *v3d = draw_ctx->v3d;
RegionView3D *rv3d = draw_ctx->rv3d;
ARegion *ar = draw_ctx->ar;
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+ IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer,
+ COLLECTION_MODE_NONE,
+ RE_engine_id_BLENDER_EEVEE);
- if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable") && (draw_ctx->evil_C != NULL)) {
+ if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable")) {
/* Update Motion Blur Matrices */
- if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ if (camera) {
float persmat[4][4];
float ctime = BKE_scene_frame_get(scene);
float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter");
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, camera);
/* Current matrix */
- eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime, effects->current_ndc_to_world);
+ eevee_motion_blur_camera_get_matrix_at_time(scene,
+ ar, rv3d, v3d,
+ camera_object,
+ ctime,
+ effects->current_ndc_to_world);
/* Viewport Matrix */
DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
/* Only continue if camera is not being keyed */
- if (compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) {
-
+ if (DRW_state_is_image_render() ||
+ compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f))
+ {
/* Past matrix */
- eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime - delta, effects->past_world_to_ndc);
+ eevee_motion_blur_camera_get_matrix_at_time(scene,
+ ar, rv3d, v3d,
+ camera_object,
+ ctime - delta,
+ effects->past_world_to_ndc);
#if 0 /* for future high quality blur */
/* Future matrix */
- eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, ctime + delta, effects->future_world_to_ndc);
+ eevee_motion_blur_camera_get_matrix_at_time(scene,
+ ar, rv3d, v3d,
+ camera_object,
+ ctime + delta,
+ effects->future_world_to_ndc);
#endif
invert_m4(effects->current_ndc_to_world);
- effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props, "motion_blur_samples");
+ effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props,
+ "motion_blur_samples");
if (!e_data.motion_blur_sh) {
eevee_create_shader_motion_blur();
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index c1dde385284..9da438e825f 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -27,7 +27,7 @@
#include "DRW_render.h"
-#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "DNA_anim_types.h"
@@ -38,38 +38,43 @@
static struct {
/* Ground Truth Ambient Occlusion */
struct GPUShader *gtao_sh;
+ struct GPUShader *gtao_layer_sh;
struct GPUShader *gtao_debug_sh;
+ struct GPUTexture *src_depth;
} e_data = {NULL}; /* Engine data */
extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_gtao_frag_glsl[];
static void eevee_create_shader_occlusion(void)
{
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_effect_gtao_frag_glsl);
- char *frag_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_effect_gtao_frag_glsl);
e_data.gtao_sh = DRW_shader_create_fullscreen(frag_str, NULL);
+ e_data.gtao_layer_sh = DRW_shader_create_fullscreen(frag_str, "#define LAYERED_DEPTH\n");
e_data.gtao_debug_sh = DRW_shader_create_fullscreen(frag_str, "#define DEBUG_AO\n");
MEM_freeN(frag_str);
}
-int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
- EEVEE_EffectsInfo *effects = stl->effects;
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+ IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer,
+ COLLECTION_MODE_NONE,
+ RE_engine_id_BLENDER_EEVEE);
if (BKE_collection_engine_property_value_get_bool(props, "gtao_enable")) {
const float *viewport_size = DRW_viewport_size_get();
@@ -79,48 +84,24 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata
eevee_create_shader_occlusion();
}
- effects->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance");
- effects->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor");
- effects->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality");
- effects->ao_samples = BKE_collection_engine_property_value_get_int(props, "gtao_samples");
- effects->ao_samples_inv = 1.0f / effects->ao_samples;
+ common_data->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance");
+ common_data->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor");
+ common_data->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality");
- effects->ao_settings = 1.0; /* USE_AO */
+ common_data->ao_settings = 1.0; /* USE_AO */
if (BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals")) {
- effects->ao_settings += 2.0; /* USE_BENT_NORMAL */
+ common_data->ao_settings += 2.0; /* USE_BENT_NORMAL */
}
if (BKE_collection_engine_property_value_get_bool(props, "gtao_denoise")) {
- effects->ao_settings += 4.0; /* USE_DENOISE */
- }
-
- effects->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce");
-
- effects->ao_texsize[0] = ((int)viewport_size[0]);
- effects->ao_texsize[1] = ((int)viewport_size[1]);
-
- /* Round up to multiple of 2 */
- if ((effects->ao_texsize[0] & 0x1) != 0) {
- effects->ao_texsize[0] += 1;
+ common_data->ao_settings += 4.0; /* USE_DENOISE */
}
- if ((effects->ao_texsize[1] & 0x1) != 0) {
- effects->ao_texsize[1] += 1;
- }
-
- CLAMP(effects->ao_samples, 1, 32);
- if (effects->hori_tex_layers != effects->ao_samples) {
- DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons);
- }
-
- if (txl->gtao_horizons == NULL) {
- effects->hori_tex_layers = effects->ao_samples;
- txl->gtao_horizons = DRW_texture_create_2D_array((int)viewport_size[0], (int)viewport_size[1], effects->hori_tex_layers, DRW_TEX_RG_8, 0, NULL);
- }
+ common_data->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce");
- DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RG_8, 0};
+ DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RGBA_8, 0};
DRW_framebuffer_init(&fbl->gtao_fb, &draw_engine_eevee_type,
- effects->ao_texsize[0], effects->ao_texsize[1],
+ (int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
if (G.debug_value == 6) {
@@ -137,12 +118,12 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata
/* Cleanup */
DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb);
- effects->ao_settings = 0.0f;
+ common_data->ao_settings = 0.0f;
return 0;
}
-void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
@@ -166,51 +147,54 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
**/
psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer);
- DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10);
- DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2);
- DRW_shgroup_uniform_float(grp, "sampleNbr", &stl->effects->ao_sample_nbr, 1);
- DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &effects->ao_src_depth);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->ao_horizon_search_layer = DRW_pass_create("GTAO Horizon Search Layer", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.gtao_layer_sh, psl->ao_horizon_search_layer);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_buffer(grp, "depthBufferLayered", &effects->ao_src_depth);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1);
DRW_shgroup_call_add(grp, quad, NULL);
if (G.debug_value == 6) {
psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR);
grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10);
- DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2);
- DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_call_add(grp, quad, NULL);
}
}
}
-void EEVEE_occlusion_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_occlusion_compute(
+ EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer)
{
EEVEE_PassList *psl = vedata->psl;
- EEVEE_TextureList *txl = vedata->txl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
DRW_stats_group_start("GTAO Horizon Scan");
- for (effects->ao_sample_nbr = 0.0;
- effects->ao_sample_nbr < effects->ao_samples;
- ++effects->ao_sample_nbr)
- {
- DRW_framebuffer_texture_detach(txl->gtao_horizons);
- DRW_framebuffer_texture_layer_attach(fbl->gtao_fb, txl->gtao_horizons, 0, (int)effects->ao_sample_nbr, 0);
- DRW_framebuffer_bind(fbl->gtao_fb);
+ effects->ao_src_depth = depth_src;
+ effects->ao_depth_layer = layer;
+ DRW_framebuffer_bind(fbl->gtao_fb);
+
+ if (layer >= 0) {
+ DRW_draw_pass(psl->ao_horizon_search_layer);
+ }
+ else {
DRW_draw_pass(psl->ao_horizon_search);
}
@@ -247,5 +231,6 @@ void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
void EEVEE_occlusion_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.gtao_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gtao_layer_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh);
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 98fc6d6a6e4..218de6ddd88 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -27,6 +27,8 @@
#define __EEVEE_PRIVATE_H__
struct Object;
+struct EEVEE_BoundSphere;
+struct EEVEE_ShadowCasterBuffer;
extern struct DrawEngineType draw_engine_eevee_type;
@@ -127,6 +129,14 @@ enum {
SHADOW_METHOD_MAX = 3,
};
+typedef struct EEVEE_BoundSphere {
+ float center[3], radius;
+} EEVEE_BoundSphere;
+
+typedef struct EEVEE_BoundBox {
+ float center[3], halfdim[3];
+} EEVEE_BoundBox;
+
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
@@ -148,6 +158,7 @@ typedef struct EEVEE_PassList {
/* Effects */
struct DRWPass *ao_horizon_search;
+ struct DRWPass *ao_horizon_search_layer;
struct DRWPass *ao_horizon_debug;
struct DRWPass *motion_blur;
struct DRWPass *bloom_blit;
@@ -195,6 +206,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *refract_pass;
struct DRWPass *transparent_pass;
struct DRWPass *background_pass;
+ struct DRWPass *update_noise_pass;
} EEVEE_PassList;
typedef struct EEVEE_FramebufferList {
@@ -217,6 +229,8 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *screen_tracing_fb;
struct GPUFrameBuffer *refract_fb;
+ struct GPUFrameBuffer *update_noise_fb;
+
struct GPUFrameBuffer *planarref_fb;
struct GPUFrameBuffer *main;
@@ -237,6 +251,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; /* R16_G16_B16 */
struct GPUTexture *ssr_normal_input;
struct GPUTexture *ssr_specrough_input;
+ struct GPUTexture *ssr_hit_output;
struct GPUTexture *refract_color;
struct GPUTexture *volume_prop_scattering;
@@ -310,17 +325,23 @@ typedef struct EEVEE_ShadowRender {
float shadow_inv_samples_ct;
} EEVEE_ShadowRender;
-/* ************ VOLUME DATA ************ */
-typedef struct EEVEE_VolumetricsInfo {
- float integration_step_count, shadow_step_count, sample_distribution, light_clamp;
- float integration_start, integration_end;
- float depth_param[3], history_alpha;
- bool use_lights, use_volume_shadows;
- int froxel_tex_size[3];
- float inv_tex_size[3];
- float volume_coord_scale[2];
- float jitter[3];
-} EEVEE_VolumetricsInfo;
+/* This is just a really long bitflag with special function to access it. */
+#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8)
+typedef struct EEVEE_LightBits {
+ unsigned char fields[MAX_LIGHTBITS_FIELDS];
+} EEVEE_LightBits;
+
+typedef struct EEVEE_ShadowCaster {
+ struct EEVEE_LightBits bits;
+ struct EEVEE_BoundBox bbox;
+} EEVEE_ShadowCaster;
+
+typedef struct EEVEE_ShadowCasterBuffer {
+ struct EEVEE_ShadowCaster *shadow_casters;
+ char *flags;
+ unsigned int alloc_count;
+ unsigned int count;
+} EEVEE_ShadowCasterBuffer;
/* ************ LIGHT DATA ************* */
typedef struct EEVEE_LampsInfo {
@@ -346,8 +367,20 @@ typedef struct EEVEE_LampsInfo {
struct EEVEE_Shadow shadow_data[MAX_SHADOW];
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+ /* Lights tracking */
+ int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */
+ struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tighly packed light bounds */
+ /* Pointers only. */
+ struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer;
+ struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer;
} EEVEE_LampsInfo;
+/* EEVEE_LampsInfo->shadow_casters_flag */
+enum {
+ SHADOW_CASTER_PRUNED = (1 << 0),
+ SHADOW_CASTER_UPDATED = (1 << 1),
+};
+
/* EEVEE_LampsInfo->update_flag */
enum {
LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
@@ -395,11 +428,9 @@ typedef struct EEVEE_LightProbesInfo {
int num_bounce;
int cubemap_res;
int target_size;
- int irradiance_vis_size;
int grid_initialized;
- /* Actual number of probes that have datas. */
- int num_render_cube;
- int num_render_grid;
+ struct World *prev_world;
+ bool do_cube_update;
/* For rendering probes */
float probemat[6][4][4];
int layer;
@@ -414,11 +445,8 @@ typedef struct EEVEE_LightProbesInfo {
float lod_rt_max, lod_cube_max, lod_planar_max;
float visibility_range;
float visibility_blur;
+ float intensity_fac;
int shres;
- int shnbr;
- bool specular_toggle;
- bool ssr_toggle;
- bool sss_toggle;
/* List of probes in the scene. */
/* XXX This is fragile, can get out of sync quickly. */
struct Object *probes_cube_ref[MAX_PROBE];
@@ -441,30 +469,18 @@ enum {
typedef struct EEVEE_EffectsInfo {
int enabled_effects;
bool swap_double_buffer;
-
/* SSSS */
int sss_sample_count;
- float sss_jitter_threshold;
bool sss_separate_albedo;
-
/* Volumetrics */
- bool use_volumetrics;
int volume_current_sample;
-
/* SSR */
- bool use_ssr;
bool reflection_trace_full;
- bool ssr_use_normalization;
- int ssr_ray_count;
- float ssr_firefly_fac;
- float ssr_border_fac;
- float ssr_max_roughness;
- float ssr_quality;
- float ssr_thickness;
- float ssr_pixelsize[2];
-
+ int ssr_neighbor_ofs;
+ int ssr_halfres_ofs[2];
/* Temporal Anti Aliasing */
int taa_current_sample;
+ int taa_render_sample;
int taa_total_sample;
float taa_alpha;
bool prev_drw_support;
@@ -473,27 +489,19 @@ typedef struct EEVEE_EffectsInfo {
float overide_persinv[4][4];
float overide_winmat[4][4];
float overide_wininv[4][4];
-
/* Ambient Occlusion */
- bool use_ao, use_bent_normals;
- float ao_dist, ao_samples, ao_factor, ao_samples_inv;
- float ao_offset, ao_bounce_fac, ao_quality, ao_settings;
- float ao_sample_nbr;
- int ao_texsize[2], hori_tex_layers;
-
+ int ao_depth_layer;
+ struct GPUTexture *ao_src_depth; /* pointer copy */
/* Motion Blur */
float current_ndc_to_world[4][4];
float past_world_to_ndc[4][4];
- float tmp_mat[4][4];
int motion_blur_samples;
-
/* Depth Of Field */
float dof_near_far[2];
float dof_params[3];
float dof_bokeh[4];
float dof_layer_select[2];
int dof_target_size[2];
-
/* Bloom */
int bloom_iteration_ct;
float source_texel_size[2];
@@ -506,10 +514,11 @@ typedef struct EEVEE_EffectsInfo {
float unf_source_texel_size[2];
struct GPUTexture *unf_source_buffer; /* pointer copy */
struct GPUTexture *unf_base_buffer; /* pointer copy */
-
/* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */
struct GPUTexture *source_buffer; /* latest updated texture */
struct GPUFrameBuffer *target_buffer; /* next target to render to */
+ struct GPUTexture *final_tx; /* Final color to transform to display color space. */
+ struct GPUFrameBuffer *final_fb; /* Framebuffer with final_tx as attachement. */
} EEVEE_EffectsInfo;
enum {
@@ -527,6 +536,58 @@ enum {
EFFECT_SSS = (1 << 11),
};
+/* ***************** COMMON DATA **************** */
+
+/* Common uniform buffer containing all "constant" data over the whole drawing pipeline. */
+/* !! CAUTION !!
+ * - [i]vec3 need to be paded to [i]vec4 (even in ubo declaration).
+ * - Make sure that [i]vec4 start at a multiple of 16 bytes.
+ * - Arrays of vec2/vec3 are padded as arrays of vec4.
+ * - sizeof(bool) == sizeof(int) in GLSL so use int in C */
+typedef struct EEVEE_CommonUniformBuffer {
+ float prev_persmat[4][4]; /* mat4 */
+ float view_vecs[2][4]; /* vec4[2] */
+ float mip_ratio[10][4]; /* vec2[10] */
+ /* Ambient Occlusion */
+ /* -- 16 byte aligned -- */
+ float ao_dist, pad1, ao_factor, pad2; /* vec4 */
+ float ao_offset, ao_bounce_fac, ao_quality, ao_settings; /* vec4 */
+ /* Volumetric */
+ /* -- 16 byte aligned -- */
+ int vol_tex_size[3], pad3; /* ivec3 */
+ float vol_depth_param[3], pad4; /* vec3 */
+ float vol_inv_tex_size[3], pad5; /* vec3 */
+ float vol_jitter[3], pad6; /* vec3 */
+ float vol_coord_scale[2], pad7[2]; /* vec2 */
+ /* -- 16 byte aligned -- */
+ float vol_history_alpha; /* float */
+ float vol_light_clamp; /* float */
+ float vol_shadow_steps; /* float */
+ int vol_use_lights; /* bool */
+ /* Screen Space Reflections */
+ /* -- 16 byte aligned -- */
+ float ssr_quality, ssr_thickness, ssr_pixelsize[2]; /* vec4 */
+ float ssr_border_fac; /* float */
+ float ssr_max_roughness; /* float */
+ float ssr_firefly_fac; /* float */
+ float ssr_brdf_bias; /* float */
+ int ssr_toggle; /* bool */
+ /* SubSurface Scattering */
+ float sss_jitter_threshold; /* float */
+ int sss_toggle; /* bool */
+ /* Specular */
+ int spec_toggle; /* bool */
+ /* Lamps */
+ int la_num_light; /* int */
+ /* Probes */
+ int prb_num_planar; /* int */
+ int prb_num_render_cube; /* int */
+ int prb_num_render_grid; /* int */
+ int prb_irradiance_vis_size; /* int */
+ float prb_lod_cube_max; /* float */
+ float prb_lod_planar_max; /* float */
+} EEVEE_CommonUniformBuffer;
+
/* ************** SCENE LAYER DATA ************** */
typedef struct EEVEE_ViewLayerData {
/* Lamps */
@@ -546,7 +607,7 @@ typedef struct EEVEE_ViewLayerData {
struct GPUTexture *shadow_cascade_blur;
struct GPUTexture *shadow_pool;
- struct ListBase shadow_casters; /* Shadow casters gathered during cache iteration */
+ struct EEVEE_ShadowCasterBuffer shcasters_buffers[2];
/* Probes */
struct EEVEE_LightProbesInfo *probes;
@@ -564,20 +625,45 @@ typedef struct EEVEE_ViewLayerData {
struct GPUTexture *irradiance_pool;
struct GPUTexture *irradiance_rt;
- struct ListBase probe_queue; /* List of probes to update */
-
- /* Volumetrics */
- struct EEVEE_VolumetricsInfo *volumetrics;
+ /* Common Uniform Buffer */
+ struct EEVEE_CommonUniformBuffer common_data;
+ struct GPUUniformBuffer *common_ubo;
} EEVEE_ViewLayerData;
/* ************ OBJECT DATA ************ */
+typedef struct EEVEE_LightData {
+ short light_id, shadow_id;
+} EEVEE_LightData;
+
+typedef struct EEVEE_ShadowCubeData {
+ short light_id, shadow_id, cube_id, layer_id;
+} EEVEE_ShadowCubeData;
+
+typedef struct EEVEE_ShadowCascadeData {
+ short light_id, shadow_id, cascade_id, layer_id;
+ float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+ float radius[MAX_CASCADE_NUM];
+} EEVEE_ShadowCascadeData;
+
+/* Theses are the structs stored inside Objects.
+ * It works with even if the object is in multiple layers
+ * because we don't get the same "Object *" for each layer. */
typedef struct EEVEE_LampEngineData {
+ ObjectEngineData engine_data;
+
bool need_update;
- struct ListBase shadow_caster_list;
- void *storage; /* either EEVEE_LightData, EEVEE_ShadowCubeData, EEVEE_ShadowCascadeData */
+ /* This needs to be out of the union to avoid undefined behaviour. */
+ short prev_cube_shadow_id;
+ union {
+ struct EEVEE_LightData ld;
+ struct EEVEE_ShadowCubeData scd;
+ struct EEVEE_ShadowCascadeData scad;
+ } data;
} EEVEE_LampEngineData;
typedef struct EEVEE_LightProbeEngineData {
+ ObjectEngineData engine_data;
+
/* NOTE: need_full_update is set by dependency graph when the probe or it's
* object is updated. This triggers full probe update, including it's
* "progressive" GI refresh.
@@ -606,7 +692,10 @@ typedef struct EEVEE_LightProbeEngineData {
} EEVEE_LightProbeEngineData;
typedef struct EEVEE_ObjectEngineData {
+ ObjectEngineData engine_data;
+
bool need_update;
+ unsigned int shadow_caster_id;
} EEVEE_ObjectEngineData;
/* *********************************** */
@@ -635,18 +724,18 @@ typedef struct EEVEE_PrivateData {
struct GHash *material_hash;
struct GHash *hair_material_hash;
struct GPUTexture *minzbuffer;
- struct GPUTexture *ssr_hit_output[4];
+ struct GPUTexture *ssr_pdf_output;
struct GPUTexture *gtao_horizons_debug;
float background_alpha; /* TODO find a better place for this. */
- float viewvecs[2][4];
/* For planar probes */
- float texel_size[2];
- /* To correct mip level texel mis-alignement */
- float mip_ratio[10][2]; /* TODO put in a UBO */
+ float planar_texel_size[2];
/* For double buffering */
bool view_updated;
bool valid_double_buffer;
- float prev_persmat[4][4];
+ /* Render Matrices */
+ float persmat[4][4], persinv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float winmat[4][4], wininv[4][4];
} EEVEE_PrivateData; /* Transient data */
/* eevee_data.c */
@@ -661,7 +750,7 @@ EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob);
/* eevee_materials.c */
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
-void EEVEE_materials_init(EEVEE_StorageList *stl);
+void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl);
void EEVEE_materials_cache_init(EEVEE_Data *vedata);
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob);
void EEVEE_materials_cache_finish(EEVEE_Data *vedata);
@@ -676,7 +765,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method);
void EEVEE_materials_free(void);
void EEVEE_draw_default_passes(EEVEE_PassList *psl);
-void EEVEE_update_util_texture(float offset);
+void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double offsets[3]);
/* eevee_lights.c */
void EEVEE_lights_init(EEVEE_ViewLayerData *sldata);
@@ -688,6 +777,7 @@ void EEVEE_lights_cache_shcaster_material_add(
EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl,
struct GPUMaterial *gpumat, struct Gwn_Batch *geom, struct Object *ob,
float (*obmat)[4], float *alpha_threshold);
+void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata);
void EEVEE_lights_update(EEVEE_ViewLayerData *sldata);
void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
@@ -702,7 +792,7 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_free(void);
/* eevee_depth_of_field.c */
-int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_depth_of_field_draw(EEVEE_Data *vedata);
void EEVEE_depth_of_field_free(void);
@@ -716,7 +806,7 @@ void EEVEE_bloom_free(void);
/* eevee_occlusion.c */
int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_free(void);
@@ -730,19 +820,22 @@ void EEVEE_screen_raytrace_free(void);
/* eevee_subsurface.c */
int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile);
+void EEVEE_subsurface_add_pass(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile);
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_free(void);
/* eevee_motion_blur.c */
-int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_motion_blur_draw(EEVEE_Data *vedata);
void EEVEE_motion_blur_free(void);
/* eevee_temporal_sampling.c */
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_temporal_sampling_matrices_calc(
+ EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], double ht_point[2]);
void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata);
void EEVEE_temporal_sampling_free(void);
@@ -757,15 +850,21 @@ void EEVEE_volumes_free_smoke_textures(void);
void EEVEE_volumes_free(void);
/* eevee_effects.c */
-void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level);
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level);
void EEVEE_effects_do_gtao(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_draw_effects(EEVEE_Data *vedata);
+void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_free(void);
+/* eevee_ */
+void EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void EEVEE_render_output(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+
/* Shadow Matrix */
static const float texcomat[4][4] = { /* From NDC to TexCo */
{0.5f, 0.0f, 0.0f, 0.0f},
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
new file mode 100644
index 00000000000..a020887e420
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2016, 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(s): Blender Institute
+ *
+ */
+
+/** \file eevee_render.c
+ * \ingroup draw_engine
+ */
+
+/**
+ * Render functions for final render outputs.
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BLI_rand.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_glew.h"
+
+#include "RE_pipeline.h"
+
+#include "eevee_private.h"
+
+void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* Init default FB and render targets:
+ * In render mode the default framebuffer is not generated
+ * because there is no viewport. So we need to manually create it or
+ * not use it. For code clarity we just allocate it make use of it. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ /* NOTE : use 32 bit format for precision in render mode. */
+ DRWFboTexture dtex = {&dtxl->depth, DRW_TEX_DEPTH_24_STENCIL_8, 0};
+ DRW_framebuffer_init(&dfbl->default_fb, &draw_engine_eevee_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &dtex, 1);
+
+ DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_32, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
+ DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
+
+ /* Alloc transient data. */
+ if (!stl->g_data) {
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ EEVEE_PrivateData *g_data = stl->g_data;
+ g_data->background_alpha = 1.0f; /* TODO option */
+ g_data->valid_double_buffer = 0;
+
+ /* Alloc common ubo data. */
+ if (sldata->common_ubo == NULL) {
+ sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
+ }
+
+ /* Set the pers & view matrix. */
+ struct Object *camera = RE_GetCamera(engine->re);
+ float frame = BKE_scene_frame_get(scene);
+ RE_GetCameraWindow(engine->re, camera, frame, g_data->winmat);
+ RE_GetCameraModelMatrix(engine->re, camera, g_data->viewinv);
+
+ invert_m4_m4(g_data->viewmat, g_data->viewinv);
+ mul_m4_m4m4(g_data->persmat, g_data->winmat, g_data->viewmat);
+ invert_m4_m4(g_data->persinv, g_data->persmat);
+ invert_m4_m4(g_data->wininv, g_data->winmat);
+
+ DRW_viewport_matrix_override_set(g_data->persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(g_data->persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(g_data->winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(g_data->wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV);
+
+ /* EEVEE_effects_init needs to go first for TAA */
+ EEVEE_effects_init(sldata, vedata, camera);
+ EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_lights_init(sldata);
+ EEVEE_lightprobes_init(sldata, vedata);
+
+ /* INIT CACHE */
+ EEVEE_bloom_cache_init(sldata, vedata);
+ EEVEE_depth_of_field_cache_init(sldata, vedata);
+ EEVEE_effects_cache_init(sldata, vedata);
+ EEVEE_lightprobes_cache_init(sldata, vedata);
+ EEVEE_lights_cache_init(sldata, psl);
+ EEVEE_materials_cache_init(vedata);
+ EEVEE_motion_blur_cache_init(sldata, vedata);
+ EEVEE_occlusion_cache_init(sldata, vedata);
+ EEVEE_screen_raytrace_cache_init(sldata, vedata);
+ EEVEE_subsurface_cache_init(sldata, vedata);
+ EEVEE_temporal_sampling_cache_init(sldata, vedata);
+ EEVEE_volumes_cache_init(sldata, vedata);
+}
+
+void EEVEE_render_cache(
+ void *vedata, struct Object *ob,
+ struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
+{
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+
+ if (DRW_check_object_visible_within_active_context(ob) == false) {
+ return;
+ }
+
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ EEVEE_materials_cache_populate(vedata, sldata, ob);
+
+ const bool cast_shadow = true;
+
+ if (cast_shadow) {
+ EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ }
+ }
+ else if (ob->type == OB_LIGHTPROBE) {
+ EEVEE_lightprobes_cache_add(sldata, ob);
+ }
+ else if (ob->type == OB_LAMP) {
+ EEVEE_lights_cache_add(sldata, ob);
+ }
+}
+
+void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ /* FINISH CACHE */
+ EEVEE_materials_cache_finish(vedata);
+ EEVEE_lights_cache_finish(sldata);
+ EEVEE_lightprobes_cache_finish(sldata, vedata);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+ unsigned int render_samples = BKE_collection_engine_property_value_get_int(props, "taa_render_samples");
+
+ while (render_samples-- > 0) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.6f};
+ unsigned int primes[3] = {2, 3, 7};
+ double offset[3] = {0.0, 0.0, 0.0};
+ double r[3];
+
+ BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r);
+ EEVEE_update_noise(psl, fbl, r);
+ EEVEE_temporal_sampling_matrices_calc(stl->effects, g_data->viewmat, g_data->persmat, r);
+
+ /* Refresh Probes & shadows */
+ EEVEE_lightprobes_refresh(sldata, vedata);
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ EEVEE_draw_shadows(sldata, psl);
+
+ DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV);
+
+ DRW_framebuffer_texture_detach(dtxl->depth);
+ DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
+ DRW_framebuffer_bind(fbl->main);
+ DRW_framebuffer_clear(true, true, true, clear_col, 1.0f);
+ /* Depth prepass */
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+ /* Create minmax texture */
+ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
+ EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+ EEVEE_volumes_compute(sldata, vedata);
+ /* Shading pass */
+ DRW_draw_pass(psl->background_pass);
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+ EEVEE_subsurface_data_render(sldata, vedata);
+ /* Effects pre-transparency */
+ EEVEE_subsurface_compute(sldata, vedata);
+ EEVEE_reflection_compute(sldata, vedata);
+ EEVEE_occlusion_draw_debug(sldata, vedata);
+ DRW_draw_pass(psl->probe_display);
+ EEVEE_refraction_compute(sldata, vedata);
+ /* Opaque refraction */
+ DRW_draw_pass(psl->refract_depth_pass);
+ DRW_draw_pass(psl->refract_depth_pass_cull);
+ DRW_draw_pass(psl->refract_pass);
+ /* Volumetrics Resolve Opaque */
+ EEVEE_volumes_resolve(sldata, vedata);
+ /* Transparent */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
+ DRW_draw_pass(psl->transparent_pass);
+ /* Post Process */
+ EEVEE_draw_effects(sldata, vedata);
+ }
+}
+
+void EEVEE_render_output(EEVEE_Data *vedata, RenderEngine *engine, struct Depsgraph *UNUSED(depsgraph))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+
+ const char *viewname = NULL;
+ const float *render_size = DRW_viewport_size_get();
+
+ /* Combined */
+ RenderResult *rr = RE_engine_begin_result(engine, 0, 0, (int)render_size[0], (int)render_size[1], NULL, viewname);
+ RenderLayer *rl = rr->layers.first;
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
+
+ DRW_framebuffer_bind(stl->effects->final_fb);
+ DRW_framebuffer_read_data(0, 0, (int)render_size[0], (int)render_size[1], 4, 0, rp->rect);
+
+ if (view_layer->passflag & SCE_PASS_Z) {
+ rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
+
+ DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
+ DRW_framebuffer_bind(fbl->main);
+ DRW_framebuffer_read_depth(0, 0, (int)render_size[0], (int)render_size[1], rp->rect);
+
+ bool is_persp = DRW_viewport_is_persp_get();
+
+ /* Convert ogl depth [0..1] to view Z [near..far] */
+ for (int i = 0; i < (int)render_size[0] * (int)render_size[1]; ++i) {
+ if (rp->rect[i] == 1.0f ) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ if (is_persp) {
+ rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
+ rp->rect[i] = g_data->winmat[3][2] / (rp->rect[i] + g_data->winmat[2][2]);
+ }
+ else {
+ rp->rect[i] = -common_data->view_vecs[0][2] + rp->rect[i] * -common_data->view_vecs[1][2];
+ }
+ }
+ }
+ }
+
+ RE_engine_end_result(engine, rr, false, false, false);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 35669968337..2917bfd1236 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -28,15 +28,16 @@
#include "DRW_render.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "eevee_private.h"
#include "GPU_texture.h"
/* SSR shader variations */
enum {
- SSR_SAMPLES = (1 << 0) | (1 << 1),
- SSR_RESOLVE = (1 << 2),
- SSR_FULL_TRACE = (1 << 3),
+ SSR_RESOLVE = (1 << 0),
+ SSR_FULL_TRACE = (1 << 1),
+ SSR_AO = (1 << 3),
SSR_MAX_SHADER = (1 << 4),
};
@@ -50,6 +51,7 @@ static struct {
} e_data = {NULL}; /* Engine data */
extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
@@ -60,22 +62,18 @@ extern char datatoc_raytrace_lib_glsl[];
static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
{
if (e_data.ssr_sh[options] == NULL) {
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl);
- char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- int samples = (SSR_SAMPLES & options) + 1;
+ char *ssr_shader_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_effect_ssr_frag_glsl);
DynStr *ds_defines = BLI_dynstr_new();
BLI_dynstr_appendf(ds_defines, SHADER_DEFINES);
- BLI_dynstr_appendf(ds_defines, "#define RAY_COUNT %d\n", samples);
if (options & SSR_RESOLVE) {
BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n");
}
@@ -86,6 +84,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
if (options & SSR_FULL_TRACE) {
BLI_dynstr_appendf(ds_defines, "#define FULLRES\n");
}
+ if (options & SSR_AO) {
+ BLI_dynstr_appendf(ds_defines, "#define SSR_AO\n");
+ }
char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines);
BLI_dynstr_free(ds_defines);
@@ -98,8 +99,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
return e_data.ssr_sh[options];
}
-int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
@@ -108,11 +110,13 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+ IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer,
+ COLLECTION_MODE_NONE,
+ RE_engine_id_BLENDER_EEVEE);
/* Compute pixel size, (shared with contact shadows) */
- copy_v2_v2(effects->ssr_pixelsize, viewport_size);
- invert_v2(effects->ssr_pixelsize);
+ copy_v2_v2(common_data->ssr_pixelsize, viewport_size);
+ invert_v2(common_data->ssr_pixelsize);
if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) {
const bool use_refraction = BKE_collection_engine_property_value_get_bool(props, "ssr_refraction");
@@ -120,24 +124,27 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
if (use_refraction) {
DRWFboTexture tex = {&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
- DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1);
+ DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
}
- effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count");
+ bool prev_trace_full = effects->reflection_trace_full;
effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres");
- effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight");
- effects->ssr_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "ssr_quality");
- effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness");
- effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade");
- effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac");
- effects->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness");
-
- if (effects->ssr_firefly_fac < 1e-8f) {
- effects->ssr_firefly_fac = FLT_MAX;
+ common_data->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness");
+ common_data->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade");
+ common_data->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac");
+ common_data->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness");
+ common_data->ssr_quality = 1.0f - 0.95f * BKE_collection_engine_property_value_get_float(props, "ssr_quality");
+ common_data->ssr_brdf_bias = 0.1f + common_data->ssr_quality * 0.6f; /* Range [0.1, 0.7]. */
+
+ if (common_data->ssr_firefly_fac < 1e-8f) {
+ common_data->ssr_firefly_fac = FLT_MAX;
}
- /* Important, can lead to breakage otherwise. */
- CLAMP(effects->ssr_ray_count, 1, 4);
+ if (prev_trace_full != effects->reflection_trace_full) {
+ DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output);
+ }
const int divisor = (effects->reflection_trace_full) ? 1 : 2;
int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
@@ -147,7 +154,8 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
/* TODO create one texture layer per lobe */
if (txl->ssr_specrough_input == NULL) {
DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8;
- txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL);
+ txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1],
+ specrough_format, 0, NULL);
}
/* Reattach textures to the right buffer (because we are alternating between buffers) */
@@ -156,15 +164,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
/* Raytracing output */
- /* TODO try integer format for hit coord to increase precision */
- DRWFboTexture tex_output[4] = {
- {&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
- {&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
- {&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
- {&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
- };
+ /* (AMD or Intel) For some reason DRW_TEX_TEMP with DRW_TEX_RG_16I
+ * creates problems when toggling ssr_halfres. Texture is not read correctly (black output).
+ * So using a persistent buffer instead. */
+ DRWFboTexture tex_output[2] = {{&txl->ssr_hit_output, DRW_TEX_RG_16I, 0},
+ {&stl->g_data->ssr_pdf_output, DRW_TEX_R_16, DRW_TEX_TEMP}};
- DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count);
+ DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type,
+ tracing_res[0], tracing_res[1],
+ tex_output, 2);
/* Enable double buffering to be able to read previous frame color */
return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0);
@@ -172,10 +180,9 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
/* Cleanup to release memory */
DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input);
+ DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
- for (int i = 0; i < 4; ++i) {
- stl->g_data->ssr_hit_output[i] = NULL;
- }
+ stl->g_data->ssr_pdf_output = NULL;
return 0;
}
@@ -191,7 +198,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0;
- options |= (effects->ssr_ray_count - 1);
+ options |= ((effects->enabled_effects & EFFECT_GTAO) != 0) ? SSR_AO : 0;
struct GPUShader *trace_shader = eevee_effects_screen_raytrace_shader_get(options);
struct GPUShader *resolve_shader = eevee_effects_screen_raytrace_shader_get(SSR_RESOLVE | options);
@@ -214,15 +221,14 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10);
- DRW_shgroup_uniform_vec4(grp, "ssrParameters", &effects->ssr_quality, 1);
- DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1);
- DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1);
DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ if (!effects->reflection_trace_full) {
+ DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1);
+ }
DRW_shgroup_call_add(grp, quad, NULL);
psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
@@ -230,41 +236,19 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth);
+ DRW_shgroup_uniform_buffer(grp, "hitBuffer", &vedata->txl->ssr_hit_output);
+ DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &stl->g_data->ssr_pdf_output);
DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer);
- DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1);
- DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1);
- DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10);
- DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1);
- DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1);
- DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
- DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1);
- DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool);
- DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool);
- DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]);
- if (effects->ssr_ray_count > 1) {
- DRW_shgroup_uniform_buffer(grp, "hitBuffer1", &stl->g_data->ssr_hit_output[1]);
- }
- if (effects->ssr_ray_count > 2) {
- DRW_shgroup_uniform_buffer(grp, "hitBuffer2", &stl->g_data->ssr_hit_output[2]);
- }
- if (effects->ssr_ray_count > 3) {
- DRW_shgroup_uniform_buffer(grp, "hitBuffer3", &stl->g_data->ssr_hit_output[3]);
- }
-
- DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &effects->ao_dist, 2);
- if (effects->use_ao) {
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
+ if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &vedata->txl->gtao_horizons);
- DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1);
- }
- else {
- /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */
- DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &sldata->shadow_pool);
}
DRW_shgroup_call_add(grp, quad, NULL);
@@ -301,22 +285,39 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
e_data.depth_src = dtxl->depth;
DRW_stats_group_start("SSR");
-
- for (int i = 0; i < effects->ssr_ray_count; ++i) {
- DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0);
- }
+ DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_pdf_output, 1, 0);
DRW_framebuffer_bind(fbl->screen_tracing_fb);
/* Raytrace. */
DRW_draw_pass(psl->ssr_raytrace);
- for (int i = 0; i < effects->ssr_ray_count; ++i) {
- DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]);
- }
+ DRW_framebuffer_texture_detach(stl->g_data->ssr_pdf_output);
EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9);
/* Resolve at fullres */
+ int sample = (DRW_state_is_image_render()) ? effects->taa_render_sample : effects->taa_current_sample;
+ /* Doing a neighbor shift only after a few iteration. We wait for a prime number of cycles to avoid
+ * noise correlation. This reduces variance faster. */
+ effects->ssr_neighbor_ofs = ((sample / 5) % 8) * 4;
+ switch ((sample / 11) % 4) {
+ case 0:
+ effects->ssr_halfres_ofs[0] = 0;
+ effects->ssr_halfres_ofs[1] = 0;
+ break;
+ case 1:
+ effects->ssr_halfres_ofs[0] = 0;
+ effects->ssr_halfres_ofs[1] = 1;
+ break;
+ case 2:
+ effects->ssr_halfres_ofs[0] = 1;
+ effects->ssr_halfres_ofs[1] = 0;
+ break;
+ case 4:
+ effects->ssr_halfres_ofs[0] = 1;
+ effects->ssr_halfres_ofs[1] = 1;
+ break;
+ }
DRW_framebuffer_texture_detach(dtxl->depth);
DRW_framebuffer_texture_detach(txl->ssr_normal_input);
DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 4efdfb0fb84..17da4a18b78 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -27,7 +27,7 @@
#include "DRW_render.h"
-#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "eevee_private.h"
#include "GPU_texture.h"
@@ -36,18 +36,26 @@ static struct {
struct GPUShader *sss_sh[3];
} e_data = {NULL}; /* Engine data */
+extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
static void eevee_create_shader_subsurface(void)
{
- e_data.sss_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define FIRST_PASS\n");
- e_data.sss_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n");
- e_data.sss_sh[2] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n"
- "#define USE_SEP_ALBEDO\n");
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_effect_subsurface_frag_glsl);
+
+ e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
+ e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n");
+ e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"
+ "#define USE_SEP_ALBEDO\n");
+
+ MEM_freeN(frag_str);
}
-int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_FramebufferList *fbl = vedata->fbl;
@@ -60,8 +68,8 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedat
if (BKE_collection_engine_property_value_get_bool(props, "sss_enable")) {
effects->sss_sample_count = 1 + BKE_collection_engine_property_value_get_int(props, "sss_samples") * 2;
- effects->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold");
effects->sss_separate_albedo = BKE_collection_engine_property_value_get_bool(props, "sss_separate_albedo");
+ common_data->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold");
/* Shaders */
if (!e_data.sss_sh[0]) {
@@ -117,7 +125,8 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
}
}
-void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile)
+void EEVEE_subsurface_add_pass(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile)
{
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
EEVEE_TextureList *txl = vedata->txl;
@@ -127,23 +136,21 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G
struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_data);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call_add(grp, quad, NULL);
struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1];
grp = DRW_shgroup_create(sh, psl->sss_resolve_ps);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call_add(grp, quad, NULL);
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index 5faac4c42cc..24b8117b6f5 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -44,6 +44,23 @@ static void eevee_create_shader_temporal_sampling(void)
e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL);
}
+void EEVEE_temporal_sampling_matrices_calc(
+ EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], double ht_point[2])
+{
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* TODO Blackman-Harris filter */
+
+ window_translate_m4(
+ effects->overide_winmat, persmat,
+ ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0],
+ ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]);
+
+ mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat);
+ invert_m4_m4(effects->overide_persinv, effects->overide_persmat);
+ invert_m4_m4(effects->overide_wininv, effects->overide_winmat);
+}
+
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = vedata->stl;
@@ -51,14 +68,21 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
+ /* Reset for each "redraw". When rendering using ogl render,
+ * we accumulate the redraw inside the drawing loop in eevee_draw_background().
+ * But we do NOT accumulate between "redraw" (as in full draw manager drawloop)
+ * because the opengl render already does that. */
+ effects->taa_render_sample = 1;
+
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
- if (BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 &&
+ if ((BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 &&
/* FIXME the motion blur camera evaluation is tagging view_updated
* thus making the TAA always reset and never stopping rendering. */
- (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0)
+ (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) ||
+ DRW_state_is_image_render())
{
const float *viewport_size = DRW_viewport_size_get();
float persmat[4][4], viewmat[4][4];
@@ -79,40 +103,41 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN);
- view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN);
- copy_m4_m4(effects->prev_drw_persmat, persmat);
+ /* The view is jittered by the oglrenderer. So avoid testing in this case. */
+ if (!DRW_state_is_image_render()) {
+ view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN);
+ copy_m4_m4(effects->prev_drw_persmat, persmat);
+ }
/* Prevent ghosting from probe data. */
view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support());
effects->prev_drw_support = DRW_state_draw_support();
- if (view_is_valid &&
- ((effects->taa_total_sample == 0) ||
- (effects->taa_current_sample < effects->taa_total_sample)))
+ if (((effects->taa_total_sample == 0) || (effects->taa_current_sample < effects->taa_total_sample)) ||
+ DRW_state_is_image_render())
{
- effects->taa_current_sample += 1;
-
- effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample);
-
- double ht_point[2];
- double ht_offset[2] = {0.0, 0.0};
- unsigned int ht_primes[2] = {2, 3};
-
- BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point);
-
- window_translate_m4(
- effects->overide_winmat, persmat,
- ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0],
- ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]);
-
- mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat);
- invert_m4_m4(effects->overide_persinv, effects->overide_persmat);
- invert_m4_m4(effects->overide_wininv, effects->overide_winmat);
-
- DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS);
- DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN);
- DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV);
+ if (view_is_valid) {
+ /* OGL render already jitter the camera. */
+ if (!DRW_state_is_image_render()) {
+ effects->taa_current_sample += 1;
+
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ unsigned int ht_primes[2] = {2, 3};
+
+ BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point);
+
+ EEVEE_temporal_sampling_matrices_calc(effects, viewmat, persmat, ht_point);
+
+ DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV);
+ }
+ }
+ else {
+ effects->taa_current_sample = 1;
+ }
}
else {
effects->taa_current_sample = 1;
@@ -127,6 +152,8 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
return EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER;
}
+ effects->taa_current_sample = 1;
+
/* Cleanup to release memory */
DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->depth_double_buffer_fb);
@@ -162,11 +189,21 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata)
if ((effects->enabled_effects & EFFECT_TAA) != 0) {
if (effects->taa_current_sample != 1) {
+ if (DRW_state_is_image_render()) {
+ /* See EEVEE_temporal_sampling_init() for more details. */
+ effects->taa_alpha = 1.0f / (float)(effects->taa_render_sample);
+ }
+ else {
+ effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample);
+ }
+
DRW_framebuffer_bind(fbl->effect_fb);
DRW_draw_pass(psl->taa_resolve);
/* Restore the depth from sample 1. */
- DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true, false);
+ if (!DRW_state_is_image_render()) {
+ DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true, false);
+ }
/* Special Swap */
SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer);
@@ -179,15 +216,25 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata)
/* Save the depth buffer for the next frame.
* This saves us from doing anything special
* in the other mode engines. */
- DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true, false);
+ if (!DRW_state_is_image_render()) {
+ DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true, false);
+ }
}
- if ((effects->taa_total_sample == 0) ||
- (effects->taa_current_sample < effects->taa_total_sample))
- {
- DRW_viewport_request_redraw();
+ /* Make each loop count when doing a render. */
+ if (DRW_state_is_image_render()) {
+ effects->taa_render_sample += 1;
+ effects->taa_current_sample += 1;
+ }
+ else {
+ if ((effects->taa_total_sample == 0) ||
+ (effects->taa_current_sample < effects->taa_total_sample))
+ {
+ DRW_viewport_request_redraw();
+ }
}
}
+
}
void EEVEE_temporal_sampling_free(void)
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index dae4503dc32..a960682e8c9 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -27,8 +27,8 @@
#include "DRW_render.h"
-#include "BLI_dynstr.h"
#include "BLI_rand.h"
+#include "BLI_string_utils.h"
#include "DNA_object_force.h"
#include "DNA_smoke_types.h"
@@ -51,6 +51,7 @@ static struct {
struct GPUShader *volumetric_clear_sh;
struct GPUShader *volumetric_scatter_sh;
+ struct GPUShader *volumetric_scatter_with_lamps_sh;
struct GPUShader *volumetric_integration_sh;
struct GPUShader *volumetric_resolve_sh;
@@ -63,6 +64,7 @@ static struct {
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_direct_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lamps_lib_glsl[];
@@ -77,21 +79,19 @@ extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
static void eevee_create_shader_volumes(void)
{
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
- e_data.volumetric_common_lib = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
- e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ e_data.volumetric_common_lib = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_volumetric_lib_glsl);
+
+ e_data.volumetric_common_lamps_lib = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_direct_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lamps_lib_glsl,
+ datatoc_volumetric_lib_glsl);
e_data.volumetric_clear_sh = DRW_shader_create_with_lib(
datatoc_volumetric_vert_glsl,
@@ -108,6 +108,15 @@ static void eevee_create_shader_volumes(void)
SHADER_DEFINES
"#define VOLUMETRICS\n"
"#define VOLUME_SHADOW\n");
+ e_data.volumetric_scatter_with_lamps_sh = DRW_shader_create_with_lib(
+ datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_scatter_frag_glsl,
+ e_data.volumetric_common_lamps_lib,
+ SHADER_DEFINES
+ "#define VOLUMETRICS\n"
+ "#define VOLUME_LIGHTING\n"
+ "#define VOLUME_SHADOW\n");
e_data.volumetric_integration_sh = DRW_shader_create_with_lib(
datatoc_volumetric_vert_glsl,
datatoc_volumetric_geom_glsl,
@@ -125,6 +134,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
@@ -141,29 +151,23 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
eevee_create_shader_volumes();
}
- if (sldata->volumetrics == NULL) {
- sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo");
- }
-
- EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics;
-
int tile_size = BKE_collection_engine_property_value_get_int(props, "volumetric_tile_size");
/* Find Froxel Texture resolution. */
- int froxel_tex_size[3];
+ int tex_size[3];
- froxel_tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size));
- froxel_tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size));
- froxel_tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1);
+ tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size));
+ tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size));
+ tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1);
- volumetrics->volume_coord_scale[0] = viewport_size[0] / (float)(tile_size * froxel_tex_size[0]);
- volumetrics->volume_coord_scale[1] = viewport_size[1] / (float)(tile_size * froxel_tex_size[1]);
+ common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]);
+ common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]);
/* TODO compute snap to maxZBuffer for clustered rendering */
- if ((volumetrics->froxel_tex_size[0] != froxel_tex_size[0]) ||
- (volumetrics->froxel_tex_size[1] != froxel_tex_size[1]) ||
- (volumetrics->froxel_tex_size[2] != froxel_tex_size[2]))
+ if ((common_data->vol_tex_size[0] != tex_size[0]) ||
+ (common_data->vol_tex_size[1] != tex_size[1]) ||
+ (common_data->vol_tex_size[2] != tex_size[2]))
{
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering);
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction);
@@ -176,38 +180,46 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb);
- volumetrics->froxel_tex_size[0] = froxel_tex_size[0];
- volumetrics->froxel_tex_size[1] = froxel_tex_size[1];
- volumetrics->froxel_tex_size[2] = froxel_tex_size[2];
+ common_data->vol_tex_size[0] = tex_size[0];
+ common_data->vol_tex_size[1] = tex_size[1];
+ common_data->vol_tex_size[2] = tex_size[2];
- volumetrics->inv_tex_size[0] = 1.0f / (float)(volumetrics->froxel_tex_size[0]);
- volumetrics->inv_tex_size[1] = 1.0f / (float)(volumetrics->froxel_tex_size[1]);
- volumetrics->inv_tex_size[2] = 1.0f / (float)(volumetrics->froxel_tex_size[2]);
+ common_data->vol_inv_tex_size[0] = 1.0f / (float)(tex_size[0]);
+ common_data->vol_inv_tex_size[1] = 1.0f / (float)(tex_size[1]);
+ common_data->vol_inv_tex_size[2] = 1.0f / (float)(tex_size[2]);
}
/* Like frostbite's paper, 5% blend of the new frame. */
- volumetrics->history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f;
+ common_data->vol_history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f;
if (txl->volume_prop_scattering == NULL) {
/* Volume properties: We evaluate all volumetric objects
* and store their final properties into each froxel */
- txl->volume_prop_scattering = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
- txl->volume_prop_extinction = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
- txl->volume_prop_emission = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
- txl->volume_prop_phase = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RG_16, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_scattering = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_extinction = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_emission = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_phase = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RG_16, DRW_TEX_FILTER, NULL);
/* Volume scattering: We compute for each froxel the
* Scattered light towards the view. We also resolve temporal
* super sampling during this stage. */
- txl->volume_scatter = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
- txl->volume_transmittance = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_scatter = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_transmittance = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
/* Final integration: We compute for each froxel the
* amount of scattered light and extinction coef at this
* given depth. We use theses textures as double buffer
* for the volumetric history. */
- txl->volume_scatter_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
- txl->volume_transmittance_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_scatter_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
+ txl->volume_transmittance_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL);
}
/* Temporal Super sampling jitter */
@@ -225,7 +237,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
if (do_taa) {
- volumetrics->history_alpha = 0.0f;
+ common_data->vol_history_alpha = 0.0f;
current_sample = effects->taa_current_sample - 1;
effects->volume_current_sample = -1;
}
@@ -238,9 +250,9 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point);
- volumetrics->jitter[0] = (float)ht_point[0];
- volumetrics->jitter[1] = (float)ht_point[1];
- volumetrics->jitter[2] = (float)ht_point[2];
+ common_data->vol_jitter[0] = (float)ht_point[0];
+ common_data->vol_jitter[1] = (float)ht_point[1];
+ common_data->vol_jitter[2] = (float)ht_point[2];
/* Framebuffer setup */
DRWFboTexture tex_vol[4] = {{&txl->volume_prop_scattering, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER},
@@ -249,63 +261,64 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{&txl->volume_prop_phase, DRW_TEX_RG_16, DRW_TEX_FILTER}};
DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type,
- (int)froxel_tex_size[0], (int)froxel_tex_size[1],
+ (int)tex_size[0], (int)tex_size[1],
tex_vol, 4);
DRWFboTexture tex_vol_scat[2] = {{&txl->volume_scatter, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER},
{&txl->volume_transmittance, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}};
DRW_framebuffer_init(&fbl->volumetric_scat_fb, &draw_engine_eevee_type,
- (int)froxel_tex_size[0], (int)froxel_tex_size[1],
+ (int)tex_size[0], (int)tex_size[1],
tex_vol_scat, 2);
DRWFboTexture tex_vol_integ[2] = {{&txl->volume_scatter_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER},
{&txl->volume_transmittance_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}};
DRW_framebuffer_init(&fbl->volumetric_integ_fb, &draw_engine_eevee_type,
- (int)froxel_tex_size[0], (int)froxel_tex_size[1],
+ (int)tex_size[0], (int)tex_size[1],
tex_vol_integ, 2);
- volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start");
- volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end");
- volumetrics->sample_distribution = 4.0f * (1.00001f - BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution"));
- volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows");
- volumetrics->light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp");
+ float integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start");
+ float integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end");
+ common_data->vol_light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp");
- if (volumetrics->use_volume_shadows) {
- volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples");
+ common_data->vol_shadow_steps = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples");
+ if (BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows")) {
}
else {
- volumetrics->shadow_step_count = 0;
+ common_data->vol_shadow_steps = 0;
}
if (DRW_viewport_is_persp_get()) {
- const float clip_start = stl->g_data->viewvecs[0][2];
+ float sample_distribution = BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution");
+ sample_distribution = 4.0f * (1.00001f - sample_distribution);
+
+ const float clip_start = common_data->view_vecs[0][2];
/* Negate */
- float near = volumetrics->integration_start = min_ff(-volumetrics->integration_start, clip_start - 1e-4f);
- float far = volumetrics->integration_end = min_ff(-volumetrics->integration_end, near - 1e-4f);
+ float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f);
+ float far = integration_end = min_ff(-integration_end, near - 1e-4f);
- volumetrics->depth_param[0] = (far - near * exp2(1.0f / volumetrics->sample_distribution)) / (far - near);
- volumetrics->depth_param[1] = (1.0f - volumetrics->depth_param[0]) / near;
- volumetrics->depth_param[2] = volumetrics->sample_distribution;
+ common_data->vol_depth_param[0] = (far - near * exp2(1.0f / sample_distribution)) / (far - near);
+ common_data->vol_depth_param[1] = (1.0f - common_data->vol_depth_param[0]) / near;
+ common_data->vol_depth_param[2] = sample_distribution;
}
else {
- const float clip_start = stl->g_data->viewvecs[0][2];
- const float clip_end = stl->g_data->viewvecs[1][2];
- volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start);
- volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end);
-
- volumetrics->depth_param[0] = volumetrics->integration_start;
- volumetrics->depth_param[1] = volumetrics->integration_end;
- volumetrics->depth_param[2] = 1.0f / (volumetrics->integration_end - volumetrics->integration_start);
+ const float clip_start = common_data->view_vecs[0][2];
+ const float clip_end = common_data->view_vecs[1][2];
+ integration_start = min_ff(integration_end, clip_start);
+ integration_end = max_ff(-integration_end, clip_end);
+
+ common_data->vol_depth_param[0] = integration_start;
+ common_data->vol_depth_param[1] = integration_end;
+ common_data->vol_depth_param[2] = 1.0f / (integration_end - integration_start);
}
/* Disable clamp if equal to 0. */
- if (volumetrics->light_clamp == 0.0) {
- volumetrics->light_clamp = FLT_MAX;
+ if (common_data->vol_light_clamp == 0.0) {
+ common_data->vol_light_clamp = FLT_MAX;
}
- volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights");
+ common_data->vol_use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights");
return EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER;
}
@@ -332,12 +345,11 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics;
- static int zero = 0;
DRWShadingGroup *grp;
/* Quick breakdown of the Volumetric rendering:
@@ -374,65 +386,59 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if (wo != NULL && wo->use_nodes && wo->nodetree) {
struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo);
- grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]);
+ grp = DRW_shgroup_material_empty_tri_batch_create(mat,
+ psl->volumetric_world_ps,
+ common_data->vol_tex_size[2]);
if (grp) {
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1);
- DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
}
}
else {
/* If no world or volume material is present just clear the buffer with this drawcall */
- grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]);
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh,
+ psl->volumetric_world_ps,
+ common_data->vol_tex_size[2]);
- DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
}
/* Volumetric Objects */
- psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+ psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR |
+ DRW_STATE_ADDITIVE);
+ struct GPUShader *scatter_sh = (common_data->vol_use_lights) ? e_data.volumetric_scatter_with_lamps_sh
+ : e_data.volumetric_scatter_sh;
psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR);
- grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_scatter_sh, psl->volumetric_scatter_ps, volumetrics->froxel_tex_size[2]);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1);
- DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_int(grp, "light_count", (volumetrics->use_lights) ? &sldata->lamps->num_light : &zero, 1);
+ grp = DRW_shgroup_empty_tri_batch_create(scatter_sh, psl->volumetric_scatter_ps,
+ common_data->vol_tex_size[2]);
DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool);
- DRW_shgroup_uniform_float(grp, "volume_light_clamp", &volumetrics->light_clamp, 1);
- DRW_shgroup_uniform_float(grp, "volume_shadows_steps", &volumetrics->shadow_step_count, 1);
- DRW_shgroup_uniform_float(grp, "volume_history_alpha", &volumetrics->history_alpha, 1);
DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_prop_scattering);
DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_prop_extinction);
DRW_shgroup_uniform_buffer(grp, "volumeEmission", &txl->volume_prop_emission);
DRW_shgroup_uniform_buffer(grp, "volumePhase", &txl->volume_prop_phase);
DRW_shgroup_uniform_buffer(grp, "historyScattering", &txl->volume_scatter_history);
DRW_shgroup_uniform_buffer(grp, "historyTransmittance", &txl->volume_transmittance_history);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
psl->volumetric_integration_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR);
- grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps, volumetrics->froxel_tex_size[2]);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1);
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh,
+ psl->volumetric_integration_ps,
+ common_data->vol_tex_size[2]);
DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_scatter);
DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_transmittance);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR);
grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1);
DRW_shgroup_uniform_buffer(grp, "inScattering", &txl->volume_scatter);
DRW_shgroup_uniform_buffer(grp, "inTransmittance", &txl->volume_transmittance);
DRW_shgroup_uniform_buffer(grp, "inSceneColor", &e_data.color_src);
DRW_shgroup_uniform_buffer(grp, "inSceneDepth", &e_data.depth_src);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
}
@@ -442,7 +448,6 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
float *texcoloc = NULL;
float *texcosize = NULL;
struct ModifierData *md = NULL;
- EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics;
Material *ma = give_current_material(ob, 1);
if (ma == NULL) {
@@ -451,7 +456,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma);
- DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, volumetrics->froxel_tex_size[2]);
+ DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]);
/* Making sure it's updated. */
invert_m4_m4(ob->imat, ob->obmat);
@@ -459,14 +464,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize);
if (grp) {
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat);
DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1);
DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2);
- DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1);
- DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1);
- DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1);
}
/* Smoke Simulation */
@@ -576,6 +577,7 @@ void EEVEE_volumes_free(void)
DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh);
DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh);
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_with_lamps_sh);
DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh);
DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh);
}
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 5ec72833379..55f66f5500a 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -30,87 +30,18 @@
#ifndef UTIL_TEX
#define UTIL_TEX
uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
-uniform vec4 aoParameters[2];
-uniform sampler2DArray horizonBuffer;
-
-/* Cannot use textureSize(horizonBuffer) when rendering to it */
-uniform ivec2 aoHorizonTexSize;
-
-#define aoDistance aoParameters[0].x
-#define aoSamples aoParameters[0].y
-#define aoFactor aoParameters[0].z
-#define aoInvSamples aoParameters[0].w
-
-#define aoOffset aoParameters[1].x /* UNUSED */
-#define aoBounceFac aoParameters[1].y
-#define aoQuality aoParameters[1].z
-#define aoSettings aoParameters[1].w
+uniform sampler2D horizonBuffer;
+/* aoSettings flags */
#define USE_AO 1
#define USE_BENT_NORMAL 2
#define USE_DENOISE 4
-vec2 pack_horizons(vec2 v) { return v * 0.5 + 0.5; }
-vec2 unpack_horizons(vec2 v) { return v * 2.0 - 1.0; }
-
-/* Returns the texel coordinate in horizonBuffer
- * for a given fullscreen coord */
-ivec2 get_hr_co(ivec2 fs_co)
-{
- bvec2 quarter = notEqual(fs_co & ivec2(1), ivec2(0));
-
- ivec2 hr_co = fs_co / 2;
- hr_co += ivec2(quarter) * (aoHorizonTexSize / 2);
-
- return hr_co;
-}
-
-/* Returns the texel coordinate in fullscreen (depthBuffer)
- * for a given horizonBuffer coord */
-ivec2 get_fs_co(ivec2 hr_co)
-{
- hr_co *= 2;
- bvec2 quarter = greaterThanEqual(hr_co, aoHorizonTexSize);
-
- hr_co -= ivec2(quarter) * (aoHorizonTexSize - 1);
-
- return hr_co;
-}
-
-/* Returns the phi angle in horizonBuffer
- * for a given horizonBuffer coord */
-float get_phi(ivec2 hr_co, ivec2 fs_co, float sample)
-{
- bvec2 quarter = greaterThanEqual(hr_co, aoHorizonTexSize / 2);
- ivec2 tex_co = ((int(aoSettings) & USE_DENOISE) != 0) ? hr_co - ivec2(quarter) * (aoHorizonTexSize / 2) : fs_co;
- float blue_noise = texture(utilTex, vec3((vec2(tex_co) + 0.5) / LUT_SIZE, 2.0)).r;
-
- float phi = sample * aoInvSamples;
-
- if ((int(aoSettings) & USE_DENOISE) != 0) {
- /* Interleaved jitter for spatial 2x2 denoising */
- phi += 0.25 * aoInvSamples * (float(quarter.x) + 2.0 * float(quarter.y));
- blue_noise *= 0.25;
- }
- /* Blue noise is scaled to cover the rest of the range. */
- phi += aoInvSamples * blue_noise;
- phi *= M_PI;
-
- return phi;
-}
-
-/* Returns direction jittered offset for a given fullscreen coord */
-float get_offset(ivec2 fs_co, float sample)
-{
- float offset = sample * aoInvSamples;
-
- /* Interleaved jitter for spatial 2x2 denoising */
- offset += 0.25 * dot(vec2(1.0), vec2(fs_co & 1));
- offset += texture(utilTex, vec3((vec2(fs_co / 2) + 0.5 + 16.0) / LUT_SIZE, 2.0)).r;
- return offset;
-}
+vec4 pack_horizons(vec4 v) { return v * 0.5 + 0.5; }
+vec4 unpack_horizons(vec4 v) { return v * 2.0 - 1.0; }
/* Returns maximum screen distance an AO ray can travel for a given view depth */
vec2 get_max_dir(float view_depth)
@@ -120,6 +51,13 @@ vec2 get_max_dir(float view_depth)
return vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * max_dist;
}
+vec2 get_ao_dir(float jitter)
+{
+ /* Only half a turn because we integrate in slices. */
+ jitter *= M_PI;
+ return vec2(cos(jitter), sin(jitter));
+}
+
void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float h)
{
co1 *= mipRatio[int(lod + 1.0)].xyxy; /* +1 because we are using half res top level */
@@ -161,10 +99,8 @@ void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float
h = mix(h, max(h, s_h.w), blend.w);
}
-vec2 search_horizon_sweep(float phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir)
+vec2 search_horizon_sweep(vec2 t_phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir)
{
- vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */
-
max_dir *= max_v2(abs(t_phi));
/* Convert to pixel space. */
@@ -214,11 +150,8 @@ vec2 search_horizon_sweep(float phi, vec3 pos, vec2 uvs, float jitter, vec2 max_
return h;
}
-void integrate_slice(vec3 normal, float phi, vec2 horizons, inout float visibility, inout vec3 bent_normal)
+void integrate_slice(vec3 normal, vec2 t_phi, vec2 horizons, inout float visibility, inout vec3 bent_normal)
{
- /* TODO OPTI Could be precomputed. */
- vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */
-
/* Projecting Normal to Plane P defined by t_phi and omega_o */
vec3 np = vec3(t_phi.y, -t_phi.x, 0.0); /* Normal vector to Integration plane */
vec3 t = vec3(-t_phi, 0.0);
@@ -251,71 +184,43 @@ void integrate_slice(vec3 normal, float phi, vec2 horizons, inout float visibili
bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle) * 0.5);
}
-void denoise_ao(vec3 normal, float frag_depth, inout float visibility, inout vec3 bent_normal)
+void gtao_deferred(vec3 normal, vec3 position, vec4 noise, float frag_depth, out float visibility, out vec3 bent_normal)
{
- vec2 d_sign = vec2(ivec2(gl_FragCoord.xy) & 1) - 0.5;
-
- if ((int(aoSettings) & USE_DENOISE) == 0) {
- d_sign *= 0.0;
- }
-
- /* 2x2 Bilateral Filter using derivatives. */
- vec2 n_step = step(-0.2, -abs(vec2(length(dFdx(normal)), length(dFdy(normal)))));
- vec2 z_step = step(-0.1, -abs(vec2(dFdx(frag_depth), dFdy(frag_depth))));
-
- visibility -= dFdx(visibility) * d_sign.x * z_step.x * n_step.x;
- visibility -= dFdy(visibility) * d_sign.y * z_step.y * n_step.y;
+ /* Fetch early, hide latency! */
+ vec4 horizons = texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0);
- bent_normal -= dFdx(bent_normal) * d_sign.x * z_step.x * n_step.x;
- bent_normal -= dFdy(bent_normal) * d_sign.y * z_step.y * n_step.y;
-}
-
-void gtao_deferred(vec3 normal, vec3 position, float frag_depth, out float visibility, out vec3 bent_normal)
-{
+ vec4 dirs;
+ dirs.xy = get_ao_dir(noise.x * 0.5);
+ dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
vec2 uvs = get_uvs_from_view(position);
- vec4 texel_size = vec4(-1.0, -1.0, 1.0, 1.0) / vec2(textureSize(depthBuffer, 0)).xyxy;
-
- ivec2 fs_co = ivec2(gl_FragCoord.xy);
- ivec2 hr_co = get_hr_co(fs_co);
-
bent_normal = vec3(0.0);
visibility = 0.0;
- for (float i = 0.0; i < MAX_PHI_STEP; i++) {
- if (i >= aoSamples) break;
+ horizons = unpack_horizons(horizons);
- vec2 horiz = unpack_horizons(texelFetch(horizonBuffer, ivec3(hr_co, int(i)), 0).rg);
- float phi = get_phi(hr_co, fs_co, i);
+ integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
+ integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal);
- integrate_slice(normal, phi, horiz.xy, visibility, bent_normal);
- }
+ visibility *= 0.5; /* We integrated 2 slices. */
- visibility *= aoInvSamples;
bent_normal = normalize(bent_normal);
}
-void gtao(vec3 normal, vec3 position, vec2 noise, out float visibility, out vec3 bent_normal)
+void gtao(vec3 normal, vec3 position, vec4 noise, out float visibility, out vec3 bent_normal)
{
vec2 uvs = get_uvs_from_view(position);
-
- float homcco = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
- float max_dist = aoDistance / homcco; /* Search distance */
- vec2 max_dir = max_dist * vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]);
+ vec2 max_dir = get_max_dir(position.z);
+ vec2 dir = get_ao_dir(noise.x);
bent_normal = vec3(0.0);
visibility = 0.0;
- for (float i = 0.0; i < MAX_PHI_STEP; i++) {
- if (i >= aoSamples) break;
-
- float phi = M_PI * (i + noise.x) * aoInvSamples;
- vec2 horizons = search_horizon_sweep(phi, position, uvs, noise.g, max_dir);
-
- integrate_slice(normal, phi, horizons, visibility, bent_normal);
- }
+ /* Only trace in 2 directions. May lead to a darker result but since it's mostly for
+ * alpha blended objects that will have overdraw, we limit the performance impact. */
+ vec2 horizons = search_horizon_sweep(dir, position, uvs, noise.y, max_dir);
+ integrate_slice(normal, dir, horizons, visibility, bent_normal);
- visibility *= aoInvSamples;
bent_normal = normalize(bent_normal);
}
@@ -337,7 +242,7 @@ float gtao_multibounce(float visibility, vec3 albedo)
}
/* Use the right occlusion */
-float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec2 randuv, out vec3 bent_normal)
+float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal)
{
#ifndef USE_REFRACTION
if ((int(aoSettings) & USE_AO) > 0) {
@@ -345,11 +250,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec2 randuv, ou
vec3 vnor = mat3(ViewMatrix) * N;
#ifdef ENABLE_DEFERED_AO
- gtao_deferred(vnor, vpos, gl_FragCoord.z, visibility, bent_normal);
+ gtao_deferred(vnor, vpos, rand, gl_FragCoord.z, visibility, bent_normal);
#else
- gtao(vnor, vpos, randuv, visibility, bent_normal);
+ gtao(vnor, vpos, rand, visibility, bent_normal);
#endif
- denoise_ao(vnor, gl_FragCoord.z, visibility, bent_normal);
/* Prevent some problems down the road. */
visibility = max(1e-3, visibility);
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 37ed2235c6f..68299fe7546 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -11,7 +11,6 @@
uniform mat4 ProjectionMatrix;
uniform mat4 ViewProjectionMatrix;
uniform mat4 ViewMatrixInverse;
-uniform vec4 viewvecs[2];
#ifndef SHADOW_SHADER
uniform mat4 ViewMatrix;
#else
@@ -31,8 +30,6 @@ flat in int shFace; /* Shadow layer we are rendering to. */
#define ViewMatrix FaceViewMatrix[shFace]
#endif
-uniform vec2 mipRatio[10];
-
/* Buffers */
uniform sampler2D colorBuffer;
uniform sampler2D depthBuffer;
@@ -125,6 +122,10 @@ float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
float max_v2(vec2 v) { return max(v.x, v.y); }
float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
+float sum(vec2 v) { return dot(vec2(1.0), v); }
+float sum(vec3 v) { return dot(vec3(1.0), v); }
+float sum(vec4 v) { return dot(vec4(1.0), v); }
+
float saturate(float a) { return clamp(a, 0.0, 1.0); }
vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }
@@ -300,7 +301,7 @@ float get_view_z_from_depth(float depth)
return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
}
else {
- return viewvecs[0].z + depth * viewvecs[1].z;
+ return viewVecs[0].z + depth * viewVecs[1].z;
}
}
@@ -311,7 +312,7 @@ float get_depth_from_view_z(float z)
return d * 0.5 + 0.5;
}
else {
- return (z - viewvecs[0].z) / viewvecs[1].z;
+ return (z - viewVecs[0].z) / viewVecs[1].z;
}
}
@@ -324,10 +325,10 @@ vec2 get_uvs_from_view(vec3 view)
vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
{
if (ProjectionMatrix[3][3] == 0.0) {
- return (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz) * get_view_z_from_depth(depth);
+ return (viewVecs[0].xyz + vec3(uvcoords, 0.0) * viewVecs[1].xyz) * get_view_z_from_depth(depth);
}
else {
- return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz;
+ return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz;
}
}
@@ -545,7 +546,7 @@ vec3 F_schlick(vec3 f0, float cos_theta)
/* Fresnel approximation for LTC area lights (not MRP) */
vec3 F_area(vec3 f0, vec2 lut)
{
- vec2 fac = normalize(lut.xy);
+ vec2 fac = normalize(lut.xy); /* XXX FIXME this does not work!!! */
/* Unreal specular matching : if specular color is below 2% intensity,
* treat as shadowning */
@@ -691,7 +692,6 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
}
else {
cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */
- cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */
cl.ssr_normal = cl2.ssr_normal;
cl.ssr_id = cl2.ssr_id;
}
@@ -739,12 +739,10 @@ Closure closure_add(Closure cl1, Closure cl2)
#endif
#endif
cl.radiance = cl1.radiance + cl2.radiance;
- cl.opacity = cl1.opacity + cl2.opacity;
+ cl.opacity = saturate(cl1.opacity + cl2.opacity);
return cl;
}
-uniform bool sssToggle;
-
#if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
layout(location = 0) out vec4 fragColor;
#ifdef USE_SSS
@@ -774,6 +772,10 @@ vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth);
void main()
{
Closure cl = nodetree_exec();
+#ifndef USE_ALPHA_BLEND
+ /* Prevent alpha hash material writing into alpha channel. */
+ cl.opacity = 1.0;
+#endif
#if defined(USE_ALPHA_BLEND_VOLUMETRICS)
/* XXX fragile, better use real viewport resolution */
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
index ae03f22ac14..ddc7327334c 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
@@ -28,56 +28,30 @@ float direct_diffuse_sun(LightData ld, vec3 N)
return bsdf;
}
-/* From Frostbite PBR Course
- * Analytical irradiance from a sphere with correct horizon handling
- * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+#ifdef USE_LTC
float direct_diffuse_sphere(LightData ld, vec3 N, vec4 l_vector)
{
- float dist = l_vector.w;
- vec3 L = l_vector.xyz / dist;
- float radius = max(ld.l_sizex, 0.0001);
- float costheta = clamp(dot(N, L), -0.999, 0.999);
- float h = min(ld.l_radius / dist , 0.9999);
- float h2 = h*h;
- float costheta2 = costheta * costheta;
- float bsdf;
-
- if (costheta2 > h2) {
- bsdf = M_PI * h2 * clamp(costheta, 0.0, 1.0);
- }
- else {
- float sintheta = sqrt(1.0 - costheta2);
- float x = sqrt(1.0 / h2 - 1.0);
- float y = -x * (costheta / sintheta);
- float sinthetasqrty = sintheta * sqrt(1.0 - y * y);
- bsdf = (costheta * acos(y) - x * sinthetasqrty) * h2 + atan(sinthetasqrty / x);
- }
-
- bsdf = max(bsdf, 0.0);
- bsdf *= M_1_PI2;
+ float NL = dot(N, l_vector.xyz / l_vector.w);
- return bsdf;
+ return ltc_evaluate_disk_simple(ld.l_radius / l_vector.w, NL);
}
-#ifdef USE_LTC
float direct_diffuse_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector)
{
vec3 corners[4];
- corners[0] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey;
- corners[1] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey;
- corners[2] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey;
- corners[3] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey;
+ corners[0] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey);
+ corners[1] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey);
+ corners[2] = normalize(l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey);
+ corners[3] = normalize(l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey);
- float bsdf = ltc_evaluate(N, V, mat3(1.0), corners);
- bsdf *= M_1_2PI;
- return bsdf;
+ return ltc_evaluate_quad(corners, N);
}
-#endif
-#if 0
-float direct_diffuse_unit_disc(vec3 N, vec3 L)
+float direct_diffuse_unit_disc(LightData ld, vec3 N, vec3 V)
{
+ float NL = dot(N, -ld.l_forward);
+ return ltc_evaluate_disk_simple(ld.l_radius, NL);
}
#endif
@@ -106,47 +80,27 @@ vec3 direct_ggx_sun(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0)
#ifdef USE_LTC
vec3 direct_ggx_sphere(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
{
- vec3 L = l_vector.xyz / l_vector.w;
- vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughness);
- vec3 P = line_aligned_plane_intersect(vec3(0.0), spec_dir, l_vector.xyz);
-
- vec3 Px = normalize(P - l_vector.xyz) * ld.l_radius;
- vec3 Py = cross(Px, L);
+ roughness = clamp(roughness, 0.0008, 0.999); /* Fix low roughness artifacts. */
vec2 uv = lut_coords(dot(N, V), sqrt(roughness));
vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
mat3 ltc_mat = ltc_matrix(ltc_lut);
-// #define HIGHEST_QUALITY
-#ifdef HIGHEST_QUALITY
- vec3 Pxy1 = normalize( Px + Py) * ld.l_radius;
- vec3 Pxy2 = normalize(-Px + Py) * ld.l_radius;
-
- /* counter clockwise */
- vec3 points[8];
- points[0] = l_vector.xyz + Px;
- points[1] = l_vector.xyz - Pxy2;
- points[2] = l_vector.xyz - Py;
- points[3] = l_vector.xyz - Pxy1;
- points[4] = l_vector.xyz - Px;
- points[5] = l_vector.xyz + Pxy2;
- points[6] = l_vector.xyz + Py;
- points[7] = l_vector.xyz + Pxy1;
- float bsdf = ltc_evaluate_circle(N, V, ltc_mat, points);
-#else
- vec3 points[4];
- points[0] = l_vector.xyz + Px;
- points[1] = l_vector.xyz - Py;
- points[2] = l_vector.xyz - Px;
- points[3] = l_vector.xyz + Py;
- float bsdf = ltc_evaluate(N, V, ltc_mat, points);
- /* sqrt(pi/2) difference between square and disk area */
- bsdf *= 1.25331413731;
-#endif
+ /* Make orthonormal basis. */
+ vec3 L = l_vector.xyz / l_vector.w;
+ vec3 Px, Py;
+ make_orthonormal_basis(L, Px, Py);
+ Px *= ld.l_radius;
+ Py *= ld.l_radius;
+ vec3 points[3];
+ points[0] = l_vector.xyz - Px - Py;
+ points[1] = l_vector.xyz + Px - Py;
+ points[2] = l_vector.xyz + Px + Py;
+
+ float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points);
bsdf *= brdf_lut.b; /* Bsdf intensity */
- bsdf *= M_1_2PI * M_1_PI;
vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
@@ -165,19 +119,38 @@ vec3 direct_ggx_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector, float rou
vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
mat3 ltc_mat = ltc_matrix(ltc_lut);
- float bsdf = ltc_evaluate(N, V, ltc_mat, corners);
+
+ ltc_transform_quad(N, V, ltc_mat, corners);
+ float bsdf = ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0));
bsdf *= brdf_lut.b; /* Bsdf intensity */
- bsdf *= M_1_2PI;
vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
return spec;
}
-#endif
-#if 0
-float direct_ggx_disc(vec3 N, vec3 L)
+vec3 direct_ggx_unit_disc(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0)
{
+ roughness = clamp(roughness, 0.0004, 0.999); /* Fix low roughness artifacts. */
+
+ vec2 uv = lut_coords(dot(N, V), sqrt(roughness));
+ vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
+ vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
+ mat3 ltc_mat = ltc_matrix(ltc_lut);
+ vec3 Px = ld.l_right * ld.l_radius;
+ vec3 Py = ld.l_up * ld.l_radius;
+
+ vec3 points[3];
+ points[0] = -ld.l_forward - Px - Py;
+ points[1] = -ld.l_forward + Px - Py;
+ points[2] = -ld.l_forward + Px + Py;
+
+ float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points);
+ bsdf *= brdf_lut.b; /* Bsdf intensity */
+
+ vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
+
+ return spec;
}
#endif \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
index 13586619fe9..e5c0cb9c9c9 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -9,12 +9,12 @@ vec2 jitternoise = vec2(0.0);
#ifndef UTIL_TEX
#define UTIL_TEX
uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
void setup_noise(void)
{
- jitternoise = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).rg; /* Global variable */
- jitternoise.g = (jitternoise.g - 0.5) * 2.0;
+ jitternoise = texelfetch_noise_tex(gl_FragCoord.xy).rg; /* Global variable */
}
#ifdef HAMMERSLEY_SIZE
diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
new file mode 100644
index 00000000000..37106fc32bd
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
@@ -0,0 +1,55 @@
+
+layout(std140) uniform common_block {
+ mat4 pastViewProjectionMatrix;
+ vec4 viewVecs[2];
+ vec2 mipRatio[10]; /* To correct mip level texel mis-alignement */
+ /* Ambient Occlusion */
+ vec4 aoParameters[2];
+ /* Volumetric */
+ ivec4 volTexSize;
+ vec4 volDepthParameters; /* Parameters to the volume Z equation */
+ vec4 volInvTexSize;
+ vec4 volJitter;
+ vec4 volCoordScale; /* To convert volume uvs to screen uvs */
+ float volHistoryAlpha;
+ float volLightClamp;
+ float volShadowSteps;
+ bool volUseLights;
+ /* Screen Space Reflections */
+ vec4 ssrParameters;
+ float ssrBorderFac;
+ float ssrMaxRoughness;
+ float ssrFireflyFac;
+ float ssrBrdfBias;
+ bool ssrToggle;
+ /* SubSurface Scattering */
+ float sssJitterThreshold;
+ bool sssToggle;
+ /* Specular */
+ bool specToggle;
+ /* Lamps */
+ int laNumLight;
+ /* Probes */
+ int prbNumPlanar;
+ int prbNumRenderCube;
+ int prbNumRenderGrid;
+ int prbIrradianceVisSize;
+ float prbLodCubeMax;
+ float prbLodPlanarMax;
+};
+
+/* aoParameters */
+#define aoDistance aoParameters[0].x
+#define aoSamples aoParameters[0].y /* UNUSED */
+#define aoFactor aoParameters[0].z
+#define aoInvSamples aoParameters[0].w /* UNUSED */
+
+#define aoOffset aoParameters[1].x /* UNUSED */
+#define aoBounceFac aoParameters[1].y
+#define aoQuality aoParameters[1].z
+#define aoSettings aoParameters[1].w
+
+/* ssrParameters */
+#define ssrQuality ssrParameters.x
+#define ssrThickness ssrParameters.y
+#define ssrPixelSize ssrParameters.zw \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
index 45c5c88e763..6d941ae6ec3 100644
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -11,7 +11,7 @@ Closure nodetree_exec(void)
vec3 f0 = mix(dielectric, basecol, metallic);
vec3 N = (gl_FrontFacing) ? worldNormal : -worldNormal;
vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default(N, albedo, f0, 0, roughness, 1.0, out_diff, out_spec, ssr_spec);
+ eevee_closure_default(N, albedo, f0, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
Closure result = Closure(out_spec + out_diff * albedo, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0);
diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
index 1c63051c65b..32edf709d88 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
@@ -12,8 +12,8 @@ uniform sampler2D normalBuffer;
void main()
{
- vec4 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xyxy;
- vec2 uvs = saturate(gl_FragCoord.xy * texel_size.xy);
+ vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy;
+ vec2 uvs = saturate(gl_FragCoord.xy * texel_size);
float depth = textureLod(depthBuffer, uvs, 0.0).r;
@@ -23,28 +23,32 @@ void main()
vec3 bent_normal;
float visibility;
-#if 1
- gtao_deferred(normal, viewPosition, depth, visibility, bent_normal);
-#else
- vec2 rand = vec2((1.0 / 4.0) * float((int(gl_FragCoord.y) & 0x1) * 2 + (int(gl_FragCoord.x) & 0x1)), 0.5);
- rand = fract(rand.x + texture(utilTex, vec3(floor(gl_FragCoord.xy * 0.5) / LUT_SIZE, 2.0)).rg);
- gtao(normal, viewPosition, rand, visibility, bent_normal);
-#endif
- denoise_ao(normal, depth, visibility, bent_normal);
+
+ vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy);
+
+ gtao_deferred(normal, viewPosition, noise, depth, visibility, bent_normal);
FragColor = vec4(visibility);
}
#else
-uniform float sampleNbr;
+
+#ifdef LAYERED_DEPTH
+uniform sampler2DArray depthBufferLayered;
+uniform int layer;
+# define gtao_depthBuffer depthBufferLayered
+# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c)
+
+#else
+# define gtao_depthBuffer depthBuffer
+# define gtao_textureLod(a, b, c) textureLod(a, b, c)
+
+#endif
void main()
{
- ivec2 hr_co = ivec2(gl_FragCoord.xy);
- ivec2 fs_co = get_fs_co(hr_co);
-
- vec2 uvs = saturate((vec2(fs_co) + 0.5) / vec2(textureSize(depthBuffer, 0)));
- float depth = textureLod(depthBuffer, uvs, 0.0).r;
+ vec2 uvs = saturate(gl_FragCoord.xy / vec2(textureSize(gtao_depthBuffer, 0).xy));
+ float depth = gtao_textureLod(gtao_depthBuffer, uvs, 0.0).r;
if (depth == 1.0) {
/* Do not trace for background */
@@ -56,14 +60,17 @@ void main()
depth = saturate(depth - 3e-6); /* Tweaked for 24bit depth buffer. */
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
-
- float phi = get_phi(hr_co, fs_co, sampleNbr);
- float offset = get_offset(fs_co, sampleNbr);
+ vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy);
vec2 max_dir = get_max_dir(viewPosition.z);
+ vec4 dirs;
+ dirs.xy = get_ao_dir(noise.x * 0.5);
+ dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
- FragColor.xy = search_horizon_sweep(phi, viewPosition, uvs, offset, max_dir);
+ /* Search in 4 directions. */
+ FragColor.xy = search_horizon_sweep(dirs.xy, viewPosition, uvs, noise.y, max_dir);
+ FragColor.zw = search_horizon_sweep(dirs.zw, viewPosition, uvs, noise.y, max_dir);
/* Resize output for integer texture. */
- FragColor = pack_horizons(FragColor.xy).xyxy;
+ FragColor = pack_horizons(FragColor);
}
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
index ce6f3568cdf..65d3970a82a 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -23,6 +23,10 @@ uniform sampler2D depthBuffer;
#define minmax(a, b) max(a, b)
#endif
+#ifdef GPU_INTEL
+out vec4 fragColor;
+#endif
+
void main()
{
ivec2 texelPos = ivec2(gl_FragCoord.xy);
@@ -61,5 +65,10 @@ void main()
}
#endif
+#ifdef GPU_INTEL
+ /* Use color format instead of 24bit depth texture */
+ fragColor = vec4(val);
+#else
gl_FragDepth = val;
+#endif
} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
index 1a01db3a1a3..73e284570cd 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
@@ -57,7 +57,7 @@ void main()
float inc = 2.0 * inv_samples;
float i = -1.0 + noise;
- FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ FragColor = vec4(0.0);
for (int j = 0; j < samples && j < MAX_SAMPLE; j++) {
FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples;
i += inc;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index 2dc8dfa0d1c..aa88e365d93 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -5,80 +5,78 @@
#ifndef UTIL_TEX
#define UTIL_TEX
uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
-#define BRDF_BIAS 0.7
#define MAX_MIP 9.0
-uniform float fireflyFactor;
-uniform float maxRoughness;
+uniform ivec2 halfresOffset;
+
+ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar)
+{
+ ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */
+ hit_data.x *= (is_planar) ? -1 : 1;
+ hit_data.y *= (has_hit) ? 1 : -1;
+ return hit_data;
+}
+
+vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar)
+{
+ is_planar = (hit_data.x < 0);
+ has_hit = (hit_data.y > 0);
+ return vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */
+}
#ifdef STEP_RAYTRACE
uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
-uniform int planar_count;
-uniform float noiseOffset;
-
-layout(location = 0) out vec4 hitData0;
-layout(location = 1) out vec4 hitData1;
-layout(location = 2) out vec4 hitData2;
-layout(location = 3) out vec4 hitData3;
+layout(location = 0) out ivec2 hitData;
+layout(location = 1) out float pdfData;
-vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand, float ofs)
+void do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec4 rand)
{
- float pdf, NH;
- float jitter = fract(rand.x + ofs);
-
- /* Importance sampling bias */
- rand.x = mix(rand.x, 0.0, BRDF_BIAS);
-
- vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
- pdf = pdf_ggx_reflect(NH, a2);
+ float NH;
+ vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
+ float pdf = pdf_ggx_reflect(NH, a2);
vec3 R = reflect(-V, H);
R = reflect(R, planeNormal);
/* If ray is bad (i.e. going below the plane) regenerate. */
if (dot(R, planeNormal) > 0.0) {
- vec3 H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
+ vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
pdf = pdf_ggx_reflect(NH, a2);
R = reflect(-V, H);
R = reflect(R, planeNormal);
}
- pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */
- pdf *= -1.0; /* Tag as planar ray. */
+ pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
/* Since viewspace hit position can land behind the camera in this case,
* we save the reflected view position (visualize it as the hit position
* below the reflection plane). This way it's garanted that the hit will
* be in front of the camera. That let us tag the bad rays with a negative
* sign in the Z component. */
- vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, jitter, ssrQuality, a2, false);
+ vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, rand.y, ssrQuality, a2, false);
- return vec4(hit_pos, pdf);
+ hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
}
-vec4 do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec3 rand, float ofs)
+void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec4 rand)
{
- float pdf, NH;
- float jitter = fract(rand.x + ofs);
-
- /* Importance sampling bias */
- rand.x = mix(rand.x, 0.0, BRDF_BIAS);
-
- vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
- pdf = pdf_ggx_reflect(NH, a2);
+ float NH;
+ vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
+ float pdf = pdf_ggx_reflect(NH, a2);
vec3 R = reflect(-V, H);
- pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */
+ pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
- vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, a2, true);
+ vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
- return vec4(hit_pos, pdf);
+ hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
}
void main()
@@ -87,20 +85,22 @@ void main()
ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
ivec2 halfres_texel = fullres_texel;
#else
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2;
+ ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset;
ivec2 halfres_texel = ivec2(gl_FragCoord.xy);
#endif
float depth = texelFetch(depthBuffer, fullres_texel, 0).r;
+ /* Default: not hits. */
+ hitData = encode_hit_data(vec2(0.5), false, false);
+ pdfData = 0.0;
+
/* Early out */
+ /* We can't do discard because we don't clear the render target. */
if (depth == 1.0)
- discard;
+ return;
- vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
-#ifndef FULLRES
- uvs *= 2.0;
-#endif
+ vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0));
/* Using view space */
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
@@ -112,18 +112,24 @@ void main()
/* Early out */
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
- discard;
+ return;
float roughness = speccol_roughness.a;
float roughnessSquared = max(1e-3, roughness * roughness);
float a2 = roughnessSquared * roughnessSquared;
- if (roughness > maxRoughness + 0.2) {
- hitData0 = hitData1 = hitData2 = hitData3 = vec4(0.0);
+ /* Early out */
+ if (roughness > ssrMaxRoughness + 0.2)
return;
- }
- vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba;
+ vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0);
+
+ /* Gives *perfect* reflection for very small roughness */
+ if (roughness < 0.04) {
+ rand.xzw *= 0.0;
+ }
+ /* Importance sampling bias */
+ rand.x = mix(rand.x, 0.0, ssrBrdfBias);
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
vec3 wN = transform_direction(ViewMatrixInverse, N);
@@ -132,7 +138,7 @@ void main()
make_orthonormal_basis(N, T, B); /* Generate tangent space */
/* Planar Reflections */
- for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
PlanarData pd = planars_data[i];
float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
@@ -144,31 +150,12 @@ void main()
tracePosition = transform_point(ViewMatrix, tracePosition);
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
- hitData0 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand, 0.0);
-#if (RAY_COUNT > 1)
- hitData1 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT));
-#endif
-#if (RAY_COUNT > 2)
- hitData2 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT));
-#endif
-#if (RAY_COUNT > 3)
- hitData3 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT));
-#endif
+ do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand);
return;
}
}
- /* TODO : Raytrace together if textureGather is supported. */
- hitData0 = do_ssr(V, N, T, B, viewPosition, a2, rand, 0.0);
-#if (RAY_COUNT > 1)
- hitData1 = do_ssr(V, N, T, B, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT));
-#endif
-#if (RAY_COUNT > 2)
- hitData2 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT));
-#endif
-#if (RAY_COUNT > 3)
- hitData3 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT));
-#endif
+ do_ssr(V, N, T, B, viewPosition, a2, rand);
}
#else /* STEP_RESOLVE */
@@ -177,30 +164,42 @@ uniform sampler2D prevColorBuffer; /* previous frame */
uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
-uniform sampler2D hitBuffer0;
-uniform sampler2D hitBuffer1;
-uniform sampler2D hitBuffer2;
-uniform sampler2D hitBuffer3;
+uniform isampler2D hitBuffer;
+uniform sampler2D pdfBuffer;
+
+uniform int neighborOffset;
-uniform int probe_count;
-uniform int planar_count;
+const ivec2 neighbors[32] = ivec2[32](
+ ivec2( 0, 0), ivec2( 1, 1), ivec2(-2, 0), ivec2( 0, -2),
+ ivec2( 0, 0), ivec2( 1, -1), ivec2(-2, 0), ivec2( 0, 2),
+ ivec2( 0, 0), ivec2(-1, -1), ivec2( 2, 0), ivec2( 0, 2),
+ ivec2( 0, 0), ivec2(-1, 1), ivec2( 2, 0), ivec2( 0, -2),
-uniform mat4 PastViewProjectionMatrix;
+ ivec2( 0, 0), ivec2( 2, 2), ivec2(-2, 2), ivec2( 0, -1),
+ ivec2( 0, 0), ivec2( 2, -2), ivec2(-2, -2), ivec2( 0, 1),
+ ivec2( 0, 0), ivec2(-2, -2), ivec2(-2, 2), ivec2( 1, 0),
+ ivec2( 0, 0), ivec2( 2, 2), ivec2( 2, -2), ivec2(-1, 0)
+);
out vec4 fragColor;
-void fallback_cubemap(vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum)
+void fallback_cubemap(
+ vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum)
{
/* Specular probes */
vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
- vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0));
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
vec3 bent_normal;
- float final_ao = occlusion_compute(N, viewPosition, 1.0, rand.rg, bent_normal);
+#ifdef SSR_AO
+ float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal);
final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
+#else
+ const float final_ao = 1.0;
+#endif
/* Starts at 1 because 0 is world probe */
- for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
+ for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) {
CubeData cd = probes_data[i];
float fade = probe_attenuation_cube(cd, W);
@@ -251,90 +250,177 @@ float brightness(vec3 c)
vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
{
/* TODO real reprojection with motion vectors, etc... */
- return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
+ return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
}
-vec4 get_ssr_sample(
- sampler2D hitBuffer, PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
- float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
- inout float weight_acc)
+float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
{
- vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba;
- bool has_hit = (hit_co_pdf.z > 0.0);
- bool is_planar = (hit_co_pdf.w < 0.0);
- hit_co_pdf.z = abs(hit_co_pdf.z);
- hit_co_pdf.w = abs(hit_co_pdf.w);
-
- /* Hit position in world space. */
- hit_co_pdf.xyz = get_view_space_from_depth(hit_co_pdf.xy, hit_co_pdf.z);
- vec3 hit_pos = transform_point(ViewMatrixInverse, hit_co_pdf.xyz);
+ if (is_planar) {
+ return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r;
+ }
+ else {
+ return textureLod(depthBuffer, hit_co, 0.0).r;
+ }
+}
- vec2 ref_uvs;
+vec3 get_hit_vector(
+ vec3 hit_pos, PlanarData pd, vec3 worldPosition, vec3 N, vec3 V, bool is_planar,
+ inout vec2 hit_co, inout float mask)
+{
vec3 hit_vec;
- float mask = 1.0;
+
if (is_planar) {
/* Reflect back the hit position to have it in non-reflected world space */
vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
hit_vec = hit_pos - trace_pos;
hit_vec = reflect(hit_vec, pd.pl_normal);
- ref_uvs = project_point(ProjectionMatrix, hit_co_pdf.xyz).xy * 0.5 + 0.5;
}
else {
/* Find hit position in previous frame. */
- ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N);
+ mask = screen_border_mask(gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0)));
+ hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
hit_vec = hit_pos - worldPosition;
- mask = screen_border_mask(gl_FragCoord.xy / texture_size);
}
- mask = min(mask, screen_border_mask(ref_uvs));
- mask *= float(has_hit);
- float hit_dist = max(1e-8, length(hit_vec));
- vec3 L = hit_vec / hit_dist;
+ mask = min(mask, screen_border_mask(hit_co));
+ return hit_vec;
+}
- float cone_footprint = hit_dist * cone_tan;
+vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar)
+{
+ if (is_planar) {
+ return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb;
+ }
+ else {
+ return textureLod(prevColorBuffer, ref_uvs, mip).rgb;
+ }
+}
+
+vec4 get_ssr_samples(
+ vec4 hit_pdf, ivec4 hit_data[2],
+ PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V,
+ float roughnessSquared, float cone_tan, vec2 source_uvs,
+ inout float weight_acc)
+{
+ bvec4 is_planar, has_hit;
+ vec4 hit_co[2];
+ hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x);
+ hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y);
+ hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z);
+ hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w);
+
+ vec4 hit_depth;
+ hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index);
+ hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index);
+ hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index);
+ hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index);
+
+ /* Hit position in view space. */
+ vec3 hit_view[4];
+ hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x);
+ hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y);
+ hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z);
+ hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w);
+
+ vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z);
+ homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3];
+
+ /* Hit position in world space. */
+ vec3 hit_pos[4];
+ hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]);
+ hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]);
+ hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]);
+ hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]);
+
+ /* Get actual hit vector and hit coordinate (from last frame). */
+ vec4 mask = vec4(1.0);
+ hit_pos[0] = get_hit_vector(hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x);
+ hit_pos[1] = get_hit_vector(hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y);
+ hit_pos[2] = get_hit_vector(hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z);
+ hit_pos[3] = get_hit_vector(hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w);
+
+ vec4 hit_dist;
+ hit_dist.x = length(hit_pos[0]);
+ hit_dist.y = length(hit_pos[1]);
+ hit_dist.z = length(hit_pos[2]);
+ hit_dist.w = length(hit_pos[3]);
+ hit_dist = max(vec4(1e-8), hit_dist);
+
+ /* Normalize */
+ hit_pos[0] /= hit_dist.x;
+ hit_pos[1] /= hit_dist.y;
+ hit_pos[2] /= hit_dist.z;
+ hit_pos[3] /= hit_dist.w;
/* Compute cone footprint in screen space. */
- float homcoord = ProjectionMatrix[2][3] * hit_co_pdf.z + ProjectionMatrix[3][3];
- cone_footprint = BRDF_BIAS * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord;
+ vec4 cone_footprint = hit_dist * cone_tan;
+ cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord;
/* Estimate a cone footprint to sample a corresponding mipmap level. */
- float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, MAX_MIP);
+ vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0))));
+ mip = clamp(mip, 0.0, MAX_MIP);
/* Correct UVs for mipmaping mis-alignment */
- ref_uvs *= mip_ratio_interp(mip);
+ hit_co[0].xy *= mip_ratio_interp(mip.x);
+ hit_co[0].zw *= mip_ratio_interp(mip.y);
+ hit_co[1].xy *= mip_ratio_interp(mip.z);
+ hit_co[1].zw *= mip_ratio_interp(mip.w);
/* Slide 54 */
- float bsdf = bsdf_ggx(N, L, V, roughnessSquared);
- float weight = step(1e-8, hit_co_pdf.w) * bsdf / max(1e-8, hit_co_pdf.w);
- weight_acc += weight;
+ vec4 bsdf;
+ bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared);
+ bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared);
+ bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared);
+ bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared);
- vec3 sample;
- if (is_planar) {
- sample = textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, lodPlanarMax)).rgb;
- }
- else {
- sample = textureLod(prevColorBuffer, ref_uvs, mip).rgb;
- }
+ vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf);
- /* Clamped brightness. */
- float luma = max(1e-8, brightness(sample));
- sample *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
+ vec3 sample[4];
+ sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x);
+ sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y);
+ sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z);
+ sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w);
- /* Do not add light if ray has failed. */
- sample *= float(has_hit);
+ /* Clamped brightness. */
+ vec4 luma;
+ luma.x = brightness(sample[0]);
+ luma.y = brightness(sample[1]);
+ luma.z = brightness(sample[2]);
+ luma.w = brightness(sample[3]);
+ luma = max(vec4(1e-8), luma);
+ luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma;
+
+ sample[0] *= luma.x;
+ sample[1] *= luma.y;
+ sample[2] *= luma.z;
+ sample[3] *= luma.w;
/* Protection against NaNs in the history buffer.
* This could be removed if some previous pass has already
* sanitized the input. */
- if (any(isnan(sample))) {
- sample = vec3(0.0);
- weight = 0.0;
+ if (any(isnan(sample[0]))) {
+ sample[0] = vec3(0.0); weight.x = 0.0;
+ }
+ if (any(isnan(sample[1]))) {
+ sample[1] = vec3(0.0); weight.y = 0.0;
+ }
+ if (any(isnan(sample[2]))) {
+ sample[2] = vec3(0.0); weight.z = 0.0;
+ }
+ if (any(isnan(sample[3]))) {
+ sample[3] = vec3(0.0); weight.w = 0.0;
}
- return vec4(sample, mask) * weight;
-}
+ weight_acc += sum(weight);
-#define NUM_NEIGHBORS 4
+ /* Do not add light if ray has failed. */
+ vec4 accum;
+ accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x);
+ accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y);
+ accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z);
+ accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w);
+ return accum;
+}
void main()
{
@@ -344,9 +430,7 @@ void main()
#else
ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
#endif
- vec2 texture_size = vec2(textureSize(depthBuffer, 0));
- vec2 uvs = gl_FragCoord.xy / texture_size;
- vec3 rand = texelFetch(utilTex, ivec3(fullres_texel % LUT_SIZE, 2), 0).rba;
+ vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
float depth = textureLod(depthBuffer, uvs, 0.0).r;
@@ -366,10 +450,24 @@ void main()
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
discard;
+ /* TODO optimize with textureGather */
+ /* Doing these fetches early to hide latency. */
+ vec4 hit_pdf;
+ hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r;
+ hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r;
+ hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r;
+ hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r;
+
+ ivec4 hit_data[2];
+ hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg;
+ hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg;
+ hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg;
+ hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg;
+
/* Find Planar Reflections affecting this pixel */
PlanarData pd;
float planar_index;
- for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
pd = planars_data[i];
float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
@@ -390,55 +488,21 @@ void main()
float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */
- vec2 source_uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
+ vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
vec4 ssr_accum = vec4(0.0);
float weight_acc = 0.0;
- const ivec2 neighbors[9] = ivec2[9](
- ivec2(0, 0),
-
- ivec2(0, 1),
- ivec2(-1, -1), ivec2(1, -1),
-
- ivec2(-1, 1), ivec2(1, 1),
- ivec2(0, -1),
-
- ivec2(-1, 0), ivec2(1, 0)
- );
- ivec2 invert_neighbor;
- invert_neighbor.x = ((fullres_texel.x & 0x1) == 0) ? 1 : -1;
- invert_neighbor.y = ((fullres_texel.y & 0x1) == 0) ? 1 : -1;
-
- if (roughness < maxRoughness + 0.2) {
- for (int i = 0; i < NUM_NEIGHBORS; i++) {
- ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor;
-
- ssr_accum += get_ssr_sample(hitBuffer0, pd, planar_index, worldPosition, N, V,
- roughnessSquared, cone_tan, source_uvs,
- texture_size, target_texel, weight_acc);
-#if (RAY_COUNT > 1)
- ssr_accum += get_ssr_sample(hitBuffer1, pd, planar_index, worldPosition, N, V,
- roughnessSquared, cone_tan, source_uvs,
- texture_size, target_texel, weight_acc);
-#endif
-#if (RAY_COUNT > 2)
- ssr_accum += get_ssr_sample(hitBuffer2, pd, planar_index, worldPosition, N, V,
- roughnessSquared, cone_tan, source_uvs,
- texture_size, target_texel, weight_acc);
-#endif
-#if (RAY_COUNT > 3)
- ssr_accum += get_ssr_sample(hitBuffer3, pd, planar_index, worldPosition, N, V,
- roughnessSquared, cone_tan, source_uvs,
- texture_size, target_texel, weight_acc);
-#endif
- }
+
+ if (roughness < ssrMaxRoughness + 0.2) {
+ ssr_accum += get_ssr_samples(hit_pdf, hit_data, pd, planar_index, worldPosition, N, V,
+ roughnessSquared, cone_tan, source_uvs, weight_acc);
}
/* Compute SSR contribution */
if (weight_acc > 0.0) {
ssr_accum /= weight_acc;
/* fade between 0.5 and 1.0 roughness */
- ssr_accum.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness);
+ ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
index 88e71a060c5..184eac54c26 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -8,16 +8,19 @@ layout(std140) uniform sssProfile {
int sss_samples;
};
-uniform float jitterThreshold;
uniform sampler2D depthBuffer;
uniform sampler2D sssData;
uniform sampler2D sssAlbedo;
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
out vec4 FragColor;
uniform mat4 ProjectionMatrix;
-uniform vec4 viewvecs[2];
float get_view_z_from_depth(float depth)
{
@@ -26,7 +29,7 @@ float get_view_z_from_depth(float depth)
return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
}
else {
- return viewvecs[0].z + depth * viewvecs[1].z;
+ return viewVecs[0].z + depth * viewVecs[1].z;
}
}
@@ -41,7 +44,7 @@ void main(void)
vec4 sss_data = texture(sssData, uvs).rgba;
float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r);
- float rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2), 0).r;
+ float rand = texelfetch_noise_tex(gl_FragCoord.xy).r;
#ifdef FIRST_PASS
float angle = M_2PI * rand + M_PI_2;
vec2 dir = vec2(1.0, 0.0);
@@ -61,7 +64,7 @@ void main(void)
vec3 accum = sss_data.rgb * kernel[0].rgb;
for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) {
- vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > jitterThreshold) ? dir : dir_rand);
+ vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand);
vec3 color = texture(sssData, sample_uv).rgb;
float sample_depth = texture(depthBuffer, sample_uv).r;
sample_depth = get_view_z_from_depth(sample_depth);
diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
index 76d20486d3d..132cc16fcbd 100644
--- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
@@ -1,6 +1,5 @@
uniform sampler2DArray irradianceGrid;
-uniform int irradianceVisibilitySize;
#define IRRADIANCE_LIB
@@ -81,8 +80,8 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range)
{
/* Keep in sync with diffuse_filter_probe() */
- ivec2 cell_co = ivec2(irradianceVisibilitySize);
- ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / irradianceVisibilitySize;
+ ivec2 cell_co = ivec2(prbIrradianceVisSize);
+ ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize;
cell_co.x *= (cell % cell_per_row_col.x);
cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y;
float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y);
@@ -90,8 +89,8 @@ float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed
vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy);
vec2 co = vec2(cell_co) * texel_size;
- vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize)));
- uv *= vec2(irradianceVisibilitySize) * texel_size;
+ vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize)));
+ uv *= vec2(prbIrradianceVisSize) * texel_size;
vec4 data = texture(irradianceGrid, vec3(co + uv, layer));
diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
index 933f056c401..1c7956bb807 100644
--- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
@@ -161,7 +161,7 @@ float light_visibility(LightData ld, vec3 W,
float x = dot(ld.l_right, lL) / ld.l_sizex;
float y = dot(ld.l_up, lL) / ld.l_sizey;
- float ellipse = 1.0 / sqrt(1.0 + x * x + y * y);
+ float ellipse = inversesqrt(1.0 + x * x + y * y);
float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend);
@@ -203,14 +203,13 @@ float light_visibility(LightData ld, vec3 W,
vec3 T, B;
make_orthonormal_basis(L.xyz / L.w, T, B);
- vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw;
- /* XXX This is a hack to not have noise correlation artifacts.
- * A better solution to have better noise is welcome. */
- rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_contact_spread;
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ /* WATCH THIS : This still seems to have correlation artifacts for low samples. */
+ rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread;
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
- vec3 ray_dir = L.xyz + T * rand.y + B * rand.z;
+ vec3 ray_dir = L.xyz + T * rand.z + B * rand.w;
ray_dir = transform_direction(ViewMatrix, ray_dir);
ray_dir = normalize(ray_dir);
vec3 ray_origin = viewPosition + viewNormal * data.sh_contact_offset;
@@ -235,8 +234,7 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
{
#ifdef USE_LTC
if (ld.l_type == SUN) {
- /* TODO disk area light */
- return direct_diffuse_sun(ld, N);
+ return direct_diffuse_unit_disc(ld, N, V);
}
else if (ld.l_type == AREA) {
return direct_diffuse_rectangle(ld, N, V, l_vector);
@@ -258,8 +256,7 @@ vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness
{
#ifdef USE_LTC
if (ld.l_type == SUN) {
- /* TODO disk area light */
- return direct_ggx_sun(ld, N, V, roughness, f0);
+ return direct_ggx_unit_disc(ld, N, V, roughness, f0);
}
else if (ld.l_type == AREA) {
return direct_ggx_rectangle(ld, N, V, l_vector, roughness, f0);
@@ -298,9 +295,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
{
#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
return vec3(0.0);
-#endif
-
-#ifndef VOLUMETRICS
+#else
vec3 vis = vec3(1.0);
/* Only shadowed light can produce translucency */
@@ -313,14 +308,13 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
vec3 T, B;
make_orthonormal_basis(L.xyz / L.w, T, B);
- vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw;
- /* XXX This is a hack to not have noise correlation artifacts.
- * A better solution to have better noise is welcome. */
- rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_blur;
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ /* WATCH THIS : This still seems to have correlation artifacts for low samples. */
+ rand.zw *= fast_sqrt(rand.y) * data.sh_blur;
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
- W = W + T * rand.y + B * rand.z;
+ W = W + T * rand.z + B * rand.w;
if (ld.l_type == SUN) {
ShadowCascadeData scd = shadows_cascade_data[int(data.sh_data_start)];
@@ -374,19 +368,24 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
/* TODO : put this out of the shader. */
float falloff;
if (ld.l_type == AREA) {
- vis *= 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI);
+ vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ vis *= 0.3 * 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
vis /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
else if (ld.l_type == SUN) {
+ vis *= (4.0f * ld.l_radius * ld.l_radius * M_2PI) * (1.0 / 12.5); /* Removing area light power*/
+ vis *= M_2PI * 0.78; /* Matching cycles with point light. */
+ vis *= 0.082; /* XXX ad hoc, empirical */
falloff = dot(N, -ld.l_forward);
}
else {
- vis *= 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI);
+ vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0);
+ vis *= 1.5; /* XXX ad hoc, empirical */
vis /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
- vis *= M_1_PI; /* Normalize */
+ // vis *= M_1_PI; /* Normalize */
/* Applying profile */
vis *= sss_profile(abs(delta) / scale);
@@ -400,7 +399,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
float x = dot(ld.l_right, lL) / ld.l_sizex;
float y = dot(ld.l_up, lL) / ld.l_sizey;
- float ellipse = 1.0 / sqrt(1.0 + x * x + y * y);
+ float ellipse = inversesqrt(1.0 + x * x + y * y);
float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend);
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
index fc0b5b9548b..d10f4bc0d42 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
@@ -11,5 +11,5 @@ void main()
? normalize(cameraPos - worldPosition)
: cameraForward;
vec3 N = normalize(worldNormal);
- FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, lodCubeMax).rgb, 1.0);
+ FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, prbLodCubeMax).rgb, 1.0);
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
index eb4315c93a3..b19ee7a9ea3 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -3,6 +3,7 @@ uniform samplerCube probeHdr;
uniform int probeSize;
uniform float lodFactor;
uniform float lodMax;
+uniform float intensityFac;
in vec3 worldPosition;
@@ -192,6 +193,6 @@ void main()
}
}
- FragColor = irradiance_encode(out_radiance / weight);
+ FragColor = irradiance_encode(intensityFac * out_radiance / weight);
#endif
} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
index 33714c5293c..3aec3ce4642 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
@@ -5,6 +5,7 @@ uniform float texelSize;
uniform float lodFactor;
uniform float lodMax;
uniform float paddingSize;
+uniform float intensityFac;
in vec3 worldPosition;
@@ -82,5 +83,5 @@ void main() {
}
}
- FragColor = vec4(out_radiance / weight, 1.0);
+ FragColor = vec4(intensityFac * out_radiance / weight, 1.0);
} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index e914228aded..429f6ea92e4 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -1,10 +1,7 @@
/* ----------- Uniforms --------- */
uniform sampler2DArray probePlanars;
-uniform float lodPlanarMax;
-
uniform sampler2DArray probeCubes;
-uniform float lodCubeMax;
/* ----------- Structures --------- */
@@ -162,12 +159,12 @@ vec3 probe_evaluate_cube(float id, CubeData cd, vec3 W, vec3 R, float roughness)
float fac = saturate(original_roughness * 2.0 - 1.0);
R = mix(intersection, R, fac * fac);
- return textureLod_octahedron(probeCubes, vec4(R, id), roughness * lodCubeMax, lodCubeMax).rgb;
+ return textureLod_octahedron(probeCubes, vec4(R, id), roughness * prbLodCubeMax, prbLodCubeMax).rgb;
}
vec3 probe_evaluate_world_spec(vec3 R, float roughness)
{
- return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * lodCubeMax, lodCubeMax).rgb;
+ return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax).rgb;
}
vec3 probe_evaluate_planar(
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 6ecaf0a627b..cc66b477da0 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -2,19 +2,12 @@
#ifndef LIT_SURFACE_UNIFORM
#define LIT_SURFACE_UNIFORM
-uniform int light_count;
-uniform int probe_count;
-uniform int grid_count;
-uniform int planar_count;
-
-uniform bool specToggle;
-uniform bool ssrToggle;
-
uniform float refractionDepth;
#ifndef UTIL_TEX
#define UTIL_TEX
uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
in vec3 worldPosition;
@@ -28,9 +21,6 @@ in vec3 worldNormal;
in vec3 viewNormal;
#endif
-uniform float maxRoughness;
-uniform int rayCount;
-
#endif /* LIT_SURFACE_UNIFORM */
/** AUTO CONFIG
@@ -176,7 +166,7 @@ void CLOSURE_NAME(
vec3 V = cameraVec;
- vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0));
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
/* ---------------------------------------------------------------- */
/* -------------------- SCENE LAMPS LIGHTING ---------------------- */
@@ -187,7 +177,7 @@ void CLOSURE_NAME(
norm_view = normalize(cross(norm_view, N)); /* Normal facing view */
#endif
- for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) {
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
LightData ld = lights_data[i];
vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
@@ -266,7 +256,7 @@ void CLOSURE_NAME(
/* Planar Reflections */
/* ---------------------------- */
- for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) {
PlanarData pd = planars_data[i];
/* Fade on geometric normal. */
@@ -312,17 +302,11 @@ void CLOSURE_NAME(
/* Screen Space Refraction */
/* ---------------------------- */
#ifdef USE_REFRACTION
- if (ssrToggle && roughness < maxRoughness + 0.2) {
+ if (ssrToggle && roughness < ssrMaxRoughness + 0.2) {
/* Find approximated position of the 2nd refraction event. */
vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition;
-
- float ray_ofs = 1.0 / float(rayCount);
- vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw, 0.0);
- if (rayCount > 1) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs);
- if (rayCount > 2) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs);
- if (rayCount > 3) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs);
- trans /= float(rayCount);
- trans.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness);
+ vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand);
+ trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
accumulate_light(trans.rgb, trans.a, refr_accum);
}
#endif
@@ -342,7 +326,7 @@ void CLOSURE_NAME(
#endif
/* Starts at 1 because 0 is world probe */
- for (int i = 1; ACCUM.a < 0.999 && i < probe_count && i < MAX_PROBE; ++i) {
+ for (int i = 1; ACCUM.a < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) {
CubeData cd = probes_data[i];
float fade = probe_attenuation_cube(cd, worldPosition);
@@ -402,7 +386,7 @@ void CLOSURE_NAME(
/* ---------------------------- */
#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
vec3 bent_normal;
- float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal);
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
#endif
@@ -417,12 +401,14 @@ void CLOSURE_NAME(
/* This factor is outputed to be used by SSR in order
* to match the intensity of the regular reflections. */
ssr_spec = F_ibl(f0, brdf_lut);
- if (!(ssrToggle && ssr_id == outputSsrId)) {
- /* The SSR pass recompute the occlusion to not apply it to the SSR */
- ssr_spec *= specular_occlusion(NV, final_ao, roughness);
+ float spec_occlu = specular_occlusion(NV, final_ao, roughness);
+
+ /* The SSR pass recompute the occlusion to not apply it to the SSR */
+ if (ssrToggle && ssr_id == outputSsrId) {
+ spec_occlu = 1.0;
}
- out_spec += spec_accum.rgb * ssr_spec * float(specToggle);
+ out_spec += spec_accum.rgb * ssr_spec * spec_occlu * float(specToggle);
#endif
#ifdef CLOSURE_REFRACTION
@@ -452,7 +438,7 @@ void CLOSURE_NAME(
/* Irradiance Grids */
/* ---------------------------- */
/* Start at 1 because 0 is world irradiance */
- for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) {
+ for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) {
GridData gd = grids_data[i];
vec3 localpos;
@@ -467,7 +453,7 @@ void CLOSURE_NAME(
/* ---------------------------- */
/* World Diffuse */
/* ---------------------------- */
- if (diff_accum.a < 0.999 && grid_count > 0) {
+ if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) {
vec3 diff = probe_evaluate_world_diff(bent_normal);
accumulate_light(diff, 1.0, diff_accum);
}
diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
index ffaa81c3638..5c62cb19152 100644
--- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
@@ -1,150 +1,140 @@
-/* Mainly From https://eheitzresearch.wordpress.com/415-2/ */
+/**
+ * Adapted from :
+ * Real-Time Polygonal-Light Shading with Linearly Transformed Cosines.
+ * Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt.
+ * ACM Transactions on Graphics (Proceedings of ACM SIGGRAPH 2016) 35(4), 2016.
+ * Project page: https://eheitzresearch.wordpress.com/415-2/
+ **/
#define USE_LTC
#ifndef UTIL_TEX
#define UTIL_TEX
uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
-/* from Real-Time Area Lighting: a Journey from Research to Production
- * Stephen Hill and Eric Heitz */
-float edge_integral(vec3 p1, vec3 p2)
+/* Diffuse *clipped* sphere integral. */
+float diffuse_sphere_integral_lut(float avg_dir_z, float form_factor)
{
-#if 0
- /* more accurate replacement of acos */
- float x = dot(p1, p2);
- float y = abs(x);
+ vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor);
+ uv = uv * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
- float a = 5.42031 + (3.12829 + 0.0902326 * y) * y;
- float b = 3.45068 + (4.18814 + y) * y;
- float theta_sintheta = a / b;
-
- if (x < 0.0) {
- theta_sintheta = (M_PI / sqrt(1.0 - x * x)) - theta_sintheta;
- }
- vec3 u = cross(p1, p2);
- return theta_sintheta * dot(u, N);
-#endif
- float cos_theta = dot(p1, p2);
- cos_theta = clamp(cos_theta, -0.9999, 0.9999);
+ return texture(utilTex, vec3(uv, 1.0)).w;
+}
- float theta = acos(cos_theta);
- vec3 u = normalize(cross(p1, p2));
- return theta * cross(p1, p2).z / sin(theta);
+float diffuse_sphere_integral_cheap(float avg_dir_z, float form_factor)
+{
+ return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0);
}
-int clip_quad_to_horizon(inout vec3 L[5])
+/**
+ * An extended version of the implementation from
+ * "How to solve a cubic equation, revisited"
+ * http://momentsingraphics.de/?p=105
+ **/
+vec3 solve_cubic(vec4 coefs)
{
- /* detect clipping config */
- int config = 0;
- if (L[0].z > 0.0) config += 1;
- if (L[1].z > 0.0) config += 2;
- if (L[2].z > 0.0) config += 4;
- if (L[3].z > 0.0) config += 8;
+ /* Normalize the polynomial */
+ coefs.xyz /= coefs.w;
+ /* Divide middle coefficients by three */
+ coefs.yz /= 3.0;
- /* clip */
- int n = 0;
+ float A = coefs.w;
+ float B = coefs.z;
+ float C = coefs.y;
+ float D = coefs.x;
- if (config == 0)
- {
- /* clip all */
- }
- else if (config == 1) /* V1 clip V2 V3 V4 */
- {
- n = 3;
- L[1] = -L[1].z * L[0] + L[0].z * L[1];
- L[2] = -L[3].z * L[0] + L[0].z * L[3];
- }
- else if (config == 2) /* V2 clip V1 V3 V4 */
- {
- n = 3;
- L[0] = -L[0].z * L[1] + L[1].z * L[0];
- L[2] = -L[2].z * L[1] + L[1].z * L[2];
- }
- else if (config == 3) /* V1 V2 clip V3 V4 */
- {
- n = 4;
- L[2] = -L[2].z * L[1] + L[1].z * L[2];
- L[3] = -L[3].z * L[0] + L[0].z * L[3];
- }
- else if (config == 4) /* V3 clip V1 V2 V4 */
- {
- n = 3;
- L[0] = -L[3].z * L[2] + L[2].z * L[3];
- L[1] = -L[1].z * L[2] + L[2].z * L[1];
- }
- else if (config == 5) /* V1 V3 clip V2 V4) impossible */
- {
- n = 0;
- }
- else if (config == 6) /* V2 V3 clip V1 V4 */
- {
- n = 4;
- L[0] = -L[0].z * L[1] + L[1].z * L[0];
- L[3] = -L[3].z * L[2] + L[2].z * L[3];
- }
- else if (config == 7) /* V1 V2 V3 clip V4 */
- {
- n = 5;
- L[4] = -L[3].z * L[0] + L[0].z * L[3];
- L[3] = -L[3].z * L[2] + L[2].z * L[3];
- }
- else if (config == 8) /* V4 clip V1 V2 V3 */
- {
- n = 3;
- L[0] = -L[0].z * L[3] + L[3].z * L[0];
- L[1] = -L[2].z * L[3] + L[3].z * L[2];
- L[2] = L[3];
- }
- else if (config == 9) /* V1 V4 clip V2 V3 */
- {
- n = 4;
- L[1] = -L[1].z * L[0] + L[0].z * L[1];
- L[2] = -L[2].z * L[3] + L[3].z * L[2];
- }
- else if (config == 10) /* V2 V4 clip V1 V3) impossible */
- {
- n = 0;
- }
- else if (config == 11) /* V1 V2 V4 clip V3 */
- {
- n = 5;
- L[4] = L[3];
- L[3] = -L[2].z * L[3] + L[3].z * L[2];
- L[2] = -L[2].z * L[1] + L[1].z * L[2];
- }
- else if (config == 12) /* V3 V4 clip V1 V2 */
+ /* Compute the Hessian and the discriminant */
+ vec3 delta = vec3(
+ -coefs.z*coefs.z + coefs.y,
+ -coefs.y*coefs.z + coefs.x,
+ dot(vec2(coefs.z, -coefs.y), coefs.xy)
+ );
+
+ /* Discriminant */
+ float discr = dot(vec2(4.0 * delta.x, -delta.y), delta.zy);
+
+ vec2 xlc, xsc;
+
+ /* Algorithm A */
{
- n = 4;
- L[1] = -L[1].z * L[2] + L[2].z * L[1];
- L[0] = -L[0].z * L[3] + L[3].z * L[0];
+ float A_a = 1.0;
+ float C_a = delta.x;
+ float D_a = -2.0 * B * delta.x + delta.y;
+
+ /* Take the cubic root of a normalized complex number */
+ float theta = atan(sqrt(discr), -D_a) / 3.0;
+
+ float x_1a = 2.0 * sqrt(-C_a) * cos(theta);
+ float x_3a = 2.0 * sqrt(-C_a) * cos(theta + (2.0 / 3.0) * M_PI);
+
+ float xl;
+ if ((x_1a + x_3a) > 2.0 * B) {
+ xl = x_1a;
+ }
+ else {
+ xl = x_3a;
+ }
+
+ xlc = vec2(xl - B, A);
}
- else if (config == 13) /* V1 V3 V4 clip V2 */
+
+ /* Algorithm D */
{
- n = 5;
- L[4] = L[3];
- L[3] = L[2];
- L[2] = -L[1].z * L[2] + L[2].z * L[1];
- L[1] = -L[1].z * L[0] + L[0].z * L[1];
+ float A_d = D;
+ float C_d = delta.z;
+ float D_d = -D * delta.y + 2.0 * C * delta.z;
+
+ /* Take the cubic root of a normalized complex number */
+ float theta = atan(D * sqrt(discr), -D_d) / 3.0;
+
+ float x_1d = 2.0 * sqrt(-C_d) * cos(theta);
+ float x_3d = 2.0 * sqrt(-C_d) * cos(theta + (2.0 / 3.0) * M_PI);
+
+ float xs;
+ if (x_1d + x_3d < 2.0 * C)
+ xs = x_1d;
+ else
+ xs = x_3d;
+
+ xsc = vec2(-D, xs + C);
}
- else if (config == 14) /* V2 V3 V4 clip V1 */
- {
- n = 5;
- L[4] = -L[0].z * L[3] + L[3].z * L[0];
- L[0] = -L[0].z * L[1] + L[1].z * L[0];
+
+ float E = xlc.y * xsc.y;
+ float F = -xlc.x * xsc.y - xlc.y * xsc.x;
+ float G = xlc.x * xsc.x;
+
+ vec2 xmc = vec2(C * F - B * G, -B * F + C * E);
+
+ vec3 root = vec3(xsc.x / xsc.y,
+ xmc.x / xmc.y,
+ xlc.x / xlc.y);
+
+ if (root.x < root.y && root.x < root.z) {
+ root.xyz = root.yxz;
}
- else if (config == 15) /* V1 V2 V3 V4 */
- {
- n = 4;
+ else if (root.z < root.x && root.z < root.y) {
+ root.xyz = root.xzy;
}
- if (n == 3)
- L[3] = L[0];
- if (n == 4)
- L[4] = L[0];
+ return root;
+}
+
+/* from Real-Time Area Lighting: a Journey from Research to Production
+ * Stephen Hill and Eric Heitz */
+vec3 edge_integral_vec(vec3 v1, vec3 v2)
+{
+ float x = dot(v1, v2);
+ float y = abs(x);
+
+ float a = 0.8543985 + (0.4965155 + 0.0145206 * y) * y;
+ float b = 3.4175940 + (4.1616724 + y) * y;
+ float v = a / b;
- return n;
+ float theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt(max(1.0 - x * x, 1e-7)) - v;
+
+ return cross(v1, v2) * theta_sintheta;
}
mat3 ltc_matrix(vec4 lut)
@@ -159,7 +149,7 @@ mat3 ltc_matrix(vec4 lut)
return Minv;
}
-float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4])
+void ltc_transform_quad(vec3 N, vec3 V, mat3 Minv, inout vec3 corners[4])
{
/* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */
V = normalize(V + 1e-8);
@@ -172,42 +162,51 @@ float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4])
/* rotate area light in (T1, T2, R) basis */
Minv = Minv * transpose(mat3(T1, T2, N));
- /* polygon (allocate 5 vertices for clipping) */
- vec3 L[5];
- L[0] = Minv * corners[0];
- L[1] = Minv * corners[1];
- L[2] = Minv * corners[2];
- L[3] = Minv * corners[3];
-
- int n = clip_quad_to_horizon(L);
-
- if (n == 0)
- return 0.0;
-
- /* project onto sphere */
- L[0] = normalize(L[0]);
- L[1] = normalize(L[1]);
- L[2] = normalize(L[2]);
- L[3] = normalize(L[3]);
- L[4] = normalize(L[4]);
-
- /* integrate */
- float sum = 0.0;
-
- sum += edge_integral(L[0], L[1]);
- sum += edge_integral(L[1], L[2]);
- sum += edge_integral(L[2], L[3]);
- if (n >= 4)
- sum += edge_integral(L[3], L[4]);
- if (n == 5)
- sum += edge_integral(L[4], L[0]);
-
- return abs(sum);
+ /* Apply LTC inverse matrix. */
+ corners[0] = normalize(Minv * corners[0]);
+ corners[1] = normalize(Minv * corners[1]);
+ corners[2] = normalize(Minv * corners[2]);
+ corners[3] = normalize(Minv * corners[3]);
}
-/* Aproximate circle with an octogone */
-#define LTC_CIRCLE_RES 8
-float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES])
+/* If corners have already pass through ltc_transform_quad(), then N **MUST** be vec3(0.0, 0.0, 1.0),
+ * corresponding to the Up axis of the shading basis. */
+float ltc_evaluate_quad(vec3 corners[4], vec3 N)
+{
+ /* Approximation using a sphere of the same solid angle than the quad.
+ * Finding the clipped sphere diffuse integral is easier than clipping the quad. */
+ vec3 avg_dir;
+ avg_dir = edge_integral_vec(corners[0], corners[1]);
+ avg_dir += edge_integral_vec(corners[1], corners[2]);
+ avg_dir += edge_integral_vec(corners[2], corners[3]);
+ avg_dir += edge_integral_vec(corners[3], corners[0]);
+
+ float form_factor = length(avg_dir);
+ float avg_dir_z = dot(N, avg_dir / form_factor);
+
+#if 1 /* use tabulated horizon-clipped sphere */
+ return form_factor * diffuse_sphere_integral_lut(avg_dir_z, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+ return form_factor * diffuse_sphere_integral_cheap(avg_dir_z, form_factor);
+#endif
+}
+
+/* If disk does not need to be transformed and is already front facing. */
+float ltc_evaluate_disk_simple(float disk_radius, float NL)
+{
+ float r_sqr = disk_radius * disk_radius;
+ float one_r_sqr = 1.0 + r_sqr;
+ float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr);
+
+#if 1 /* use tabulated horizon-clipped sphere */
+ return form_factor * diffuse_sphere_integral_lut(NL, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+ return form_factor * diffuse_sphere_integral_cheap(NL, form_factor);
+#endif
+}
+
+/* disk_points are WS vectors from the shading point to the disk "bounding domain" */
+float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3])
{
/* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */
V = normalize(V + 1e-8);
@@ -218,23 +217,106 @@ float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES])
T2 = cross(N, T1);
/* rotate area light in (T1, T2, R) basis */
- Minv = Minv * transpose(mat3(T1, T2, N));
+ mat3 R = transpose(mat3(T1, T2, N));
- for (int i = 0; i < LTC_CIRCLE_RES; ++i) {
- p[i] = Minv * p[i];
- /* clip to horizon */
- p[i].z = max(0.0, p[i].z);
- /* project onto sphere */
- p[i] = normalize(p[i]);
- }
+ /* Intermediate step: init ellipse. */
+ vec3 L_[3];
+ L_[0] = mul(R, disk_points[0]);
+ L_[1] = mul(R, disk_points[1]);
+ L_[2] = mul(R, disk_points[2]);
+
+ vec3 C = 0.5 * (L_[0] + L_[2]);
+ vec3 V1 = 0.5 * (L_[1] - L_[2]);
+ vec3 V2 = 0.5 * (L_[1] - L_[0]);
+
+ /* Transform ellipse by Minv. */
+ C = Minv * C;
+ V1 = Minv * V1;
+ V2 = Minv * V2;
+
+ /* Compute eigenvectors of new ellipse. */
- /* integrate */
- float sum = 0.0;
- for (int i = 0; i < LTC_CIRCLE_RES - 1; ++i) {
- sum += edge_integral(p[i], p[i + 1]);
+ float d11 = dot(V1, V1);
+ float d22 = dot(V2, V2);
+ float d12 = dot(V1, V2);
+ float a, b; /* Eigenvalues */
+ const float threshold = 0.0007; /* Can be adjusted. Fix artifacts. */
+ if (abs(d12) / sqrt(d11 * d22) > threshold) {
+ float tr = d11 + d22;
+ float det = -d12 * d12 + d11 * d22;
+
+ /* use sqrt matrix to solve for eigenvalues */
+ det = sqrt(det);
+ float u = 0.5 * sqrt(tr - 2.0 * det);
+ float v = 0.5 * sqrt(tr + 2.0 * det);
+ float e_max = (u + v);
+ float e_min = (u - v);
+ e_max *= e_max;
+ e_min *= e_min;
+
+ vec3 V1_, V2_;
+ if (d11 > d22) {
+ V1_ = d12 * V1 + (e_max - d11) * V2;
+ V2_ = d12 * V1 + (e_min - d11) * V2;
+ }
+ else {
+ V1_ = d12 * V2 + (e_max - d22) * V1;
+ V2_ = d12 * V2 + (e_min - d22) * V1;
+ }
+
+ a = 1.0 / e_max;
+ b = 1.0 / e_min;
+ V1 = normalize(V1_);
+ V2 = normalize(V2_);
}
- sum += edge_integral(p[LTC_CIRCLE_RES - 1], p[0]);
+ else {
+ a = 1.0 / d11;
+ b = 1.0 / d22;
+ V1 *= sqrt(a);
+ V2 *= sqrt(b);
+ }
+
+ /* Now find front facing ellipse with same solid angle. */
- return max(0.0, sum);
+ vec3 V3 = normalize(cross(V1, V2));
+ if (dot(C, V3) < 0.0)
+ V3 *= -1.0;
+
+ float L = dot(V3, C);
+ float x0 = dot(V1, C) / L;
+ float y0 = dot(V2, C) / L;
+
+ a *= L*L;
+ b *= L*L;
+
+ float c0 = a * b;
+ float c1 = a * b * (1.0 + x0 * x0 + y0 * y0) - a - b;
+ float c2 = 1.0 - a * (1.0 + x0 * x0) - b * (1.0 + y0 * y0);
+ float c3 = 1.0;
+
+ vec3 roots = solve_cubic(vec4(c0, c1, c2, c3));
+ float e1 = roots.x;
+ float e2 = roots.y;
+ float e3 = roots.z;
+
+ vec3 avg_dir = vec3(a * x0 / (a - e2), b * y0 / (b - e2), 1.0);
+
+ mat3 rotate = mat3(V1, V2, V3);
+
+ avg_dir = rotate * avg_dir;
+ avg_dir = normalize(avg_dir);
+
+ /* L1, L2 are the extends of the front facing ellipse. */
+ float L1 = sqrt(-e2/e3);
+ float L2 = sqrt(-e2/e1);
+
+ /* Find the sphere and compute lighting. */
+ float form_factor = max(0.0, L1 * L2 * inversesqrt((1.0 + L1 * L1) * (1.0 + L2 * L2)));
+
+#if 1 /* use tabulated horizon-clipped sphere */
+ return form_factor * diffuse_sphere_integral_lut(avg_dir.z, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+ return form_factor * diffuse_sphere_integral_cheap(avg_dir.z, form_factor);
+#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index f921d56e3bc..1c0e65f0613 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -10,14 +10,15 @@ float hash3d(vec3 a) {
return hash(vec2(hash(a.xy), a.z));
}
-//uniform float hashScale;
-float hashScale = 0.001;
+uniform float hashAlphaOffset;
float hashed_alpha_threshold(vec3 co)
{
+ const float hash_scale = 1.0; /* Roughly in pixel */
+
/* Find the discretized derivatives of our coordinates. */
float max_deriv = max(length(dFdx(co)), length(dFdy(co)));
- float pix_scale = 1.0 / (hashScale * max_deriv);
+ float pix_scale = 1.0 / (hash_scale * max_deriv);
/* Find two nearest log-discretized noise scales. */
float pix_scale_log = log2(pix_scale);
@@ -53,7 +54,8 @@ float hashed_alpha_threshold(vec3 co)
/* Avoids threshold == 0. */
threshold = clamp(threshold, 1.0e-6, 1.0);
- return threshold;
+ /* Jitter the threshold for TAA accumulation. */
+ return fract(threshold + hashAlphaOffset);
}
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index c593081ce91..cb75731b7da 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -1,13 +1,5 @@
#define MAX_STEP 256
-uniform vec4 ssrParameters;
-
-#define ssrQuality ssrParameters.x
-#define ssrThickness ssrParameters.y
-#define ssrPixelSize ssrParameters.zw
-
-uniform float borderFadeFactor;
-
float sample_depth(vec2 uv, int index, float lod)
{
#ifdef PLANAR_PROBE_RAYTRACE
@@ -233,7 +225,7 @@ vec3 raycast(
float screen_border_mask(vec2 hit_co)
{
const float margin = 0.003;
- float atten = borderFadeFactor + margin; /* Screen percentage */
+ float atten = ssrBorderFac + margin; /* Screen percentage */
hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co));
float screenfade = hit_co.x * hit_co.y;
diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
index 92287d2ecbc..6c7bfeb6b82 100644
--- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
@@ -2,10 +2,9 @@
#define BTDF_BIAS 0.85
-vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec3 rand, float ofs)
+vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand)
{
float a2 = max(5e-6, roughnessSquared * roughnessSquared);
- float jitter = fract(rand.x + ofs);
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, BTDF_BIAS);
@@ -13,12 +12,12 @@ vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float
vec3 T, B;
float NH;
make_orthonormal_basis(N, T, B);
- vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
+ vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
float pdf = pdf_ggx_reflect(NH, a2);
/* If ray is bad (i.e. going below the plane) regenerate. */
if (F_eta(ior, dot(H, V)) < 1.0) {
- H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
+ H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
pdf = pdf_ggx_reflect(NH, a2);
}
@@ -33,7 +32,7 @@ vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float
R = transform_direction(ViewMatrix, R);
- vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, roughnessSquared, false);
+ vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false);
if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
diff --git a/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
new file mode 100644
index 00000000000..13ffe02eb0d
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
@@ -0,0 +1,18 @@
+
+uniform sampler2D blueNoise;
+uniform vec3 offsets;
+
+out vec4 FragColor;
+
+#define M_2PI 6.28318530717958647692
+
+void main(void)
+{
+ vec2 blue_noise = texelFetch(blueNoise, ivec2(gl_FragCoord.xy), 0).xy;
+
+ float noise = fract(blue_noise.y + offsets.z);
+ FragColor.x = fract(blue_noise.x + offsets.x);
+ FragColor.y = fract(blue_noise.y + offsets.y);
+ FragColor.z = cos(noise * M_2PI);
+ FragColor.w = sin(noise * M_2PI);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index 00e01e753f9..3a293647f84 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -4,9 +4,6 @@
#define NODETREE_EXEC
-uniform ivec3 volumeTextureSize;
-uniform vec3 volume_jitter;
-
#ifdef MESH_SHADER
uniform mat4 volumeObjectMatrix;
uniform vec3 volumeOrcoLoc;
@@ -33,7 +30,7 @@ layout(location = 3) out vec4 volumePhase;
void main()
{
ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
- vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volumeTextureSize);
+ vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz);
viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
worldPosition = transform_point(ViewMatrixInverse, viewPosition);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
index 1376c53d633..1a8167c2830 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
@@ -2,22 +2,16 @@
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
-uniform float volume_light_clamp;
-
-uniform vec3 volume_param; /* Parameters to the volume Z equation */
-
-uniform vec2 volume_uv_ratio; /* To convert volume uvs to screen uvs */
-
/* Volume slice to view space depth. */
float volume_z_to_view_z(float z)
{
if (ProjectionMatrix[3][3] == 0.0) {
/* Exponential distribution */
- return (exp2(z / volume_param.z) - volume_param.x) / volume_param.y;
+ return (exp2(z / volDepthParameters.z) - volDepthParameters.x) / volDepthParameters.y;
}
else {
/* Linear distribution */
- return mix(volume_param.x, volume_param.y, z);
+ return mix(volDepthParameters.x, volDepthParameters.y, z);
}
}
@@ -25,11 +19,11 @@ float view_z_to_volume_z(float depth)
{
if (ProjectionMatrix[3][3] == 0.0) {
/* Exponential distribution */
- return volume_param.z * log2(depth * volume_param.y + volume_param.x);
+ return volDepthParameters.z * log2(depth * volDepthParameters.y + volDepthParameters.x);
}
else {
/* Linear distribution */
- return (depth - volume_param.x) * volume_param.z;
+ return (depth - volDepthParameters.x) * volDepthParameters.z;
}
}
@@ -38,7 +32,7 @@ vec3 volume_to_ndc(vec3 cos)
{
cos.z = volume_z_to_view_z(cos.z);
cos.z = get_depth_from_view_z(cos.z);
- cos.xy /= volume_uv_ratio;
+ cos.xy /= volCoordScale.xy;
return cos;
}
@@ -46,7 +40,7 @@ vec3 ndc_to_volume(vec3 cos)
{
cos.z = get_view_z_from_depth(cos.z);
cos.z = view_z_to_volume_z(cos.z);
- cos.xy *= volume_uv_ratio;
+ cos.xy *= volCoordScale.xy;
return cos;
}
@@ -71,14 +65,17 @@ vec3 light_volume(LightData ld, vec4 l_vector)
/* TODO : Area lighting ? */
/* XXX : Removing Area Power. */
/* TODO : put this out of the shader. */
+ /* See eevee_light_setup(). */
if (ld.l_type == AREA) {
- power = 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI);
+ power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ power *= 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
}
else if (ld.l_type == SUN) {
- power = 1.0;
+ power = (4.0f * ld.l_radius * ld.l_radius * M_2PI) * (1.0 / 12.5); /* Removing area light power*/
+ power *= M_2PI * 0.78; /* Matching cycles with point light. */
}
else {
- power = 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI);
+ power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0);
}
/* OPTI: find a better way than calculating this on the fly */
@@ -87,15 +84,13 @@ vec3 light_volume(LightData ld, vec4 l_vector)
power /= (l_vector.w * l_vector.w);
- lum = min(lum * power, volume_light_clamp);
+ lum = min(lum * power, volLightClamp);
return tint * lum;
}
#define VOLUMETRIC_SHADOW_MAX_STEP 32.0
-uniform float volume_shadows_steps;
-
vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction)
{
/* Waiting for proper volume shadowmaps and out of frustum shadow map. */
@@ -110,11 +105,11 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v
{
#if defined(VOLUME_SHADOW)
/* Heterogeneous volume shadows */
- float dd = l_vector.w / volume_shadows_steps;
+ float dd = l_vector.w / volShadowSteps;
vec3 L = l_vector.xyz * l_vector.w;
vec3 shadow = vec3(1.0);
- for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volume_shadows_steps - 0.1); s += 1.0) {
- vec3 pos = ray_wpos + L * (s / volume_shadows_steps);
+ for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) {
+ vec3 pos = ray_wpos + L * (s / volShadowSteps);
vec3 s_extinction = participating_media_extinction(pos, volume_extinction);
shadow *= exp(-s_extinction * dd);
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
index ea402ff3d99..fcbb6661b14 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -13,28 +13,20 @@ uniform sampler3D volumePhase;
uniform sampler3D historyScattering;
uniform sampler3D historyTransmittance;
-uniform vec3 volume_jitter;
-uniform float volume_history_alpha;
-uniform int light_count;
-uniform mat4 PastViewProjectionMatrix;
-
flat in int slice;
layout(location = 0) out vec4 outScattering;
layout(location = 1) out vec4 outTransmittance;
-#define VOLUME_LIGHTING
-
void main()
{
- vec3 volume_tex_size = vec3(textureSize(volumeScattering, 0));
ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
/* Emission */
outScattering = texelFetch(volumeEmission, volume_cell, 0);
outTransmittance = texelFetch(volumeExtinction, volume_cell, 0);
vec3 s_scattering = texelFetch(volumeScattering, volume_cell, 0).rgb;
- vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volume_tex_size);
+ vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz);
vec3 worldPosition = get_world_space_from_depth(volume_ndc.xy, volume_ndc.z);
vec3 wdir = cameraVec;
@@ -45,7 +37,7 @@ void main()
outScattering.rgb += irradiance_volumetric(worldPosition) * s_scattering * phase_function_isotropic();
#ifdef VOLUME_LIGHTING /* Lights */
- for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) {
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
LightData ld = lights_data[i];
@@ -63,16 +55,16 @@ void main()
/* Temporal supersampling */
/* Note : this uses the cell non-jittered position (texel center). */
- vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) / volume_tex_size);
+ vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) * volInvTexSize.xyz);
vec3 wpos = get_world_space_from_depth(curr_ndc.xy, curr_ndc.z);
- vec3 prev_ndc = project_point(PastViewProjectionMatrix, wpos);
+ vec3 prev_ndc = project_point(pastViewProjectionMatrix, wpos);
vec3 prev_volume = ndc_to_volume(prev_ndc * 0.5 + 0.5);
- if ((volume_history_alpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) {
+ if ((volHistoryAlpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) {
vec4 h_Scattering = texture(historyScattering, prev_volume);
vec4 h_Transmittance = texture(historyTransmittance, prev_volume);
- outScattering = mix(outScattering, h_Scattering, volume_history_alpha);
- outTransmittance = mix(outTransmittance, h_Transmittance, volume_history_alpha);
+ outScattering = mix(outScattering, h_Scattering, volHistoryAlpha);
+ outTransmittance = mix(outTransmittance, h_Transmittance, volHistoryAlpha);
}
/* Catch NaNs */
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 851d0ef9eb7..ec0141953fe 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -218,6 +218,7 @@ DrawEngineType draw_engine_external_type = {
&external_draw_scene,
NULL,
NULL,
+ NULL,
};
/* Note: currently unused, we should not register unless we want to see this when debugging the view. */
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 0753dbc7a1a..528495b8710 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -139,6 +139,8 @@ typedef struct DrawEngineType {
void (*view_update)(void *vedata);
void (*id_update)(void *vedata, struct ID *id);
+
+ void (*render_to_image)(void *vedata, struct RenderEngine *engine, struct Depsgraph *graph);
} DrawEngineType;
#ifndef __DRW_ENGINE_H__
@@ -157,7 +159,9 @@ typedef struct DefaultTextureList {
#endif
/* Textures */
-
+/* NOTE naming in this struct is broken.
+ * There should either be suffixes for Normalized int formats or float formats.
+ * Right now every 8bit texture is Normalized int and others are Floating point. */
typedef enum {
DRW_TEX_RGBA_8,
DRW_TEX_RGBA_16,
@@ -168,6 +172,7 @@ typedef enum {
DRW_TEX_RGB_32,
DRW_TEX_RG_8,
DRW_TEX_RG_16,
+ DRW_TEX_RG_16I,
DRW_TEX_RG_32,
DRW_TEX_R_8,
DRW_TEX_R_16,
@@ -226,12 +231,14 @@ typedef struct DRWFboTexture {
DRWTextureFlag flag;
} DRWFboTexture;
+struct GPUFrameBuffer *DRW_framebuffer_create(void);
void DRW_framebuffer_init(
struct GPUFrameBuffer **fb, void *engine_type, int width, int height,
DRWFboTexture textures[MAX_FBO_TEX], int textures_len);
void DRW_framebuffer_bind(struct GPUFrameBuffer *fb);
void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth);
void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data);
+void DRW_framebuffer_read_depth(int x, int y, int w, int h, float *data);
void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip);
void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip);
void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip);
@@ -290,6 +297,7 @@ typedef enum {
DRW_STATE_MULTIPLY = (1 << 16),
DRW_STATE_TRANSMISSION = (1 << 17),
DRW_STATE_CLIP_PLANES = (1 << 18),
+ DRW_STATE_ADDITIVE_FULL = (1 << 19), /* Same as DRW_STATE_ADDITIVE but let alpha accumulate without premult. */
DRW_STATE_WRITE_STENCIL = (1 << 27),
DRW_STATE_STENCIL_EQUAL = (1 << 28),
@@ -326,10 +334,6 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at
const void *array[] = {__VA_ARGS__}; \
DRW_shgroup_call_dynamic_add_array(shgroup, array, (sizeof(array) / sizeof(*array))); \
} while (0)
-/* Use this only to make your instances selectable. */
-#define DRW_shgroup_call_dynamic_add_empty(shgroup) do { \
- DRW_shgroup_call_dynamic_add_array(shgroup, NULL, 0); \
-} while (0)
/* Use this to set a high number of instances. */
void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count);
@@ -341,13 +345,14 @@ void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int si
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex);
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo);
void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex);
-void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize);
void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize);
void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize);
+/* Boolean are expected to be 4bytes longs for opengl! */
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
@@ -356,6 +361,7 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
+void DRW_pass_state_set(DRWPass *pass, DRWState state);
void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData);
void DRW_pass_sort_shgroup_z(DRWPass *pass);
@@ -383,19 +389,29 @@ struct DefaultTextureList *DRW_viewport_texture_list_get(void);
void DRW_viewport_request_redraw(void);
+void DRW_render_to_image(struct RenderEngine *re, struct Depsgraph *depsgraph);
+void DRW_render_object_iter(
+ void *vedata, struct RenderEngine *engine, struct Depsgraph *graph,
+ void (*callback)(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *graph));
+
/* ViewLayers */
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage));
/* Objects */
-void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type);
-void **DRW_object_engine_data_ensure(
- Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage));
+ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type);
+ObjectEngineData *DRW_object_engine_data_ensure(
+ Object *ob,
+ DrawEngineType *engine_type,
+ size_t size,
+ ObjectEngineDataInitCb init_cb,
+ ObjectEngineDataFreeCb free_cb);
struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type);
void DRW_lamp_engine_data_free(struct LampEngineData *led);
/* Settings */
bool DRW_object_is_renderable(struct Object *ob);
+bool DRW_check_object_visible_within_active_context(struct Object *ob);
bool DRW_object_is_flat_normal(const struct Object *ob);
int DRW_object_is_mode_shade(const struct Object *ob);
@@ -431,6 +447,9 @@ bool DRW_state_is_image_render(void);
bool DRW_state_is_scene_render(void);
bool DRW_state_show_text(void);
bool DRW_state_draw_support(void);
+bool DRW_state_draw_background(void);
+
+enum eDepsObjectIteratorMode DRW_iterator_mode_get(void);
struct DRWTextStore *DRW_state_text_cache_get(void);
@@ -448,6 +467,8 @@ typedef struct DRWContextState {
struct RenderEngineType *engine_type;
+ struct Depsgraph *depsgraph;
+
/* Last resort (some functions take this as an arg so we can't easily avoid).
* May be NULL when used for selection or depth buffer. */
const struct bContext *evil_C;
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index c7a88f7689e..09fe3d68651 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -102,20 +102,22 @@ static void drw_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const
{
if (g_data.bone_octahedral_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_octahedral_get();
- g_data.bone_octahedral_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ g_data.bone_octahedral_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, final_bonemat, color);
}
static void drw_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_octahedral_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_octahedral_wire_outline_get();
- g_data.bone_octahedral_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_octahedral_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_wire, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_wire, final_bonemat, color);
}
/* Box / B-Bone */
@@ -123,20 +125,22 @@ static void drw_shgroup_bone_box_solid(const float (*bone_mat)[4], const float c
{
if (g_data.bone_box_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_box_get();
- g_data.bone_box_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ g_data.bone_box_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, final_bonemat, color);
}
static void drw_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_box_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_box_wire_outline_get();
- g_data.bone_box_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_box_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_box_wire, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_box_wire, final_bonemat, color);
}
/* Wire */
@@ -144,10 +148,11 @@ static void drw_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float c
{
if (g_data.bone_wire_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_wire_wire_outline_get();
- g_data.bone_wire_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_wire_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_wire_wire, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_wire_wire, final_bonemat, color);
}
/* Envelope */
@@ -159,10 +164,11 @@ static void drw_shgroup_bone_envelope_distance(
if (g_data.bone_envelope_distance == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_envelope_distance_outline_get();
/* Note: bone_wire draw pass is not really working, think we need another one here? */
- g_data.bone_envelope_distance = shgroup_instance_bone_envelope_wire(g_data.pass_bone_envelope, geom, g_data.ob->obmat);
+ g_data.bone_envelope_distance = shgroup_instance_bone_envelope_wire(g_data.pass_bone_envelope, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, bone_mat, color, radius_head, radius_tail, distance);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, final_bonemat, color, radius_head, radius_tail, distance);
}
}
@@ -172,10 +178,11 @@ static void drw_shgroup_bone_envelope_solid(
{
if (g_data.bone_envelope_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_envelope_solid_get();
- g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, bone_mat, color, radius_head, radius_tail);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, final_bonemat, color, radius_head, radius_tail);
}
static void drw_shgroup_bone_envelope_wire(
@@ -184,10 +191,11 @@ static void drw_shgroup_bone_envelope_wire(
{
if (g_data.bone_envelope_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_envelope_wire_outline_get();
- g_data.bone_envelope_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_envelope_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, bone_mat, color, radius_head, radius_tail, distance);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, final_bonemat, color, radius_head, radius_tail, distance);
}
static void drw_shgroup_bone_envelope_head_wire(
@@ -196,10 +204,11 @@ static void drw_shgroup_bone_envelope_head_wire(
{
if (g_data.bone_envelope_head_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_envelope_head_wire_outline_get();
- g_data.bone_envelope_head_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_envelope_head_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_envelope_head_wire, bone_mat, color, radius_head, radius_tail, distance);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_head_wire, final_bonemat, color, radius_head, radius_tail, distance);
}
/* Custom (geometry) */
@@ -209,8 +218,10 @@ static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], const floa
/* grr, not re-using instances! */
struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom);
if (geom) {
- DRWShadingGroup *shgrp_geom_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
- DRW_shgroup_call_dynamic_add(shgrp_geom_solid, bone_mat, color);
+ DRWShadingGroup *shgrp_geom_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, color);
}
}
@@ -219,8 +230,10 @@ static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float
/* grr, not re-using instances! */
struct Gwn_Batch *geom = DRW_cache_object_wire_outline_get(custom);
if (geom) {
- DRWShadingGroup *shgrp_geom_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
- DRW_shgroup_call_dynamic_add(shgrp_geom_wire, bone_mat, color);
+ DRWShadingGroup *shgrp_geom_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, color);
}
}
@@ -229,20 +242,22 @@ static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float
{
if (g_data.bone_point_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_point_get();
- g_data.bone_point_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ g_data.bone_point_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, final_bonemat, color);
}
static void drw_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_point_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_point_wire_outline_get();
- g_data.bone_point_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_point_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, final_bonemat, color);
}
/* Axes */
@@ -250,10 +265,11 @@ static void drw_shgroup_bone_axes(const float (*bone_mat)[4], const float color[
{
if (g_data.bone_axes == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_arrows_get();
- g_data.bone_axes = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ g_data.bone_axes = shgroup_instance_wire(g_data.pass_bone_wire, geom);
}
-
- DRW_shgroup_call_dynamic_add(g_data.bone_axes, bone_mat, color);
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_axes, final_bonemat, color);
}
/* Relationship lines */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 8010a232f89..3b4180c0375 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -65,6 +65,7 @@ static struct DRWShapeCache {
Gwn_Batch *drw_field_tube_limit;
Gwn_Batch *drw_field_cone_limit;
Gwn_Batch *drw_lamp;
+ Gwn_Batch *drw_lamp_shadows;
Gwn_Batch *drw_lamp_sunrays;
Gwn_Batch *drw_lamp_area;
Gwn_Batch *drw_lamp_hemi;
@@ -87,6 +88,7 @@ static struct DRWShapeCache {
Gwn_Batch *drw_bone_point_wire;
Gwn_Batch *drw_bone_arrows;
Gwn_Batch *drw_camera;
+ Gwn_Batch *drw_camera_frame;
Gwn_Batch *drw_camera_tria;
Gwn_Batch *drw_camera_focus;
Gwn_Batch *drw_particle_cross;
@@ -520,6 +522,12 @@ Gwn_Batch **DRW_cache_object_surface_material_get(
switch (ob->type) {
case OB_MESH:
return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ case OB_CURVE:
+ return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ case OB_SURF:
+ return DRW_cache_surf_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ case OB_FONT:
+ return DRW_cache_text_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
default:
return NULL;
}
@@ -1007,14 +1015,14 @@ Gwn_Batch *DRW_cache_lamp_get(void)
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
- for (int a = 0; a < NSEGMENTS; a++) {
- v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS));
- v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS));
- GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v);
+ for (int a = 0; a < NSEGMENTS * 2; a += 2) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
- v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS));
- v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS));
- GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v);
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
}
SHC.drw_lamp = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
@@ -1023,12 +1031,44 @@ Gwn_Batch *DRW_cache_lamp_get(void)
#undef NSEGMENTS
}
+Gwn_Batch *DRW_cache_lamp_shadows_get(void)
+{
+#define NSEGMENTS 10
+ if (!SHC.drw_lamp_shadows) {
+ float v[2];
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
+
+ for (int a = 0; a < NSEGMENTS * 2; a += 2) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
+ }
+
+ SHC.drw_lamp_shadows = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_shadows;
+#undef NSEGMENTS
+}
+
Gwn_Batch *DRW_cache_lamp_sunrays_get(void)
{
if (!SHC.drw_lamp_sunrays) {
float v[2], v1[2], v2[2];
- /* Position Only 3D format */
+ /* Position Only 2D format */
static Gwn_VertFormat format = { 0 };
static struct { uint pos; } attr_id;
if (format.attrib_ct == 0) {
@@ -1036,17 +1076,21 @@ Gwn_Batch *DRW_cache_lamp_sunrays_get(void)
}
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
- GWN_vertbuf_data_alloc(vbo, 16);
+ GWN_vertbuf_data_alloc(vbo, 32);
for (int a = 0; a < 8; a++) {
v[0] = sinf((2.0f * M_PI * a) / 8.0f);
v[1] = cosf((2.0f * M_PI * a) / 8.0f);
- mul_v2_v2fl(v1, v, 1.2f);
- mul_v2_v2fl(v2, v, 2.5f);
+ mul_v2_v2fl(v1, v, 1.6f);
+ mul_v2_v2fl(v2, v, 1.9f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v1);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v2);
+ mul_v2_v2fl(v1, v, 2.2f);
+ mul_v2_v2fl(v2, v, 2.5f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2);
}
SHC.drw_lamp_sunrays = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
@@ -1846,7 +1890,7 @@ Gwn_Batch *DRW_cache_bone_envelope_distance_outline_get(void)
const float x = cosf(alpha);
const float y = -sinf(alpha);
- /* { X, Y, head/tail, inner/outer border } */
+ /* { X, Y, head/tail, inner/outer border } */
GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 0.0f});
GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 1.0f});
if (is_headtail_transition) {
@@ -1880,7 +1924,7 @@ Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void)
/* Two lines between head and tail circles. */
/* Encoded lines, vertex shader gives them final correct value. */
- /* { X, Y, head/tail, inner/outer border } */
+ /* { X, Y, head/tail, inner/outer border } */
GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 0.0f, 0.0f});
GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 1.0f, 0.0f});
GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 0.0f, 0.0f});
@@ -1916,7 +1960,7 @@ Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void)
const float x = cosf(alpha);
const float y = -sinf(alpha);
- /* { X, Y, head/tail, inner/outer border } */
+ /* { X, Y, head/tail, inner/outer border } */
GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ x, y, 0.0f, 0.0f});
}
@@ -1996,97 +2040,139 @@ Gwn_Batch *DRW_cache_bone_arrows_get(void)
/** \name Camera
* \{ */
+/**
+ * We could make these more generic functions.
+ * although filling 1d lines is not common.
+ *
+ * \note Use x coordinate to identify the vertex the vertex shader take care to place it appropriately.
+ */
+
+static const float camera_coords_frame_bounds[5] = {
+ 0.0f, /* center point */
+ 1.0f, /* + X + Y */
+ 2.0f, /* + X - Y */
+ 3.0f, /* - X - Y */
+ 4.0f, /* - X + Y */
+};
+
+static const float camera_coords_frame_tri[3] = {
+ 5.0f, /* tria + X */
+ 6.0f, /* tria - X */
+ 7.0f, /* tria + Y */
+};
+
+/** Draw a loop of lines. */
+static void camera_fill_lines_loop_fl_v1(
+ Gwn_VertBufRaw *pos_step,
+ const float *coords, const uint coords_len)
+{
+ for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) {
+ *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i_prev];
+ *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i];
+ }
+}
+
+/** Fan lines out from the first vertex. */
+static void camera_fill_lines_fan_fl_v1(
+ Gwn_VertBufRaw *pos_step,
+ const float *coords, const uint coords_len)
+{
+ for (uint i = 1; i < coords_len; i++) {
+ *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[0];
+ *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i];
+ }
+}
+
+/** Simply fill the array. */
+static void camera_fill_array_fl_v1(
+ Gwn_VertBufRaw *pos_step,
+ const float *coords, const uint coords_len)
+{
+ for (uint i = 0; i < coords_len; i++) {
+ *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i];
+ }
+}
+
+
Gwn_Batch *DRW_cache_camera_get(void)
{
if (!SHC.drw_camera) {
- float v0 = 0.0f; /* Center point */
- float v1 = 1.0f; /* + X + Y */
- float v2 = 2.0f; /* + X - Y */
- float v3 = 3.0f; /* - X - Y */
- float v4 = 4.0f; /* - X + Y */
- float v5 = 5.0f; /* tria + X */
- float v6 = 6.0f; /* tria - X */
- float v7 = 7.0f; /* tria + Y */
- int v_idx = 0;
-
static Gwn_VertFormat format = { 0 };
static struct { uint pos; } attr_id;
if (format.attrib_ct == 0) {
- /* use x coordinate to identify the vertex
- * the vertex shader take care to place it
- * appropriatelly */
attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
}
/* Vertices */
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
- GWN_vertbuf_data_alloc(vbo, 22);
-
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1);
+ const int vbo_len_capacity = 22;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ Gwn_VertBufRaw pos_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2);
+ /* camera cone (from center to frame) */
+ camera_fill_lines_fan_fl_v1(&pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds));
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3);
+ /* camera frame (skip center) */
+ camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4);
+ /* camera triangle (above the frame) */
+ camera_fill_lines_loop_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
- /* camera frame */
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2);
+ BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3);
+ SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_camera;
+}
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4);
+Gwn_Batch *DRW_cache_camera_frame_get(void)
+{
+ if (!SHC.drw_camera_frame) {
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1);
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ }
- /* tria */
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6);
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = 8;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ Gwn_VertBufRaw pos_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7);
+ /* camera frame (skip center) */
+ camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5);
+ BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
- SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ SHC.drw_camera_frame = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
}
- return SHC.drw_camera;
+ return SHC.drw_camera_frame;
}
Gwn_Batch *DRW_cache_camera_tria_get(void)
{
if (!SHC.drw_camera_tria) {
- float v5 = 5.0f; /* tria + X */
- float v6 = 6.0f; /* tria - X */
- float v7 = 7.0f; /* tria + Y */
- int v_idx = 0;
-
static Gwn_VertFormat format = { 0 };
static struct { uint pos; } attr_id;
if (format.attrib_ct == 0) {
- /* use x coordinate to identify the vertex
- * the vertex shader take care to place it
- * appropriatelly */
attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
}
/* Vertices */
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
- GWN_vertbuf_data_alloc(vbo, 6);
+ const int vbo_len_capacity = 3;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ Gwn_VertBufRaw pos_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ /* camera triangle (above the frame) */
+ camera_fill_array_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
- /* tria */
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6);
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7);
+ BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
SHC.drw_camera_tria = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
}
@@ -2334,6 +2420,16 @@ Gwn_Batch *DRW_cache_curve_surface_get(Object *ob)
return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache);
}
+/* Return list of batches */
+Gwn_Batch **DRW_cache_curve_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2372,6 +2468,17 @@ Gwn_Batch *DRW_cache_text_surface_get(Object *ob)
return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache);
}
+Gwn_Batch **DRW_cache_text_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_FONT);
+ struct Curve *cu = ob->data;
+ if (cu->editfont && (cu->flag & CU_FAST)) {
+ return NULL;
+ }
+ return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len);
+}
+
Gwn_Batch *DRW_cache_text_cursor_overlay_get(Object *ob)
{
BLI_assert(ob->type == OB_FONT);
@@ -2401,6 +2508,16 @@ Gwn_Batch *DRW_cache_surf_surface_get(Object *ob)
return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache);
}
+/* Return list of batches */
+Gwn_Batch **DRW_cache_surf_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_SURF);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 35ac8f4a35d..c039bb8883d 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -70,6 +70,7 @@ struct Gwn_Batch *DRW_cache_field_cone_limit_get(void);
/* Lamps */
struct Gwn_Batch *DRW_cache_lamp_get(void);
+struct Gwn_Batch *DRW_cache_lamp_shadows_get(void);
struct Gwn_Batch *DRW_cache_lamp_sunrays_get(void);
struct Gwn_Batch *DRW_cache_lamp_area_get(void);
struct Gwn_Batch *DRW_cache_lamp_hemi_get(void);
@@ -78,6 +79,7 @@ struct Gwn_Batch *DRW_cache_lamp_spot_square_get(void);
/* Camera */
struct Gwn_Batch *DRW_cache_camera_get(void);
+struct Gwn_Batch *DRW_cache_camera_frame_get(void);
struct Gwn_Batch *DRW_cache_camera_tria_get(void);
/* Speaker */
@@ -130,6 +132,8 @@ void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob);
/* Curve */
struct Gwn_Batch *DRW_cache_curve_surface_get(struct Object *ob);
+struct Gwn_Batch **DRW_cache_curve_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
struct Gwn_Batch *DRW_cache_curve_surface_verts_get(struct Object *ob);
struct Gwn_Batch *DRW_cache_curve_edge_wire_get(struct Object *ob);
/* edit-mode */
@@ -140,12 +144,16 @@ struct Gwn_Batch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
/* Font */
struct Gwn_Batch *DRW_cache_text_edge_wire_get(struct Object *ob);
struct Gwn_Batch *DRW_cache_text_surface_get(struct Object *ob);
+struct Gwn_Batch **DRW_cache_text_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
/* edit-mode */
struct Gwn_Batch *DRW_cache_text_cursor_overlay_get(struct Object *ob);
struct Gwn_Batch *DRW_cache_text_select_overlay_get(struct Object *ob);
/* Surface */
struct Gwn_Batch *DRW_cache_surf_surface_get(struct Object *ob);
+struct Gwn_Batch **DRW_cache_surf_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
/* Lattice */
struct Gwn_Batch *DRW_cache_lattice_verts_get(struct Object *ob);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index c998282ae1f..0b18f3a257f 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -29,14 +29,16 @@
struct CurveCache;
struct GPUMaterial;
struct Gwn_Batch;
+struct Gwn_IndexBuf;
+struct Gwn_VertBuf;
struct ListBase;
-struct MetaBall;
struct ModifierData;
struct ParticleSystem;
struct Curve;
struct Lattice;
struct Mesh;
+struct MetaBall;
/* Expose via BKE callbacks */
void DRW_mball_batch_cache_dirty(struct MetaBall *mb, int mode);
@@ -62,6 +64,9 @@ struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_edges(struct Curve *cu);
struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_verts(struct Curve *cu);
struct Gwn_Batch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu, struct CurveCache *ob_curve_cache);
+struct Gwn_Batch **DRW_curve_batch_cache_get_surface_shaded(
+ struct Curve *cu, struct CurveCache *ob_curve_cache,
+ struct GPUMaterial **gpumat_array, uint gpumat_array_len);
/* Metaball */
struct Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
@@ -71,7 +76,12 @@ struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu);
struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_select(struct Curve *cu);
/* DispList */
-struct Gwn_Batch *BLI_displist_batch_calc_surface(struct ListBase *lb);
+struct Gwn_VertBuf *DRW_displist_vertbuf_calc_pos_with_normals(struct ListBase *lb);
+struct Gwn_IndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(struct ListBase *lb);
+struct Gwn_IndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
+ struct ListBase *lb, uint gpumat_array_len);
+struct Gwn_Batch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
+ struct ListBase *lb, uint gpumat_array_len);
/* Lattice */
struct Gwn_Batch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt, bool use_weight, const int actdef);
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c
index e6e52fe4579..3939ea062e9 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.c
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -40,9 +40,22 @@
#include "GPU_batch.h"
+#include "UI_resources.h"
+
#include "draw_cache_impl.h" /* own include */
-#define SELECT 1
+#define SELECT 1
+#define ACTIVE_NURB 1 << 7 /* last char bite */
+#define HANDLE_SEL_OFFSET (TH_HANDLE_SEL_FREE - TH_HANDLE_FREE)
+
+/* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
+enum {
+ COLOR_NURB_ULINE_ID = TH_HANDLE_SEL_AUTOCLAMP - TH_HANDLE_FREE + 1,
+ COLOR_NURB_SEL_ULINE_ID,
+ COLOR_ACTIVE_SPLINE,
+
+ TOT_HANDLE_COL,
+};
/**
* TODO
@@ -126,7 +139,8 @@ static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_
nr -= skip;
}
#else
- normal_len += max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0);
+ /* Same as loop above */
+ normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0);
#endif
}
return normal_len;
@@ -310,7 +324,11 @@ typedef struct CurveBatchCache {
} overlay;
struct {
+ Gwn_VertBuf *verts;
+ Gwn_IndexBuf *triangles_in_order;
+ Gwn_Batch **shaded_triangles;
Gwn_Batch *batch;
+ int mat_len;
} surface;
/* 3d text */
@@ -340,6 +358,10 @@ static bool curve_batch_cache_valid(Curve *cu)
return false;
}
+ if (cache->is_dirty) {
+ return false;
+ }
+
if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
return false;
}
@@ -358,16 +380,6 @@ static bool curve_batch_cache_valid(Curve *cu)
}
}
- if (cache->is_dirty == false) {
- return true;
- }
- else {
- /* TODO: check number of vertices/edges? */
- if (cache->is_editmode) {
- return false;
- }
- }
-
return true;
}
@@ -444,6 +456,14 @@ static void curve_batch_cache_clear(Curve *cu)
GWN_BATCH_DISCARD_SAFE(cache->overlay.verts);
GWN_BATCH_DISCARD_SAFE(cache->overlay.edges);
+ GWN_VERTBUF_DISCARD_SAFE(cache->surface.verts);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->surface.triangles_in_order);
+ if (cache->surface.shaded_triangles) {
+ for (int i = 0; i < cache->surface.mat_len; ++i) {
+ GWN_BATCH_DISCARD_SAFE(cache->surface.shaded_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->surface.shaded_triangles);
GWN_BATCH_DISCARD_SAFE(cache->surface.batch);
/* don't own vbo & elems */
@@ -735,47 +755,50 @@ static void curve_batch_cache_create_overlay_batches(Curve *cu)
int vbo_len_used = 0;
GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
int i = 0;
- for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next) {
+ for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) {
+ const bool is_active_nurb = (i == cu->actnu);
+
if (nu->bezt) {
int a = 0;
for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == false) {
- const bool is_active = (i == rdata->actvert);
- char vflag;
-
- vflag = (bezt->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
- GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[0]);
- GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
- vbo_len_used += 1;
+ char col_id;
- /* same vertex twice, only check different selection */
- for (int j = 0; j < 2; j++) {
- vflag = ((j ? bezt->f3 : bezt->f1) & SELECT) ?
- (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ for (int j = 0; j < 2; j += 1) {
+ /* same vertex twice, only check different selection */
GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
- GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
vbo_len_used += 1;
- }
- vflag = (bezt->f3 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
- GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[2]);
- GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
- vbo_len_used += 1;
+ col_id = (&bezt->h1)[j];
+ if ((&bezt->f1)[j * 2] & SELECT) {
+ col_id += HANDLE_SEL_OFFSET;
+ }
+ if (is_active_nurb) {
+ col_id |= ACTIVE_NURB;
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j * 2]);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
+ vbo_len_used += 1;
+ }
}
- i += 1;
}
}
else if (nu->bp) {
int a = 1;
for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) {
if ((bp_prev->hide == false) && (bp_curr->hide == false)) {
- char vflag;
- vflag = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? VFLAG_VERTEX_SELECTED : 0;
+ char col_id = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? COLOR_NURB_SEL_ULINE_ID : COLOR_NURB_ULINE_ID;
+
+ if (is_active_nurb) {
+ col_id |= ACTIVE_NURB;
+ }
+
GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_prev->vec);
- GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
vbo_len_used += 1;
+
GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_curr->vec);
- GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
vbo_len_used += 1;
}
@@ -796,8 +819,18 @@ static Gwn_Batch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata,
{
BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
if (cache->surface.batch == NULL) {
- cache->surface.batch = BLI_displist_batch_calc_surface(&rdata->ob_curve_cache->disp);
+ ListBase *lb = &rdata->ob_curve_cache->disp;
+
+ if (cache->surface.verts == NULL) {
+ cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
+ }
+ if (cache->surface.triangles_in_order == NULL) {
+ cache->surface.triangles_in_order = DRW_displist_indexbuf_calc_triangles_in_order(lb);
+ }
+ cache->surface.batch = GWN_batch_create(
+ GWN_PRIM_TRIS, cache->surface.verts, cache->surface.triangles_in_order);
}
+
return cache->surface.batch;
}
@@ -997,6 +1030,55 @@ Gwn_Batch *DRW_curve_batch_cache_get_triangles_with_normals(
return cache->surface.batch;
}
+Gwn_Batch **DRW_curve_batch_cache_get_surface_shaded(
+ struct Curve *cu, struct CurveCache *ob_curve_cache,
+ struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->surface.mat_len != gpumat_array_len) {
+ /* TODO: deduplicate code */
+ if (cache->surface.shaded_triangles) {
+ for (int i = 0; i < cache->surface.mat_len; ++i) {
+ GWN_BATCH_DISCARD_SAFE(cache->surface.shaded_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->surface.shaded_triangles);
+ }
+
+ if (cache->surface.shaded_triangles == NULL) {
+ CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
+ ListBase *lb = &rdata->ob_curve_cache->disp;
+
+ cache->surface.mat_len = gpumat_array_len;
+ if (cu->flag & CU_UV_ORCO) {
+ cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
+ lb, gpumat_array_len);
+ }
+ else {
+ cache->surface.shaded_triangles = MEM_mallocN(
+ sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__);
+ Gwn_IndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
+ lb, gpumat_array_len);
+
+ if (cache->surface.verts == NULL) {
+ cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
+ }
+
+ for (int i = 0; i < gpumat_array_len; ++i) {
+ cache->surface.shaded_triangles[i] = GWN_batch_create_ex(
+ GWN_PRIM_TRIS, cache->surface.verts, el[i], GWN_BATCH_OWNS_INDEX);
+ }
+
+ MEM_freeN(el); /* Save `el` in cache? */
+ }
+
+ curve_render_data_free(rdata);
+ }
+
+ return cache->surface.shaded_triangles;
+}
+
/* -------------------------------------------------------------------- */
@@ -1033,4 +1115,4 @@ Gwn_Batch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu)
return cache->text.cursor;
}
-/** \} */ \ No newline at end of file
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
index 96386f82faf..627fb38d9d6 100644
--- a/source/blender/draw/intern/draw_cache_impl_displist.c
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_alloca.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
@@ -86,13 +87,39 @@ static int curve_render_surface_tri_len_get(const ListBase *lb)
return tri_len;
}
-Gwn_Batch *BLI_displist_batch_calc_surface(ListBase *lb)
+static void displist_indexbufbuilder_set(Gwn_IndexBufBuilder *elb, const DispList *dl, const int ofs)
{
- const int tri_len = curve_render_surface_tri_len_get(lb);
- if (tri_len == 0) {
- return NULL;
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ const int *idx = dl->index;
+ if (dl->type == DL_INDEX3) {
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 3) {
+ GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ const int i_end = dl->totindex;
+ for (int i = 0; i < i_end; i++, idx += 4) {
+ GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
+ GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[3] + ofs, idx[2] + ofs);
+ }
+ }
+ else {
+ BLI_assert(dl->type == DL_INDEX4);
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 4) {
+ GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
+
+ if (idx[2] != idx[3]) {
+ GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+ }
+ }
+ }
}
+}
+Gwn_VertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb)
+{
static Gwn_VertFormat format = { 0 };
static struct { uint pos, nor; } attr_id;
if (format.attrib_ct == 0) {
@@ -101,74 +128,271 @@ Gwn_Batch *BLI_displist_batch_calc_surface(ListBase *lb)
attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
}
- const int vert_len = curve_render_surface_vert_len_get(lb);
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
- {
- const int vbo_len_capacity = vert_len;
- int vbo_len_used = 0;
- GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
-
- BKE_displist_normals_add(lb);
-
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
- const bool ndata_is_single = dl->type == DL_INDEX3;
- if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
- const float *fp_co = dl->verts;
- const float *fp_no = dl->nors;
- const int vbo_end = vbo_len_used + dl_vert_len(dl);
- while (vbo_len_used < vbo_end) {
- GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co);
- if (fp_no) {
- GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no);
- if (ndata_is_single == false) {
- fp_no += 3;
- }
+ GWN_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb));
+
+ BKE_displist_normals_add(lb);
+
+ int vbo_len_used = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ const bool ndata_is_single = dl->type == DL_INDEX3;
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ const float *fp_co = dl->verts;
+ const float *fp_no = dl->nors;
+ const int vbo_end = vbo_len_used + dl_vert_len(dl);
+ while (vbo_len_used < vbo_end) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co);
+ if (fp_no) {
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no);
+ if (ndata_is_single == false) {
+ fp_no += 3;
}
- fp_co += 3;
- vbo_len_used += 1;
}
+ fp_co += 3;
+ vbo_len_used += 1;
}
}
}
- {
- Gwn_IndexBufBuilder elb;
- GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len);
+ return vbo;
+}
- int ofs = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
- if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
- const int *idx = dl->index;
- if (dl->type == DL_INDEX3) {
- const int i_end = dl->parts;
- for (int i = 0; i < i_end; i++, idx += 3) {
- GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
- }
+Gwn_IndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb)
+{
+ const int tri_len = curve_render_surface_tri_len_get(lb);
+ const int vert_len = curve_render_surface_vert_len_get(lb);
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len);
+
+ int ofs = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ displist_indexbufbuilder_set(&elb, dl, ofs);
+ ofs += dl_vert_len(dl);
+ }
+
+ return GWN_indexbuf_build(&elb);
+}
+
+Gwn_IndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(ListBase *lb, uint gpumat_array_len)
+{
+ Gwn_IndexBuf **shaded_triangles_in_order = MEM_callocN(sizeof(*shaded_triangles_in_order) * gpumat_array_len, __func__);
+ Gwn_IndexBufBuilder *elb = BLI_array_alloca(elb, gpumat_array_len);
+
+ const int tri_len = curve_render_surface_tri_len_get(lb);
+ const int vert_len = curve_render_surface_vert_len_get(lb);
+ int i;
+
+ /* Init each index buffer builder */
+ for (i = 0; i < gpumat_array_len; i++) {
+ GWN_indexbuf_init(&elb[i], GWN_PRIM_TRIS, tri_len, vert_len);
+ }
+
+ /* calc each index buffer builder */
+ int ofs = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ displist_indexbufbuilder_set(&elb[dl->col], dl, ofs);
+ ofs += dl_vert_len(dl);
+ }
+
+ /* build each indexbuf */
+ for (i = 0; i < gpumat_array_len; i++) {
+ shaded_triangles_in_order[i] = GWN_indexbuf_build(&elb[i]);
+ }
+
+ return shaded_triangles_in_order;
+}
+
+static void displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ Gwn_VertBufRaw *pos_step, Gwn_VertBufRaw *nor_step, Gwn_VertBufRaw *uv_step,
+ const float v1[3], const float v2[3], const float v3[3],
+ const float n1[3], const float n2[3], const float n3[3],
+ const float uv1[2], const float uv2[2], const float uv3[2])
+{
+ copy_v3_v3(GWN_vertbuf_raw_step(pos_step), v1);
+ copy_v3_v3(GWN_vertbuf_raw_step(nor_step), n1);
+ copy_v2_v2(GWN_vertbuf_raw_step(uv_step), uv1);
+
+ copy_v3_v3(GWN_vertbuf_raw_step(pos_step), v2);
+ copy_v3_v3(GWN_vertbuf_raw_step(nor_step), n2);
+ copy_v2_v2(GWN_vertbuf_raw_step(uv_step), uv2);
+
+ copy_v3_v3(GWN_vertbuf_raw_step(pos_step), v3);
+ copy_v3_v3(GWN_vertbuf_raw_step(nor_step), n3);
+ copy_v2_v2(GWN_vertbuf_raw_step(uv_step), uv3);
+}
+
+Gwn_Batch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(ListBase *lb, uint gpumat_array_len)
+{
+ static Gwn_VertFormat shaded_triangles_format = { 0 };
+ static struct { uint pos, nor, uv; } attr_id;
+
+ if (shaded_triangles_format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&shaded_triangles_format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&shaded_triangles_format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.uv = GWN_vertformat_attr_add(&shaded_triangles_format, "u", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_Batch **shaded_triangles = MEM_mallocN(sizeof(*shaded_triangles) * gpumat_array_len, __func__);
+
+ Gwn_VertBuf **vbo = BLI_array_alloca(vbo, gpumat_array_len);
+ uint *vbo_len_capacity = BLI_array_alloca(vbo_len_capacity, gpumat_array_len);
+
+ Gwn_VertBufRaw *pos_step, *nor_step, *uv_step;
+ pos_step = BLI_array_alloca(pos_step, gpumat_array_len);
+ nor_step = BLI_array_alloca(nor_step, gpumat_array_len);
+ uv_step = BLI_array_alloca(uv_step, gpumat_array_len);
+
+ /* Create each vertex buffer */
+ for (int i = 0; i < gpumat_array_len; i++) {
+ vbo[i] = GWN_vertbuf_create_with_format(&shaded_triangles_format);
+ vbo_len_capacity[i] = 0;
+ }
+
+ /* Calc `vbo_len_capacity` */
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ vbo_len_capacity[dl->col] += dl_tri_len(dl) * 3;
+ }
+
+ /* Alloc each vertex buffer and get each raw data */
+ for (int i = 0; i < gpumat_array_len; i++) {
+ GWN_vertbuf_data_alloc(vbo[i], vbo_len_capacity[i]);
+ GWN_vertbuf_attr_get_raw_data(vbo[i], attr_id.pos, &pos_step[i]);
+ GWN_vertbuf_attr_get_raw_data(vbo[i], attr_id.nor, &nor_step[i]);
+ GWN_vertbuf_attr_get_raw_data(vbo[i], attr_id.uv, &uv_step[i]);
+ }
+
+ BKE_displist_normals_add(lb);
+
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ const int col = dl->col;
+ const float(*verts)[3] = (float(*)[3])dl->verts;
+ const float(*nors)[3] = (float(*)[3])dl->nors;
+ const int *idx = dl->index;
+ float uv[4][2];
+
+ if (dl->type == DL_INDEX3) {
+ const float x_max = (float)(dl->nr - 1);
+ uv[0][1] = uv[1][1] = uv[2][1] = 0.0f;
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 3) {
+ uv[0][0] = idx[0] / x_max;
+ uv[1][0] = idx[2] / x_max;
+ uv[2][0] = idx[1] / x_max;
+
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[idx[0]], verts[idx[2]], verts[idx[1]],
+ nors[idx[0]], nors[idx[2]], nors[idx[1]],
+ uv[0], uv[1], uv[2]);
}
- else if (dl->type == DL_SURF) {
- const int i_end = dl->totindex;
- for (int i = 0; i < i_end; i++, idx += 4) {
- GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
- GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+ }
+ else if (dl->type == DL_SURF) {
+ uint quad[4];
+ for (int a = 0; a < dl->parts; a++) {
+ if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
+ break;
}
- }
- else {
- BLI_assert(dl->type == DL_INDEX4);
- const int i_end = dl->parts;
- for (int i = 0; i < i_end; i++, idx += 4) {
- GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
-
- if (idx[2] != idx[3]) {
- GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+
+ int b;
+ if (dl->flag & DL_CYCL_U) {
+ quad[0] = dl->nr * a;
+ quad[3] = quad[0] + dl->nr - 1;
+ quad[1] = quad[0] + dl->nr;
+ quad[2] = quad[3] + dl->nr;
+ b = 0;
+ }
+ else {
+ quad[3] = dl->nr * a;
+ quad[0] = quad[3] + 1;
+ quad[2] = quad[3] + dl->nr;
+ quad[1] = quad[0] + dl->nr;
+ b = 1;
+ }
+ if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
+ quad[1] -= dl->parts * dl->nr;
+ quad[2] -= dl->parts * dl->nr;
+ }
+
+ for (; b < dl->nr; b++) {
+ int orco_sizeu = dl->nr - 1;
+ int orco_sizev = dl->parts - 1;
+
+ /* exception as handled in convertblender.c too */
+ if (dl->flag & DL_CYCL_U) {
+ orco_sizeu++;
+ }
+ if (dl->flag & DL_CYCL_V) {
+ orco_sizev++;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ /* find uv based on vertex index into grid array */
+ uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev;
+ uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu;
+
+ /* cyclic correction */
+ if ((i == 1 || i == 2) && uv[i][0] == 0.0f) {
+ uv[i][0] = 1.0f;
+ }
+ if ((i == 0 || i == 1) && uv[i][1] == 0.0f) {
+ uv[i][1] = 1.0f;
+ }
}
+
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[quad[0]], verts[quad[1]], verts[quad[2]],
+ nors[quad[0]], nors[quad[1]], nors[quad[2]],
+ uv[0], uv[1], uv[2]);
+
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[quad[0]], verts[quad[2]], verts[quad[3]],
+ nors[quad[0]], nors[quad[2]], nors[quad[3]],
+ uv[0], uv[2], uv[3]);
+
+ quad[2] = quad[1];
+ quad[1]++;
+ quad[3] = quad[0];
+ quad[0]++;
+ }
+ }
+ }
+ else {
+ BLI_assert(dl->type == DL_INDEX4);
+ uv[0][0] = uv[0][1] = uv[1][0] = uv[3][1] = 0.0f;
+ uv[1][1] = uv[2][0] = uv[2][1] = uv[3][0] = 1.0f;
+
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 4) {
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[idx[0]], verts[idx[1]], verts[idx[2]],
+ nors[idx[0]], nors[idx[1]], nors[idx[2]],
+ uv[0], uv[1], uv[2]);
+
+ if (idx[2] != idx[3]) {
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[idx[0]], verts[idx[2]], verts[idx[3]],
+ nors[idx[0]], nors[idx[2]], nors[idx[3]],
+ uv[0], uv[2], uv[3]);
}
}
- ofs += dl_vert_len(dl);
}
}
+ }
- return GWN_batch_create_ex(
- GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb),
- GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
+ for (int i = 0; i < gpumat_array_len; i++) {
+ uint vbo_len_used = GWN_vertbuf_raw_used(&pos_step[i]);
+ if (vbo_len_capacity[i] != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo[i], vbo_len_used);
+ }
+ shaded_triangles[i] = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo[i], NULL, GWN_BATCH_OWNS_VBO);
}
+
+ return shaded_triangles;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c
index 20698fe6592..eed408de3cd 100644
--- a/source/blender/draw/intern/draw_cache_impl_lattice.c
+++ b/source/blender/draw/intern/draw_cache_impl_lattice.c
@@ -41,7 +41,7 @@
#include "BKE_lattice.h"
#include "BKE_deform.h"
-#include "BKE_texture.h"
+#include "BKE_colorband.h"
#include "GPU_batch.h"
@@ -260,7 +260,7 @@ static void lattice_render_data_weight_col_get(const LatticeRenderData *rdata, c
float weight = defvert_find_weight(rdata->dvert + vert_idx, actdef);
if (U.flag & USER_CUSTOM_RANGE) {
- do_colorband(&U.coba_weight, weight, r_col);
+ BKE_colorband_evaluate(&U.coba_weight, weight, r_col);
}
else {
rgb_from_weight(r_col, weight);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 8cd0c13faec..b44c5b8a20b 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -48,7 +48,7 @@
#include "BKE_editmesh_tangent.h"
#include "BKE_mesh.h"
#include "BKE_mesh_tangent.h"
-#include "BKE_texture.h"
+#include "BKE_colorband.h"
#include "bmesh.h"
@@ -1097,7 +1097,7 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con
const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
float weight = defvert_find_weight(dvert, defgroup);
if (U.flag & USER_CUSTOM_RANGE) {
- do_colorband(&U.coba_weight, weight, vweight[i]);
+ BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]);
}
else {
rgb_from_weight(vweight[i], weight);
@@ -1113,7 +1113,7 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con
for (int i = 0; i < rdata->vert_len; i++) {
float weight = defvert_find_weight(&rdata->dvert[i], defgroup);
if (U.flag & USER_CUSTOM_RANGE) {
- do_colorband(&U.coba_weight, weight, vweight[i]);
+ BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]);
}
else {
rgb_from_weight(vweight[i], weight);
@@ -2167,11 +2167,10 @@ static Gwn_VertBuf *mesh_batch_cache_get_facedot_pos_with_normals_and_flag(
}
}
const int vbo_len_used = vidx;
+ BLI_assert(vbo_len_used <= vbo_len_capacity);
if (vbo_len_used != vbo_len_capacity) {
GWN_vertbuf_data_resize(vbo, vbo_len_used);
}
- BLI_assert(vbo_len_capacity == vbo_len_used);
- UNUSED_VARS_NDEBUG(vbo_len_used);
}
return cache->ed_fcenter_pos_with_nor_and_sel;
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index e2dba8e626e..f01e7b929f8 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -132,7 +132,12 @@ Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
if (cache->batch == NULL) {
- cache->batch = BLI_displist_batch_calc_surface(&ob->curve_cache->disp);
+ ListBase *lb = &ob->curve_cache->disp;
+ cache->batch = GWN_batch_create_ex(
+ GWN_PRIM_TRIS,
+ DRW_displist_vertbuf_calc_pos_with_normals(lb),
+ DRW_displist_indexbuf_calc_triangles_in_order(lb),
+ GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
}
return cache->batch;
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index b52c8e280b3..0eb97a54ba5 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -31,7 +31,7 @@
#include "UI_resources.h"
#include "BKE_global.h"
-#include "BKE_texture.h"
+#include "BKE_colorband.h"
#include "draw_common.h"
@@ -81,6 +81,21 @@ void DRW_globals_update(void)
UI_GetThemeColor4fv(TH_FACE_DOT, ts.colorFaceDot);
UI_GetThemeColor4fv(TH_BACK, ts.colorBackground);
+ /* Curve */
+ UI_GetThemeColor4fv(TH_HANDLE_FREE, ts.colorHandleFree);
+ UI_GetThemeColor4fv(TH_HANDLE_AUTO, ts.colorHandleAuto);
+ UI_GetThemeColor4fv(TH_HANDLE_VECT, ts.colorHandleVect);
+ UI_GetThemeColor4fv(TH_HANDLE_ALIGN, ts.colorHandleAlign);
+ UI_GetThemeColor4fv(TH_HANDLE_AUTOCLAMP, ts.colorHandleAutoclamp);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_FREE, ts.colorHandleSelFree);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_AUTO, ts.colorHandleSelAuto);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_VECT, ts.colorHandleSelVect);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_ALIGN, ts.colorHandleSelAlign);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_AUTOCLAMP, ts.colorHandleSelAutoclamp);
+ UI_GetThemeColor4fv(TH_NURB_ULINE, ts.colorNurbUline);
+ UI_GetThemeColor4fv(TH_NURB_SEL_ULINE, ts.colorNurbSelUline);
+ UI_GetThemeColor4fv(TH_ACTIVE_SPLINE, ts.colorActiveSpline);
+
/* Grid */
UI_GetThemeColorShade4fv(TH_GRID, 10, ts.colorGrid);
/* emphasise division lines lighter instead of darker, if background is darker than grid */
@@ -130,7 +145,7 @@ void DRW_globals_update(void)
ramp.data[2].r = 1.0f;
ramp.data[2].pos = 1.0f;
- colorband_table_RGBA(&ramp, &colors, &col_size);
+ BKE_colorband_evaluate_table_rgba(&ramp, &colors, &col_size);
if (globals_ramp) {
GPU_texture_free(globals_ramp);
@@ -200,7 +215,7 @@ DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct Gwn_Batch *g
return grp;
}
-DRWShadingGroup *shgroup_instance_objspace_solid(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+DRWShadingGroup *shgroup_instance_solid(DRWPass *pass, struct Gwn_Batch *geom)
{
static float light[3] = {0.0f, 0.0f, 1.0f};
GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR);
@@ -208,20 +223,18 @@ DRWShadingGroup *shgroup_instance_objspace_solid(DRWPass *pass, struct Gwn_Batch
DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
DRW_shgroup_attrib_float(grp, "color", 4);
- DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
DRW_shgroup_uniform_vec3(grp, "light", light, 1);
return grp;
}
-DRWShadingGroup *shgroup_instance_objspace_wire(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+DRWShadingGroup *shgroup_instance_wire(DRWPass *pass, struct Gwn_Batch *geom)
{
GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR);
DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
DRW_shgroup_attrib_float(grp, "color", 4);
- DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
return grp;
}
@@ -308,8 +321,8 @@ DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, struct Gwn_Batch
DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Gwn_Batch *geom)
{
GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR);
- static bool True = true;
- static bool False = false;
+ static const int True = true;
+ static const int False = false;
DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom);
DRW_shgroup_attrib_float(grp, "color", 3);
@@ -321,7 +334,7 @@ DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Gwn_Batch *geom)
return grp;
}
-DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_Batch *geom)
{
GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE);
@@ -331,12 +344,11 @@ DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_B
DRW_shgroup_attrib_float(grp, "radius_head", 1);
DRW_shgroup_attrib_float(grp, "radius_tail", 1);
DRW_shgroup_attrib_float(grp, "distance", 1);
- DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
return grp;
}
-DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_Batch *geom)
{
static float light[3] = {0.0f, 0.0f, 1.0f};
GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID);
@@ -346,7 +358,6 @@ DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_
DRW_shgroup_attrib_float(grp, "color", 4);
DRW_shgroup_attrib_float(grp, "radius_head", 1);
DRW_shgroup_attrib_float(grp, "radius_tail", 1);
- DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
DRW_shgroup_uniform_vec3(grp, "light", light, 1);
return grp;
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 0bdb79b3a40..cfd88effd15 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -72,6 +72,20 @@ typedef struct GlobalsUboStorage {
float colorBackground[4];
+ float colorHandleFree[4];
+ float colorHandleAuto[4];
+ float colorHandleVect[4];
+ float colorHandleAlign[4];
+ float colorHandleAutoclamp[4];
+ float colorHandleSelFree[4];
+ float colorHandleSelAuto[4];
+ float colorHandleSelVect[4];
+ float colorHandleSelAlign[4];
+ float colorHandleSelAutoclamp[4];
+ float colorNurbUline[4];
+ float colorNurbSelUline[4];
+ float colorActiveSpline[4];
+
float colorGrid[4];
float colorGridEmphasise[4];
float colorGridAxisX[4];
@@ -92,8 +106,8 @@ struct DRWShadingGroup *shgroup_dynpoints_uniform_color(struct DRWPass *pass, fl
struct DRWShadingGroup *shgroup_groundlines_uniform_color(struct DRWPass *pass, float color[4]);
struct DRWShadingGroup *shgroup_groundpoints_uniform_color(struct DRWPass *pass, float color[4]);
struct DRWShadingGroup *shgroup_instance_screenspace(struct DRWPass *pass, struct Gwn_Batch *geom, float *size);
-struct DRWShadingGroup *shgroup_instance_objspace_solid(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
-struct DRWShadingGroup *shgroup_instance_objspace_wire(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
+struct DRWShadingGroup *shgroup_instance_solid(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_wire(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_screen_aligned(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_axis_names(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_image_plane(struct DRWPass *pass, struct Gwn_Batch *geom);
@@ -102,8 +116,8 @@ struct DRWShadingGroup *shgroup_instance(struct DRWPass *pass, struct Gwn_Batch
struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
-struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
-struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_mball_helpers(struct DRWPass *pass, struct Gwn_Batch *geom);
int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color);
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
new file mode 100644
index 00000000000..e7ce4374d1c
--- /dev/null
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2016, 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(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_instance_data.c
+ * \ingroup draw
+ */
+
+/**
+ * DRW Instance Data Manager
+ * This is a special memory manager that keeps memory blocks ready to send as vbo data in one continuous allocation.
+ * This way we avoid feeding gawain each instance data one by one and unecessary memcpy.
+ * Since we loose which memory block was used each DRWShadingGroup we need to redistribute them in the same order/size
+ * to avoid to realloc each frame.
+ * This is why DRWInstanceDatas are sorted in a list for each different data size.
+ **/
+
+#include "draw_instance_data.h"
+#include "DRW_engine.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+
+#define MAX_INSTANCE_DATA_SIZE 32 /* Can be adjusted for more */
+
+struct DRWInstanceData {
+ struct DRWInstanceData *next;
+ bool used; /* If this data is used or not. */
+ size_t chunk_size; /* Current size of the whole chunk. */
+ size_t data_size; /* Size of one instance data. */
+ size_t instance_group; /* How many instance to allocate at a time. */
+ size_t offset; /* Offset to the next instance data. */
+ float *memchunk; /* Should be float no matter what. */
+};
+
+struct DRWInstanceDataList {
+ /* Linked lists for all possible data pool size */
+ /* Not entirely sure if we should separate them in the first place.
+ * This is done to minimize the reattribution misses. */
+ DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE];
+ DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE];
+};
+
+/* -------------------------------------------------------------------- */
+
+/** \name Instance Data (DRWInstanceData)
+ * \{ */
+
+static DRWInstanceData *drw_instance_data_create(
+ DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group)
+{
+ DRWInstanceData *idata = MEM_mallocN(sizeof(DRWInstanceData), "DRWInstanceData");
+ idata->next = NULL;
+ idata->used = true;
+ idata->data_size = attrib_size;
+ idata->instance_group = instance_group;
+ idata->chunk_size = idata->data_size * instance_group;
+ idata->offset = 0;
+ idata->memchunk = MEM_mallocN(idata->chunk_size * sizeof(float), "DRWInstanceData memchunk");
+
+ BLI_assert(attrib_size > 0);
+
+ /* Push to linked list. */
+ if (idatalist->idata_head[attrib_size-1] == NULL) {
+ idatalist->idata_head[attrib_size-1] = idata;
+ }
+ else {
+ idatalist->idata_tail[attrib_size-1]->next = idata;
+ }
+ idatalist->idata_tail[attrib_size-1] = idata;
+
+ return idata;
+}
+
+static void DRW_instance_data_free(DRWInstanceData *idata)
+{
+ MEM_freeN(idata->memchunk);
+}
+
+/**
+ * Return a pointer to the next instance data space.
+ * DO NOT SAVE/REUSE THIS POINTER after the next call
+ * to this function since the chunk may have been
+ * reallocated.
+ **/
+void *DRW_instance_data_next(DRWInstanceData *idata)
+{
+ idata->offset += idata->data_size;
+
+ /* Check if chunk is large enough. realloc otherwise. */
+ if (idata->offset > idata->chunk_size) {
+ idata->chunk_size += idata->data_size * idata->instance_group;
+ idata->memchunk = MEM_reallocN(idata->memchunk, idata->chunk_size * sizeof(float));
+ }
+
+ return idata->memchunk + (idata->offset - idata->data_size);
+}
+
+void *DRW_instance_data_get(DRWInstanceData *idata)
+{
+ return (void *)idata->memchunk;
+}
+
+DRWInstanceData *DRW_instance_data_request(
+ DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group)
+{
+ BLI_assert(attrib_size > 0 && attrib_size <= MAX_INSTANCE_DATA_SIZE);
+
+ DRWInstanceData *idata = idatalist->idata_head[attrib_size - 1];
+
+ /* Search for an unused data chunk. */
+ for (; idata; idata = idata->next) {
+ if (idata->used == false) {
+ idata->used = true;
+ return idata;
+ }
+ }
+
+ return drw_instance_data_create(idatalist, attrib_size, instance_group);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Instance Data List (DRWInstanceDataList)
+ * \{ */
+
+DRWInstanceDataList *DRW_instance_data_list_create(void)
+{
+ return MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList");
+}
+
+void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata, *next_idata;
+
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
+ next_idata = idata->next;
+ DRW_instance_data_free(idata);
+ MEM_freeN(idata);
+ }
+ idatalist->idata_head[i] = NULL;
+ idatalist->idata_tail[i] = NULL;
+ }
+}
+
+void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata;
+
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
+ idata->used = false;
+ idata->offset = 0;
+ }
+ }
+}
+
+void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata, *next_idata;
+
+ /* Remove unused data blocks and sanitize each list. */
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ idatalist->idata_tail[i] = NULL;
+ for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
+ next_idata = idata->next;
+ if (idata->used == false) {
+ if (idatalist->idata_head[i] == idata) {
+ idatalist->idata_head[i] = next_idata;
+ }
+ else {
+ /* idatalist->idata_tail[i] is garanteed not to be null in this case. */
+ idatalist->idata_tail[i]->next = next_idata;
+ }
+ DRW_instance_data_free(idata);
+ MEM_freeN(idata);
+ }
+ else {
+ if (idatalist->idata_tail[i] != NULL) {
+ idatalist->idata_tail[i]->next = idata;
+ }
+ idatalist->idata_tail[i] = idata;
+ }
+ }
+ }
+}
+
+void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata;
+
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
+ /* Rounding up to nearest chunk size to compare. */
+ size_t fac = idata->data_size * idata->instance_group;
+ size_t tmp = idata->offset + fac - 1;
+ size_t rounded_offset = tmp - tmp % fac;
+ if (rounded_offset < idata->chunk_size) {
+ idata->chunk_size = rounded_offset;
+ idata->memchunk = MEM_reallocN(idata->memchunk, idata->chunk_size * sizeof(float));
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
new file mode 100644
index 00000000000..637c0e3cc24
--- /dev/null
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016, 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(s): Blender Institute
+ *
+ */
+
+/** \file draw_instance_data.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_INSTANCE_DATA_H__
+#define __DRAW_INSTANCE_DATA_H__
+
+typedef struct DRWInstanceData DRWInstanceData;
+typedef struct DRWInstanceDataList DRWInstanceDataList;
+
+void *DRW_instance_data_next(DRWInstanceData *idata);
+void *DRW_instance_data_get(DRWInstanceData *idata);
+DRWInstanceData *DRW_instance_data_request(
+ DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group);
+
+void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist);
+void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist);
+void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist);
+
+#endif /* __DRAW_INSTANCE_DATA_H__ */
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 264fc079e42..55195b88c05 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -25,14 +25,15 @@
#include <stdio.h>
-#include "BLI_dynstr.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BIF_glutil.h"
+#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
@@ -47,10 +48,12 @@
#include "DRW_render.h"
#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -85,6 +88,8 @@
/* only for callbacks */
#include "draw_cache_impl.h"
+#include "draw_instance_data.h"
+
#include "draw_mode_engines.h"
#include "engines/clay/clay_engine.h"
#include "engines/eevee/eevee_engine.h"
@@ -180,19 +185,8 @@ struct DRWUniform {
const void *value;
};
-typedef struct DRWAttrib {
- struct DRWAttrib *prev;
- char name[MAX_ATTRIB_NAME];
- int location;
- int format_id;
- int size; /* number of component */
- int type;
-} DRWAttrib;
-
struct DRWInterface {
DRWUniform *uniforms; /* DRWUniform, single-linked list */
- DRWAttrib *attribs; /* DRWAttrib, single-linked list */
- DRWAttrib *attribs_first; /* First added attrib to traverse in the right order */
int attribs_count;
int attribs_stride;
int attribs_size[16];
@@ -218,6 +212,12 @@ struct DRWInterface {
/* Dynamic batch */
Gwn_Batch *instance_batch; /* contains instances attributes */
GLuint instance_vbo; /* same as instance_batch but generated from DRWCalls */
+ struct DRWInstanceData *inst_data;
+#ifdef USE_GPU_SELECT
+ struct DRWInstanceData *inst_selectid;
+ /* Override for single object instances. */
+ int override_selectid;
+#endif
int instance_count;
Gwn_VertFormat vbo_format;
};
@@ -259,12 +259,6 @@ typedef struct DRWCallGenerate {
void *user_data;
} DRWCallGenerate;
-typedef struct DRWCallDynamic {
- DRWCallHeader head;
-
- const void *data[MAX_ATTRIB_COUNT];
-} DRWCallDynamic;
-
struct DRWShadingGroup {
struct DRWShadingGroup *next;
@@ -309,22 +303,15 @@ enum {
DRW_CALL_DYNAMIC,
};
-/* only 16 bits long */
-enum {
- STENCIL_SELECT = (1 << 0),
- STENCIL_ACTIVE = (1 << 1),
-};
-
/** Render State: No persistent data between draw calls. */
static struct DRWGlobalState {
/* Cache generation */
ViewportMemoryPool *vmempool;
DRWUniform *last_uniform;
- DRWAttrib *last_attrib;
DRWCall *last_call;
DRWCallGenerate *last_callgenerate;
- DRWCallDynamic *last_calldynamic;
DRWShadingGroup *last_shgroup;
+ DRWInstanceDataList *idatalist;
/* Rendering state */
GPUShader *shader;
@@ -351,6 +338,7 @@ static struct DRWGlobalState {
unsigned int is_depth : 1;
unsigned int is_image_render : 1;
unsigned int is_scene_render : 1;
+ unsigned int draw_background : 1;
} options;
/* Current rendering context */
@@ -409,6 +397,7 @@ static void drw_texture_get_format(
case DRW_TEX_RGB_11_11_10: *r_data_type = GPU_R11F_G11F_B10F; break;
case DRW_TEX_RG_8: *r_data_type = GPU_RG8; break;
case DRW_TEX_RG_16: *r_data_type = GPU_RG16F; break;
+ case DRW_TEX_RG_16I: *r_data_type = GPU_RG16I; break;
case DRW_TEX_RG_32: *r_data_type = GPU_RG32F; break;
case DRW_TEX_R_8: *r_data_type = GPU_R8; break;
case DRW_TEX_R_16: *r_data_type = GPU_R16F; break;
@@ -442,6 +431,7 @@ static void drw_texture_get_format(
break;
case DRW_TEX_RG_8:
case DRW_TEX_RG_16:
+ case DRW_TEX_RG_16I:
case DRW_TEX_RG_32:
*r_channels = 2;
break;
@@ -594,24 +584,11 @@ GPUShader *DRW_shader_create_with_lib(
char *frag_with_lib = NULL;
char *geom_with_lib = NULL;
- DynStr *ds_vert = BLI_dynstr_new();
- BLI_dynstr_append(ds_vert, lib);
- BLI_dynstr_append(ds_vert, vert);
- vert_with_lib = BLI_dynstr_get_cstring(ds_vert);
- BLI_dynstr_free(ds_vert);
-
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, lib);
- BLI_dynstr_append(ds_frag, frag);
- frag_with_lib = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ vert_with_lib = BLI_string_joinN(lib, vert);
+ frag_with_lib = BLI_string_joinN(lib, frag);
if (geom) {
- DynStr *ds_geom = BLI_dynstr_new();
- BLI_dynstr_append(ds_geom, lib);
- BLI_dynstr_append(ds_geom, geom);
- geom_with_lib = BLI_dynstr_get_cstring(ds_geom);
- BLI_dynstr_free(ds_geom);
+ geom_with_lib = BLI_string_joinN(lib, geom);
}
sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines);
@@ -682,12 +659,14 @@ static void drw_interface_create(DRWInterface *interface, GPUShader *shader)
interface->attribs_stride = 0;
interface->instance_vbo = 0;
interface->instance_batch = NULL;
+ interface->inst_data = NULL;
+ interface->uniforms = NULL;
+#ifdef USE_GPU_SELECT
+ interface->inst_selectid = NULL;
+ interface->override_selectid = -1;
+#endif
memset(&interface->vbo_format, 0, sizeof(Gwn_VertFormat));
-
- interface->uniforms = NULL;
- interface->attribs = NULL;
- interface->attribs_first = NULL;
}
@@ -725,14 +704,22 @@ static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name,
shgroup->interface.uniforms = uni;
}
-static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy)
+static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType UNUSED(type), int size, bool dummy)
{
- DRWAttrib *attrib = BLI_mempool_alloc(DST.vmempool->attribs);
+ unsigned int attrib_id = shgroup->interface.attribs_count;
GLuint program = GPU_shader_get_program(shgroup->shader);
- attrib->location = glGetAttribLocation(program, name);
- attrib->type = type;
- attrib->size = size;
+ shgroup->interface.attribs_loc[attrib_id] = glGetAttribLocation(program, name);
+ shgroup->interface.attribs_size[attrib_id] = size;
+ shgroup->interface.attribs_stride += size;
+ shgroup->interface.attribs_count += 1;
+
+ if (shgroup->type != DRW_SHG_INSTANCE) {
+ BLI_assert(size <= 4); /* Matrices are not supported by Gawain. */
+ GWN_vertformat_attr_add(&shgroup->interface.vbo_format, name, GWN_COMP_F32, size, GWN_FETCH_FLOAT);
+ }
+
+ BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT);
/* Adding attribute even if not found for now (to keep memory alignment).
* Should ideally take vertex format automatically from batch eventually */
@@ -747,23 +734,6 @@ static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRW
#else
UNUSED_VARS(dummy);
#endif
-
- BLI_assert(BLI_strnlen(name, 32) < 32);
- BLI_strncpy(attrib->name, name, 32);
-
- shgroup->interface.attribs_count += 1;
- BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT);
-
- /* Prepend */
- if (shgroup->interface.attribs == NULL) {
- shgroup->interface.attribs = attrib;
- shgroup->interface.attribs_first = attrib;
- }
- else {
- shgroup->interface.attribs->prev = attrib;
- shgroup->interface.attribs = attrib;
- }
- attrib->prev = NULL;
}
/** \} */
@@ -847,16 +817,10 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa
else {
switch (input->type) {
case GPU_FLOAT:
- DRW_shgroup_uniform_float(grp, input->shadername, (float *)input->dynamicvec, 1);
- break;
case GPU_VEC2:
- DRW_shgroup_uniform_vec2(grp, input->shadername, (float *)input->dynamicvec, 1);
- break;
case GPU_VEC3:
- DRW_shgroup_uniform_vec3(grp, input->shadername, (float *)input->dynamicvec, 1);
- break;
case GPU_VEC4:
- DRW_shgroup_uniform_vec4(grp, input->shadername, (float *)input->dynamicvec, 1);
+ /* Should already be in the material ubo. */
break;
case GPU_MAT3:
DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec);
@@ -961,14 +925,6 @@ void DRW_shgroup_free(struct DRWShadingGroup *shgroup)
GWN_BATCH_DISCARD_SAFE(shgroup->batch_geom);
}
-void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances)
-{
- BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
- BLI_assert(shgroup->interface.instance_batch == NULL);
-
- shgroup->interface.instance_batch = instances;
-}
-
#define CALL_PREPEND(shgroup, call) { \
if (shgroup->calls == NULL) { \
shgroup->calls = call; \
@@ -981,10 +937,25 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *inst
call->head.prev = NULL; \
} ((void)0)
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances)
+{
+ BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
+ BLI_assert(shgroup->interface.instance_batch == NULL);
+
+ shgroup->interface.instance_batch = instances;
+
+#ifdef USE_GPU_SELECT
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->head.select_id = g_DRW_select_id;
+
+ CALL_PREPEND(shgroup, call);
+#endif
+}
void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4])
{
BLI_assert(geom != NULL);
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
@@ -1006,6 +977,7 @@ void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obm
void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob)
{
BLI_assert(geom != NULL);
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
@@ -1027,6 +999,7 @@ void DRW_shgroup_call_generate_add(
float (*obmat)[4])
{
BLI_assert(geometry_fn != NULL);
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate);
@@ -1070,43 +1043,30 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at
DRWInterface *interface = &shgroup->interface;
#ifdef USE_GPU_SELECT
- if ((G.f & G_PICKSEL) && (interface->instance_count > 0)) {
- DRWShadingGroup *original_shgroup = shgroup;
- shgroup = BLI_mempool_alloc(DST.vmempool->shgroups);
- memcpy(shgroup, original_shgroup, sizeof(DRWShadingGroup));
-
- shgroup->calls = NULL;
- shgroup->calls_first = NULL;
-
- interface = &shgroup->interface;
- interface->instance_count = 0;
-
- /* Append */
- if (shgroup->pass_parent->shgroups != NULL) {
- shgroup->pass_parent->shgroups_last->next = shgroup;
- }
- else {
- shgroup->pass_parent->shgroups = shgroup;
+ if (G.f & G_PICKSEL) {
+ if (interface->inst_selectid == NULL) {
+ interface->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128);
}
- shgroup->pass_parent->shgroups_last = shgroup;
- shgroup->next = NULL;
+
+ int *select_id = DRW_instance_data_next(interface->inst_selectid);
+ *select_id = g_DRW_select_id;
}
#endif
- DRWCallDynamic *call = BLI_mempool_alloc(DST.vmempool->calls_dynamic);
-
- CALL_PREPEND(shgroup, call);
-
BLI_assert(attr_len == interface->attribs_count);
UNUSED_VARS_NDEBUG(attr_len);
- call->head.type = DRW_CALL_DYNAMIC;
-#ifdef USE_GPU_SELECT
- call->head.select_id = g_DRW_select_id;
-#endif
+ if (interface->attribs_stride > 0) {
+ if (interface->inst_data == NULL) {
+ interface->inst_data = DRW_instance_data_request(DST.idatalist, interface->attribs_stride, 16);
+ }
+
+ float *data = DRW_instance_data_next(interface->inst_data);
- if (interface->attribs_count != 0) {
- memcpy((void *)call->data, attr, sizeof(void *) * interface->attribs_count);
+ for (int i = 0; i < interface->attribs_count; ++i) {
+ memcpy(data, attr[i], sizeof(float) * interface->attribs_size[i]);
+ data = data + interface->attribs_size[i];
+ }
}
interface->instance_count += 1;
@@ -1117,8 +1077,15 @@ void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count)
{
DRWInterface *interface = &shgroup->interface;
+ BLI_assert(interface->instance_count == 0);
BLI_assert(interface->attribs_count == 0);
+#ifdef USE_GPU_SELECT
+ if (G.f & G_PICKSEL) {
+ interface->override_selectid = g_DRW_select_id;
+ }
+#endif
+
interface->instance_count = count;
}
@@ -1161,7 +1128,7 @@ void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUT
drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1);
}
-void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize)
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
{
drw_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize);
}
@@ -1234,32 +1201,13 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup)
return;
/* Upload Data */
- if (interface->vbo_format.attrib_ct == 0) {
- for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev) {
- BLI_assert(attrib->size <= 4); /* matrices have no place here for now */
- if (attrib->type == DRW_ATTRIB_FLOAT) {
- attrib->format_id = GWN_vertformat_attr_add(
- &interface->vbo_format, attrib->name, GWN_COMP_F32, attrib->size, GWN_FETCH_FLOAT);
- }
- else if (attrib->type == DRW_ATTRIB_INT) {
- attrib->format_id = GWN_vertformat_attr_add(
- &interface->vbo_format, attrib->name, GWN_COMP_I8, attrib->size, GWN_FETCH_INT);
- }
- else {
- BLI_assert(false);
- }
- }
- }
-
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format);
- GWN_vertbuf_data_alloc(vbo, nbr);
-
- int j = 0;
- for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev, j++) {
- int i = 0;
- for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) {
- GWN_vertbuf_attr_set(vbo, attrib->format_id, j, call->data[i]);
- }
+ if (interface->inst_data) {
+ GWN_vertbuf_data_set(vbo, nbr, DRW_instance_data_get(interface->inst_data), false);
+ } else {
+ /* Use unitialized memory. This is for dummy vertex buffers. */
+ /* XXX TODO do not alloc at all. */
+ GWN_vertbuf_data_alloc(vbo, nbr);
}
/* TODO make the batch dynamic instead of freeing it every times */
@@ -1271,10 +1219,9 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup)
static void shgroup_dynamic_instance(DRWShadingGroup *shgroup)
{
- int i = 0;
- int offset = 0;
DRWInterface *interface = &shgroup->interface;
int buffer_size = 0;
+ void *data = NULL;
if (interface->instance_batch != NULL) {
return;
@@ -1289,26 +1236,8 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup)
return;
}
- /* only once */
- if (interface->attribs_stride == 0) {
- for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) {
- BLI_assert(attrib->type == DRW_ATTRIB_FLOAT); /* Only float for now */
- interface->attribs_stride += attrib->size;
- interface->attribs_size[i] = attrib->size;
- interface->attribs_loc[i] = attrib->location;
- }
- }
-
/* Gather Data */
buffer_size = sizeof(float) * interface->attribs_stride * interface->instance_count;
- float *data = MEM_mallocN(buffer_size, "Instance VBO data");
-
- for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev) {
- for (int j = 0; j < interface->attribs_count; ++j) {
- memcpy(data + offset, call->data[j], sizeof(float) * interface->attribs_size[j]);
- offset += interface->attribs_size[j];
- }
- }
/* TODO poke mike to add this to gawain */
if (interface->instance_vbo) {
@@ -1316,11 +1245,13 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup)
interface->instance_vbo = 0;
}
+ if (interface->inst_data) {
+ data = DRW_instance_data_get(interface->inst_data);
+ }
+
glGenBuffers(1, &interface->instance_vbo);
glBindBuffer(GL_ARRAY_BUFFER, interface->instance_vbo);
glBufferData(GL_ARRAY_BUFFER, buffer_size, data, GL_STATIC_DRAW);
-
- MEM_freeN(data);
}
static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup)
@@ -1359,6 +1290,11 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
return pass;
}
+void DRW_pass_state_set(DRWPass *pass, DRWState state)
+{
+ pass->state = state;
+}
+
void DRW_pass_free(DRWPass *pass)
{
for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) {
@@ -1597,14 +1533,16 @@ static void drw_state_set(DRWState state)
{
int test;
if (CHANGED_ANY_STORE_VAR(
- DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION,
+ DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION |
+ DRW_STATE_ADDITIVE_FULL,
test))
{
if (test) {
glEnable(GL_BLEND);
if ((state & DRW_STATE_BLEND) != 0) {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, /* RGB */
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
}
else if ((state & DRW_STATE_MULTIPLY) != 0) {
glBlendFunc(GL_DST_COLOR, GL_ZERO);
@@ -1613,7 +1551,13 @@ static void drw_state_set(DRWState state)
glBlendFunc(GL_ONE, GL_SRC_ALPHA);
}
else if ((state & DRW_STATE_ADDITIVE) != 0) {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ /* Do not let alpha accumulate but premult the source RGB by it. */
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, /* RGB */
+ GL_ZERO, GL_ONE); /* Alpha */
+ }
+ else if ((state & DRW_STATE_ADDITIVE_FULL) != 0) {
+ /* Let alpha accumulate. */
+ glBlendFunc(GL_ONE, GL_ONE);
}
else {
BLI_assert(0);
@@ -1839,28 +1783,37 @@ static void draw_geometry_prepare(
GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq);
}
-static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom)
+static void draw_geometry_execute_ex(
+ DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count)
{
DRWInterface *interface = &shgroup->interface;
/* step 2 : bind vertex array & draw */
GWN_batch_program_set(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
if (interface->instance_batch) {
+ /* Used for Particles. Cannot do partial drawing. */
GWN_batch_draw_stupid_instanced_with_batch(geom, interface->instance_batch);
}
else if (interface->instance_vbo) {
GWN_batch_draw_stupid_instanced(
- geom, interface->instance_vbo, interface->instance_count, interface->attribs_count,
+ geom, interface->instance_vbo, start, count, interface->attribs_count,
interface->attribs_stride, interface->attribs_size, interface->attribs_loc);
}
else {
- GWN_batch_draw_stupid(geom);
+ GWN_batch_draw_stupid(geom, start, count);
}
/* XXX this just tells gawain we are done with the shader.
* This does not unbind the shader. */
GWN_batch_program_unset(geom);
}
-static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data)
+static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom)
+{
+ draw_geometry_execute_ex(shgroup, geom, 0, 0);
+}
+
+static void draw_geometry(
+ DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data,
+ unsigned int start, unsigned int count)
{
float *texcoloc = NULL;
float *texcosize = NULL;
@@ -1870,15 +1823,31 @@ static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float
case ID_ME:
BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
break;
+ case ID_CU:
+ {
+ Curve *cu = (Curve *)ob_data;
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(cu);
+ }
+ texcoloc = cu->loc;
+ texcosize = cu->size;
+ break;
+ }
+ case ID_MB:
+ {
+ MetaBall *mb = (MetaBall *)ob_data;
+ texcoloc = mb->loc;
+ texcosize = mb->size;
+ break;
+ }
default:
- /* TODO, curve, metaball? */
break;
}
}
draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize);
- draw_geometry_execute(shgroup, geom);
+ draw_geometry_execute_ex(shgroup, geom, start, count);
}
static void bind_texture(GPUTexture *tex)
@@ -2012,15 +1981,39 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
GPU_select_load_id((_call)->head.select_id); \
} ((void)0)
-# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_call_last, _call_first) \
- if ((G.f & G_PICKSEL) && _call_first) { \
- BLI_assert(_call_first && (_call_first == _call_last)); \
- GPU_select_load_id(((DRWCall *)_call_first)->head.select_id); \
- } ((void)0)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \
+ _start = 0; \
+ _count = _shgroup->interface.instance_count; \
+ int *select_id = NULL; \
+ if (G.f & G_PICKSEL) { \
+ if (_shgroup->interface.override_selectid == -1) { \
+ select_id = DRW_instance_data_get(_shgroup->interface.inst_selectid); \
+ switch (_shgroup->type) { \
+ case DRW_SHG_TRIANGLE_BATCH: _count = 3; break; \
+ case DRW_SHG_LINE_BATCH: _count = 2; break; \
+ default: _count = 1; break; \
+ } \
+ } \
+ else { \
+ GPU_select_load_id(_shgroup->interface.override_selectid); \
+ } \
+ } \
+ while (_start < _shgroup->interface.instance_count) { \
+ if (select_id) { \
+ GPU_select_load_id(select_id[_start]); \
+ }
+
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \
+ _start += _count; \
+ }
#else
# define GPU_SELECT_LOAD_IF_PICKSEL(call)
-# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(call, _call_first)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \
+ _start = 0; \
+ _count = _shgroup->interface.instance_count;
+
#endif
/* Rendering Calls */
@@ -2032,14 +2025,28 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
if (shgroup->type == DRW_SHG_INSTANCE &&
(interface->instance_count > 0 || interface->instance_batch != NULL))
{
- GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first);
- draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data);
+ if (interface->instance_batch != NULL) {
+ GPU_SELECT_LOAD_IF_PICKSEL((DRWCall *)shgroup->calls_first);
+ draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, 0, 0);
+ }
+ else {
+ unsigned int count, start;
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count)
+ {
+ draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, start, count);
+ }
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+ }
}
else {
/* Some dynamic batch can have no geom (no call to aggregate) */
if (shgroup->batch_geom) {
- GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first);
- draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL);
+ unsigned int count, start;
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count)
+ {
+ draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL, start, count);
+ }
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
}
}
}
@@ -2055,7 +2062,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
GPU_SELECT_LOAD_IF_PICKSEL(call);
if (call->head.type == DRW_CALL_SINGLE) {
- draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data);
+ draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data, 0, 0);
}
else {
BLI_assert(call->head.type == DRW_CALL_GENERATE);
@@ -2195,9 +2202,7 @@ bool DRW_object_is_renderable(Object *ob)
Scene *scene = DST.draw_ctx.scene;
Object *obedit = scene->obedit;
- if (!BKE_object_is_visible(ob)) {
- return false;
- }
+ BLI_assert(BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE));
if (ob->type == OB_MESH) {
if (ob == obedit) {
@@ -2216,6 +2221,18 @@ bool DRW_object_is_renderable(Object *ob)
return true;
}
+/**
+ * Return whether this object is visible depending if
+ * we are rendering or drawing in the viewport.
+ */
+bool DRW_check_object_visible_within_active_context(Object *ob)
+{
+ const eObjectVisibilityCheck mode = DRW_state_is_scene_render() ?
+ OB_VISIBILITY_CHECK_FOR_RENDER :
+ OB_VISIBILITY_CHECK_FOR_VIEWPORT;
+ return BKE_object_is_visible(ob, mode);
+}
+
bool DRW_object_is_flat_normal(const Object *ob)
{
if (ob->type == OB_MESH) {
@@ -2227,7 +2244,6 @@ bool DRW_object_is_flat_normal(const Object *ob)
return true;
}
-
/**
* Return true if the object has its own draw mode.
* Caller must check this is active */
@@ -2266,6 +2282,7 @@ static GPUTextureFormat convert_tex_format(
case DRW_TEX_R_32: *r_channels = 1; return GPU_R32F;
case DRW_TEX_RG_8: *r_channels = 2; return GPU_RG8;
case DRW_TEX_RG_16: *r_channels = 2; return GPU_RG16F;
+ case DRW_TEX_RG_16I: *r_channels = 2; return GPU_RG16I;
case DRW_TEX_RG_32: *r_channels = 2; return GPU_RG32F;
case DRW_TEX_RGBA_8: *r_channels = 4; return GPU_RGBA8;
case DRW_TEX_RGBA_16: *r_channels = 4; return GPU_RGBA16F;
@@ -2281,11 +2298,17 @@ static GPUTextureFormat convert_tex_format(
}
}
+struct GPUFrameBuffer *DRW_framebuffer_create(void)
+{
+ return GPU_framebuffer_create();
+}
+
void DRW_framebuffer_init(
struct GPUFrameBuffer **fb, void *engine_type, int width, int height,
DRWFboTexture textures[MAX_FBO_TEX], int textures_len)
{
BLI_assert(textures_len <= MAX_FBO_TEX);
+ BLI_assert(width > 0 && height > 0);
bool create_fb = false;
int color_attachment = -1;
@@ -2298,6 +2321,7 @@ void DRW_framebuffer_init(
for (int i = 0; i < textures_len; ++i) {
int channels;
bool is_depth;
+ bool create_tex = false;
DRWFboTexture fbotex = textures[i];
bool is_temp = (fbotex.flag & DRW_TEX_TEMP) != 0;
@@ -2310,16 +2334,18 @@ void DRW_framebuffer_init(
*fbotex.tex = GPU_viewport_texture_pool_query(
DST.viewport, engine_type, width, height, channels, gpu_format);
}
- else if (create_fb) {
+ else {
*fbotex.tex = GPU_texture_create_2D_custom(
width, height, channels, gpu_format, NULL, NULL);
+ create_tex = true;
}
}
- if (create_fb) {
- if (!is_depth) {
- ++color_attachment;
- }
+ if (!is_depth) {
+ ++color_attachment;
+ }
+
+ if (create_fb || create_tex) {
drw_texture_set_parameters(*fbotex.tex, fbotex.flag);
GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment, 0);
}
@@ -2339,7 +2365,9 @@ void DRW_framebuffer_init(
}
}
- GPU_framebuffer_bind(DST.default_framebuffer);
+ if (DST.default_framebuffer != NULL) {
+ GPU_framebuffer_bind(DST.default_framebuffer);
+ }
}
}
@@ -2387,6 +2415,14 @@ void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slo
glReadPixels(x, y, w, h, type, GL_FLOAT, data);
}
+void DRW_framebuffer_read_depth(int x, int y, int w, int h, float *data)
+{
+ GLenum type = GL_DEPTH_COMPONENT;
+
+ glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */
+ glReadPixels(x, y, w, h, type, GL_FLOAT, data);
+}
+
void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
{
GPU_framebuffer_texture_attach(fb, tex, slot, mip);
@@ -2437,18 +2473,22 @@ void DRW_transform_to_display(GPUTexture *tex)
bool use_ocio = false;
- {
+ /* View transform is already applied for offscreen, don't apply again, see: T52046 */
+ if (!(DST.options.is_image_render && !DST.options.is_scene_render)) {
Scene *scene = DST.draw_ctx.scene;
- /* View transform is already applied for offscreen, don't apply again, see: T52046 */
- ColorManagedViewSettings *view_settings =
- (DST.options.is_image_render && !DST.options.is_scene_render) ?
- NULL : &scene->view_settings;
use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(
- view_settings, &scene->display_settings, NULL, dither, false);
+ &scene->view_settings, &scene->display_settings, NULL, dither, false);
}
if (!use_ocio) {
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB);
+ /* View transform is already applied for offscreen, don't apply again, see: T52046 */
+ if (DST.options.is_image_render && !DST.options.is_scene_render) {
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB);
+ }
immUniform1i("image", 0);
}
@@ -2541,12 +2581,13 @@ static void drw_viewport_cache_resize(void)
if (DST.vmempool != NULL) {
BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_count(DST.vmempool->calls));
BLI_mempool_clear_ex(DST.vmempool->calls_generate, BLI_mempool_count(DST.vmempool->calls_generate));
- BLI_mempool_clear_ex(DST.vmempool->calls_dynamic, BLI_mempool_count(DST.vmempool->calls_dynamic));
BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_count(DST.vmempool->shgroups));
BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_count(DST.vmempool->uniforms));
- BLI_mempool_clear_ex(DST.vmempool->attribs, BLI_mempool_count(DST.vmempool->attribs));
BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_count(DST.vmempool->passes));
}
+
+ DRW_instance_data_list_free_unused(DST.idatalist);
+ DRW_instance_data_list_resize(DST.idatalist);
}
/* It also stores viewport variable to an immutable place: DST
@@ -2575,21 +2616,18 @@ static void drw_viewport_var_init(void)
if (DST.vmempool->calls_generate == NULL) {
DST.vmempool->calls_generate = BLI_mempool_create(sizeof(DRWCallGenerate), 0, 512, 0);
}
- if (DST.vmempool->calls_dynamic == NULL) {
- DST.vmempool->calls_dynamic = BLI_mempool_create(sizeof(DRWCallDynamic), 0, 512, 0);
- }
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0);
}
if (DST.vmempool->uniforms == NULL) {
DST.vmempool->uniforms = BLI_mempool_create(sizeof(DRWUniform), 0, 512, 0);
}
- if (DST.vmempool->attribs == NULL) {
- DST.vmempool->attribs = BLI_mempool_create(sizeof(DRWAttrib), 0, 256, 0);
- }
if (DST.vmempool->passes == NULL) {
DST.vmempool->passes = BLI_mempool_create(sizeof(DRWPass), 0, 64, 0);
}
+
+ DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport);
+ DRW_instance_data_list_reset(DST.idatalist);
}
else {
DST.size[0] = 0;
@@ -2598,14 +2636,17 @@ static void drw_viewport_var_init(void)
DST.default_framebuffer = NULL;
DST.vmempool = NULL;
}
- /* Refresh DST.screenvecs */
- copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]);
- copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]);
- normalize_v3(DST.screenvecs[0]);
- normalize_v3(DST.screenvecs[1]);
- /* Refresh DST.pixelsize */
- DST.pixsize = rv3d->pixsize;
+ if (rv3d != NULL) {
+ /* Refresh DST.screenvecs */
+ copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]);
+ copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]);
+ normalize_v3(DST.screenvecs[0]);
+ normalize_v3(DST.screenvecs[1]);
+
+ /* Refresh DST.pixelsize */
+ DST.pixsize = rv3d->pixsize;
+ }
/* Reset facing */
DST.frontface = GL_CCW;
@@ -2636,6 +2677,7 @@ void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
copy_m4_m4(mat, viewport_matrix_override.mat[type]);
}
else {
+ BLI_assert(rv3d != NULL); /* Can't use this in render mode. */
switch (type) {
case DRW_MAT_PERS:
copy_m4_m4(mat, rv3d->persmat);
@@ -2676,7 +2718,16 @@ void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type)
bool DRW_viewport_is_persp_get(void)
{
RegionView3D *rv3d = DST.draw_ctx.rv3d;
- return rv3d->is_persp;
+ if (rv3d) {
+ return rv3d->is_persp;
+ }
+ else {
+ if (viewport_matrix_override.override[DRW_MAT_WIN]) {
+ return viewport_matrix_override.mat[DRW_MAT_WIN][3][3] == 0.0f;
+ }
+ }
+ BLI_assert(0);
+ return false;
}
DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void)
@@ -2737,33 +2788,40 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*cal
/** \name Objects (DRW_object)
* \{ */
-void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type)
+ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type)
{
for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
if (oed->engine_type == engine_type) {
- return oed->storage;
+ return oed;
}
}
return NULL;
}
-void **DRW_object_engine_data_ensure(
- Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage))
+ObjectEngineData *DRW_object_engine_data_ensure(
+ Object *ob,
+ DrawEngineType *engine_type,
+ size_t size,
+ ObjectEngineDataInitCb init_cb,
+ ObjectEngineDataFreeCb free_cb)
{
- ObjectEngineData *oed;
-
- for (oed = ob->drawdata.first; oed; oed = oed->next) {
- if (oed->engine_type == engine_type) {
- return &oed->storage;
- }
+ BLI_assert(size >= sizeof(ObjectEngineData));
+ /* Try to re-use existing data. */
+ ObjectEngineData *oed = DRW_object_engine_data_get(ob, engine_type);
+ if (oed != NULL) {
+ return oed;
}
-
- oed = MEM_callocN(sizeof(ObjectEngineData), "ObjectEngineData");
+ /* Allocate new data. */
+ oed = MEM_callocN(size, "ObjectEngineData");
oed->engine_type = engine_type;
- oed->free = callback;
+ oed->free = free_cb;
+ /* Perform user-side initialization, if needed. */
+ if (init_cb != NULL) {
+ init_cb(oed);
+ }
+ /* Register in the list. */
BLI_addtail(&ob->drawdata, oed);
-
- return &oed->storage;
+ return oed;
}
/* XXX There is definitly some overlap between this and DRW_object_engine_data_ensure.
@@ -2833,6 +2891,10 @@ static void drw_engines_cache_populate(Object *ob)
DrawEngineType *engine = link->data;
ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ if (engine->id_update) {
+ engine->id_update(data, &ob->id);
+ }
+
if (engine->cache_populate) {
engine->cache_populate(data, ob);
}
@@ -2870,7 +2932,9 @@ static void drw_engines_draw_background(void)
}
/* No draw_background found, doing default background */
- DRW_draw_background();
+ if (DRW_state_draw_background()) {
+ DRW_draw_background();
+ }
}
static void drw_engines_draw_scene(void)
@@ -3244,6 +3308,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
ARegion *ar = update_ctx->ar;
View3D *v3d = update_ctx->v3d;
RegionView3D *rv3d = ar->regiondata;
+ Depsgraph *depsgraph = update_ctx->depsgraph;
Scene *scene = update_ctx->scene;
ViewLayer *view_layer = update_ctx->view_layer;
@@ -3257,7 +3322,8 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
DST.viewport = rv3d->viewport;
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph,
+ NULL,
};
drw_engines_enable(scene, view_layer, engine_type);
@@ -3293,6 +3359,7 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id)
ARegion *ar = update_ctx->ar;
View3D *v3d = update_ctx->v3d;
RegionView3D *rv3d = ar->regiondata;
+ Depsgraph *depsgraph = update_ctx->depsgraph;
Scene *scene = update_ctx->scene;
ViewLayer *view_layer = update_ctx->view_layer;
if (rv3d->viewport == NULL) {
@@ -3302,7 +3369,7 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id)
memset(&DST, 0x0, sizeof(DST));
DST.viewport = rv3d->viewport;
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, NULL,
};
drw_engines_enable(scene, view_layer, engine_type);
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
@@ -3328,14 +3395,14 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id)
* for each relevant engine / mode engine. */
void DRW_draw_view(const bContext *C)
{
- struct Depsgraph *graph = CTX_data_depsgraph(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
RenderEngineType *engine_type = CTX_data_engine_type(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
/* Reset before using it. */
memset(&DST, 0x0, sizeof(DST));
- DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, C);
+ DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, C);
}
/**
@@ -3343,13 +3410,13 @@ void DRW_draw_view(const bContext *C)
* Need to reset DST before calling this function
*/
void DRW_draw_render_loop_ex(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *ar, View3D *v3d,
const bContext *evil_C)
{
- Scene *scene = DEG_get_evaluated_scene(graph);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = ar->regiondata;
DST.draw_ctx.evil_C = evil_C;
@@ -3361,7 +3428,7 @@ void DRW_draw_render_loop_ex(
GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash());
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph,
/* reuse if caller sets */
DST.draw_ctx.evil_C,
@@ -3378,18 +3445,16 @@ void DRW_draw_render_loop_ex(
/* Init engines */
drw_engines_init();
- /* TODO : tag to refresh by the deps graph */
- /* ideally only refresh when objects are added/removed */
- /* or render properties / materials change */
+ /* Cache filling */
{
PROFILE_START(stime);
drw_engines_cache_init();
- DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL);
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get())
{
drw_engines_cache_populate(ob);
}
- DEG_OBJECT_ITER_END
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
drw_engines_cache_finish();
PROFILE_END_ACCUM(DST.cache_time, stime);
@@ -3399,6 +3464,7 @@ void DRW_draw_render_loop_ex(
/* Start Drawing */
DRW_state_reset();
+
drw_engines_draw_background();
/* WIP, single image drawn over the camera view (replace) */
@@ -3413,10 +3479,8 @@ void DRW_draw_render_loop_ex(
}
}
- extern void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame);
if (do_bg_image) {
- view3d_draw_bgpic_test(scene, ar, v3d, false, true);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true);
}
@@ -3439,16 +3503,20 @@ void DRW_draw_render_loop_ex(
if (DST.draw_ctx.evil_C) {
/* needed so manipulator isn't obscured */
glDisable(GL_DEPTH_TEST);
- DRW_draw_manipulator();
- glEnable(GL_DEPTH_TEST);
+ DRW_draw_manipulator_3d();
DRW_draw_region_info();
+
+ /* Draw 2D after region info so we can draw on top of the camera passepartout overlay.
+ * 'DRW_draw_region_info' sets the projection in pixel-space. */
+ DRW_draw_manipulator_2d();
+ glEnable(GL_DEPTH_TEST);
}
DRW_stats_reset();
if (do_bg_image) {
- view3d_draw_bgpic_test(scene, ar, v3d, true, true);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, true);
}
if (G.debug_value > 20) {
@@ -3468,21 +3536,23 @@ void DRW_draw_render_loop_ex(
}
void DRW_draw_render_loop(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
ARegion *ar, View3D *v3d)
{
/* Reset before using it. */
memset(&DST, 0x0, sizeof(DST));
- Scene *scene = DEG_get_evaluated_scene(graph);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
- DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL);
+ DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, NULL);
}
+/* @viewport CAN be NULL, in this case we create one. */
void DRW_draw_render_loop_offscreen(
- struct Depsgraph *graph, RenderEngineType *engine_type,
- ARegion *ar, View3D *v3d, GPUOffScreen *ofs)
+ struct Depsgraph *depsgraph, RenderEngineType *engine_type,
+ ARegion *ar, View3D *v3d, const bool draw_background, GPUOffScreen *ofs,
+ GPUViewport *viewport)
{
RegionView3D *rv3d = ar->regiondata;
@@ -3490,20 +3560,28 @@ void DRW_draw_render_loop_offscreen(
void *backup_viewport = rv3d->viewport;
{
/* backup (_never_ use rv3d->viewport) */
- rv3d->viewport = GPU_viewport_create_from_offscreen(ofs);
+ if (viewport == NULL) {
+ rv3d->viewport = GPU_viewport_create_from_offscreen(ofs);
+ }
+ else {
+ rv3d->viewport = viewport;
+ }
}
/* Reset before using it. */
memset(&DST, 0x0, sizeof(DST));
DST.options.is_image_render = true;
- DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL);
+ DST.options.draw_background = draw_background;
+ DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, NULL);
/* restore */
{
- /* don't free data owned by 'ofs' */
- GPU_viewport_clear_from_offscreen(rv3d->viewport);
- GPU_viewport_free(rv3d->viewport);
- MEM_freeN(rv3d->viewport);
+ if (viewport == NULL) {
+ /* don't free data owned by 'ofs' */
+ GPU_viewport_clear_from_offscreen(rv3d->viewport);
+ GPU_viewport_free(rv3d->viewport);
+ MEM_freeN(rv3d->viewport);
+ }
rv3d->viewport = backup_viewport;
}
@@ -3512,17 +3590,81 @@ void DRW_draw_render_loop_offscreen(
GPU_offscreen_bind(ofs, false);
}
+void DRW_render_to_image(RenderEngine *re, struct Depsgraph *depsgraph)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RenderEngineType *engine_type = re->type;
+ DrawEngineType *draw_engine_type = engine_type->draw_engine;
+ RenderData *r = &scene->r;
+
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+ DST.options.is_image_render = true;
+
+ DST.draw_ctx = (DRWContextState){
+ NULL, NULL, NULL, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, NULL
+ };
+
+ DST.viewport = GPU_viewport_create();
+ const int size[2] = {(r->size * r->xsch) / 100, (r->size * r->ysch) / 100};
+ GPU_viewport_size_set(DST.viewport, size);
+
+ drw_viewport_var_init();
+
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine_type);
+
+ /* set default viewport */
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
+ glViewport(0, 0, size[0], size[1]);
+
+ engine_type->draw_engine->render_to_image(data, re, depsgraph);
+
+ /* TODO grease pencil */
+
+ GPU_viewport_free(DST.viewport);
+ MEM_freeN(DST.viewport);
+
+ DRW_state_reset();
+ /* FIXME GL_DEPTH_TEST is enabled by default but it seems
+ * to trigger some bad behaviour / artifacts if it's turned
+ * on at this point. */
+ glDisable(GL_DEPTH_TEST);
+
+ /* Restore Drawing area. */
+ gpuPopAttrib();
+ glEnable(GL_SCISSOR_TEST);
+ GPU_framebuffer_restore();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ memset(&DST, 0xFF, sizeof(DST));
+#endif
+}
+
+void DRW_render_object_iter(
+ void *vedata, RenderEngine *engine, struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
+{
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get())
+ {
+ callback(vedata, ob, engine, depsgraph);
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
+}
+
/**
* object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing).
*/
void DRW_draw_select_loop(
- struct Depsgraph *graph,
+ struct Depsgraph *depsgraph,
ARegion *ar, View3D *v3d,
bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect)
{
- Scene *scene = DEG_get_evaluated_scene(graph);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
#ifndef USE_GPU_SELECT
UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
#else
@@ -3573,7 +3715,7 @@ void DRW_draw_select_loop(
/* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, (bContext *)NULL,
};
drw_viewport_var_init();
@@ -3584,7 +3726,7 @@ void DRW_draw_select_loop(
/* Init engines */
drw_engines_init();
- /* TODO : tag to refresh by the deps graph */
+ /* TODO : tag to refresh by the dependency graph */
/* ideally only refresh when objects are added/removed */
/* or render properties / materials change */
if (cache_is_dirty) {
@@ -3594,7 +3736,10 @@ void DRW_draw_select_loop(
drw_engines_cache_populate(scene->obedit);
}
else {
- DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_DUPLI)
+ DEG_OBJECT_ITER(depsgraph, ob, DRW_iterator_mode_get(),
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
{
if ((ob->base_flag & BASE_SELECTABLED) != 0) {
DRW_select_load_id(ob->select_color);
@@ -3634,12 +3779,12 @@ void DRW_draw_select_loop(
* object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
*/
void DRW_draw_depth_loop(
- Depsgraph *graph,
+ Depsgraph *depsgraph,
ARegion *ar, View3D *v3d)
{
- Scene *scene = DEG_get_evaluated_scene(graph);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = ar->regiondata;
/* backup (_never_ use rv3d->viewport) */
@@ -3669,7 +3814,7 @@ void DRW_draw_depth_loop(
/* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, (bContext *)NULL,
};
drw_viewport_var_init();
@@ -3680,17 +3825,17 @@ void DRW_draw_depth_loop(
/* Init engines */
drw_engines_init();
- /* TODO : tag to refresh by the deps graph */
+ /* TODO : tag to refresh by the dependency graph */
/* ideally only refresh when objects are added/removed */
/* or render properties / materials change */
if (cache_is_dirty) {
drw_engines_cache_init();
- DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL)
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get())
{
drw_engines_cache_populate(ob);
}
- DEG_OBJECT_ITER_END
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
drw_engines_cache_finish();
}
@@ -3736,7 +3881,7 @@ void DRW_state_dfdy_factors_get(float dfdyfac[2])
*/
bool DRW_state_is_fbo(void)
{
- return (DST.default_framebuffer != NULL);
+ return ((DST.default_framebuffer != NULL) || DST.options.is_image_render);
}
/**
@@ -3772,6 +3917,15 @@ bool DRW_state_is_scene_render(void)
}
/**
+ * Gives you the iterator mode to use for depsgraph.
+ */
+eDepsObjectIteratorMode DRW_iterator_mode_get(void)
+{
+ return DRW_state_is_scene_render() ? DEG_ITER_OBJECT_MODE_RENDER :
+ DEG_ITER_OBJECT_MODE_VIEWPORT;
+}
+
+/**
* Should text draw in this mode?
*/
bool DRW_state_show_text(void)
@@ -3793,6 +3947,17 @@ bool DRW_state_draw_support(void)
((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0);
}
+/**
+ * Whether we should render the background
+ */
+bool DRW_state_draw_background(void)
+{
+ if (DRW_state_is_image_render() == false) {
+ return true;
+ }
+ return DST.options.draw_background;
+}
+
/** \} */
@@ -3814,6 +3979,11 @@ const DRWContextState *DRW_context_state_get(void)
/** \name Init/Exit (DRW_engines)
* \{ */
+bool DRW_engine_render_support(DrawEngineType *draw_engine_type)
+{
+ return draw_engine_type->render_to_image;
+}
+
void DRW_engine_register(DrawEngineType *draw_engine_type)
{
BLI_addtail(&DRW_engines, draw_engine_type);
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
index 474d6ac8769..391c29e511f 100644
--- a/source/blender/draw/intern/draw_view.c
+++ b/source/blender/draw/intern/draw_view.c
@@ -715,16 +715,13 @@ void DRW_draw_cursor(void)
/* **************************** 3D Manipulator ******************************** */
-void DRW_draw_manipulator(void)
+void DRW_draw_manipulator_3d(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
View3D *v3d = draw_ctx->v3d;
v3d->zbuf = false;
ARegion *ar = draw_ctx->ar;
-
- /* TODO, only draws 3D manipulators right now, need to see how 2D drawing will work in new viewport */
-
/* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */
/* TODO depth culling manipulators is not yet supported, just drawing _3D here, should
* later become _IN_SCENE (and draw _3D separate) */
@@ -732,25 +729,18 @@ void DRW_draw_manipulator(void)
ar->manipulator_map, draw_ctx->evil_C,
WM_MANIPULATORMAP_DRAWSTEP_3D);
- /* We may want to split this into a separate pass.
- * or maintain a stage in the draw manager where all pixel-space drawing happens. */
- {
- float original_proj[4][4];
- gpuGetProjectionMatrix(original_proj);
- wmOrtho2_region_pixelspace(ar);
-
- gpuPushMatrix();
- gpuLoadIdentity();
-
- glDepthMask(GL_FALSE);
+}
- WM_manipulatormap_draw(
- ar->manipulator_map, draw_ctx->evil_C,
- WM_MANIPULATORMAP_DRAWSTEP_2D);
+void DRW_draw_manipulator_2d(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ v3d->zbuf = false;
+ ARegion *ar = draw_ctx->ar;
- glDepthMask(GL_TRUE);
+ WM_manipulatormap_draw(
+ ar->manipulator_map, draw_ctx->evil_C,
+ WM_MANIPULATORMAP_DRAWSTEP_2D);
- gpuPopMatrix();
- gpuLoadProjectionMatrix(original_proj);
- }
+ glDepthMask(GL_TRUE);
}
diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h
index b400ceeffa2..203420483a7 100644
--- a/source/blender/draw/intern/draw_view.h
+++ b/source/blender/draw/intern/draw_view.h
@@ -30,6 +30,7 @@ void DRW_draw_grid(void);
void DRW_draw_region_info(void);
void DRW_draw_background(void);
void DRW_draw_cursor(void);
-void DRW_draw_manipulator(void);
+void DRW_draw_manipulator_3d(void);
+void DRW_draw_manipulator_2d(void);
-#endif /* __DRAW_VIEW_H__ */ \ No newline at end of file
+#endif /* __DRAW_VIEW_H__ */
diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c
index 4deb4f86692..3c0c33b1daa 100644
--- a/source/blender/draw/modes/edit_armature_mode.c
+++ b/source/blender/draw/modes/edit_armature_mode.c
@@ -154,4 +154,5 @@ DrawEngineType draw_engine_edit_armature_type = {
NULL,
&EDIT_ARMATURE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index 1ecf1a60a35..54a1bd79572 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -45,10 +45,12 @@ extern struct GlobalsUboStorage ts; /* draw_common.c */
extern char datatoc_common_globals_lib_glsl[];
extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[];
extern char datatoc_edit_curve_overlay_frag_glsl[];
+extern char datatoc_edit_curve_overlay_handle_geom_glsl[];
extern char datatoc_gpu_shader_3D_vert_glsl[];
extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
/* *********** LISTS *********** */
/* All lists are per viewport specific datas.
@@ -158,7 +160,11 @@ static void EDIT_CURVE_engine_init(void *vedata)
}
if (!e_data.overlay_edge_sh) {
- e_data.overlay_edge_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ e_data.overlay_edge_sh = DRW_shader_create_with_lib(
+ datatoc_edit_curve_overlay_loosevert_vert_glsl,
+ datatoc_edit_curve_overlay_handle_geom_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
}
if (!e_data.overlay_vert_sh) {
@@ -182,27 +188,36 @@ static void EDIT_CURVE_cache_init(void *vedata)
}
{
+ DRWShadingGroup *grp;
+
/* Center-Line (wire) */
psl->wire_pass = DRW_pass_create(
"Curve Wire",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE);
- stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+
+ grp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorWireEdit, 1);
+ stl->g_data->wire_shgrp = grp;
- /* TODO: following handle theme colors,
- * For now use overlay vert shader for handles (we want them colored):
- * TH_NURB_ULINE, TH_NURB_SEL_ULINE, TH_HANDLE_* */
psl->overlay_edge_pass = DRW_pass_create(
"Curve Handle Overlay",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_WIRE);
- /* TODO: following handle theme colors,
- * For now use overlay vert shader for handles (we want them colored) */
- stl->g_data->overlay_edge_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_edge_pass);
+
+ grp = DRW_shgroup_create(e_data.overlay_edge_sh, psl->overlay_edge_pass);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ stl->g_data->overlay_edge_shgrp = grp;
+
psl->overlay_vert_pass = DRW_pass_create(
"Curve Vert Overlay",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT);
- stl->g_data->overlay_vert_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass);
+
+ grp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ stl->g_data->overlay_vert_shgrp = grp;
}
}
@@ -293,7 +308,8 @@ static void EDIT_CURVE_draw_scene(void *vedata)
* Mostly used for freeing shaders */
static void EDIT_CURVE_engine_free(void)
{
- // DRW_SHADER_FREE_SAFE(custom_shader);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_edge_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
}
/* Create collection settings here.
@@ -331,4 +347,5 @@ DrawEngineType draw_engine_edit_curve_type = {
NULL, /* draw_background but not needed by mode engines */
&EDIT_CURVE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c
index ff4c557326e..e676677ff97 100644
--- a/source/blender/draw/modes/edit_lattice_mode.c
+++ b/source/blender/draw/modes/edit_lattice_mode.c
@@ -294,4 +294,5 @@ DrawEngineType draw_engine_edit_lattice_type = {
NULL, /* draw_background but not needed by mode engines */
&EDIT_LATTICE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index 1a8c03e3933..29ba658f79d 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -610,4 +610,5 @@ DrawEngineType draw_engine_edit_mesh_type = {
NULL,
&EDIT_MESH_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c
index a83f5ae33bc..78ceaf8b6f1 100644
--- a/source/blender/draw/modes/edit_metaball_mode.c
+++ b/source/blender/draw/modes/edit_metaball_mode.c
@@ -248,4 +248,5 @@ DrawEngineType draw_engine_edit_metaball_type = {
NULL, /* draw_background but not needed by mode engines */
&EDIT_METABALL_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c
index 4e60c4abff5..8f0371925db 100644
--- a/source/blender/draw/modes/edit_surface_mode.c
+++ b/source/blender/draw/modes/edit_surface_mode.c
@@ -266,4 +266,5 @@ DrawEngineType draw_engine_edit_surface_type = {
NULL, /* draw_background but not needed by mode engines */
&EDIT_SURFACE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c
index b375bad84b5..60f28d89f4b 100644
--- a/source/blender/draw/modes/edit_text_mode.c
+++ b/source/blender/draw/modes/edit_text_mode.c
@@ -309,4 +309,5 @@ DrawEngineType draw_engine_edit_text_type = {
NULL, /* draw_background but not needed by mode engines */
&EDIT_TEXT_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 91b64818eff..f27f41c3d2a 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -61,6 +61,8 @@
#include "draw_manager_text.h"
#include "draw_common.h"
+#include "DEG_depsgraph_query.h"
+
extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
extern struct GPUTexture *globals_ramp; /* draw_common.c */
extern GlobalsUboStorage ts;
@@ -74,11 +76,11 @@ extern char datatoc_object_empty_image_frag_glsl[];
extern char datatoc_object_empty_image_vert_glsl[];
extern char datatoc_object_lightprobe_grid_vert_glsl[];
extern char datatoc_object_particle_prim_vert_glsl[];
-extern char datatoc_object_particle_prim_frag_glsl[];
extern char datatoc_object_particle_dot_vert_glsl[];
extern char datatoc_object_particle_dot_frag_glsl[];
extern char datatoc_common_globals_lib_glsl[];
extern char datatoc_common_fxaa_lib_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
@@ -184,6 +186,7 @@ typedef struct OBJECT_PrivateData {
/* Camera */
DRWShadingGroup *camera;
+ DRWShadingGroup *camera_frame;
DRWShadingGroup *camera_tria;
DRWShadingGroup *camera_focus;
DRWShadingGroup *camera_clip;
@@ -328,12 +331,12 @@ static void OBJECT_engine_init(void *vedata)
if (!e_data.part_prim_sh) {
e_data.part_prim_sh = DRW_shader_create(
- datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl, NULL);
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL);
}
if (!e_data.part_axis_sh) {
e_data.part_axis_sh = DRW_shader_create(
- datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl,
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl,
"#define USE_AXIS\n");
}
@@ -506,8 +509,14 @@ static void OBJECT_engine_init(void *vedata)
e_data.zneg_flag = e_data.zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
}
- float dist = (rv3d->persp == RV3D_CAMOB && v3d->camera)
- ? ((Camera *)v3d->camera)->clipend : v3d->far;
+ float dist;
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ dist = ((Camera *)camera_object)->clipend;
+ }
+ else {
+ dist = v3d->far;
+ }
e_data.grid_settings[0] = dist / 2.0f; /* gridDistance */
e_data.grid_settings[1] = grid_res; /* gridResolution */
@@ -749,8 +758,9 @@ static void OBJECT_cache_init(void *vedata)
DRWState state = DRW_STATE_WRITE_COLOR;
struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
static float alphaOcclu = 0.35f;
- static bool bTrue = true;
- static bool bFalse = false;
+ /* Reminder : bool uniforms need to be 4 bytes. */
+ static const int bTrue = true;
+ static const int bFalse = false;
psl->outlines_search = DRW_pass_create("Outlines Detect Pass", state);
@@ -920,6 +930,9 @@ static void OBJECT_cache_init(void *vedata)
geom = DRW_cache_camera_get();
stl->g_data->camera = shgroup_camera_instance(psl->non_meshes, geom);
+ geom = DRW_cache_camera_frame_get();
+ stl->g_data->camera_frame = shgroup_camera_instance(psl->non_meshes, geom);
+
geom = DRW_cache_camera_tria_get();
stl->g_data->camera_tria = shgroup_camera_instance(psl->non_meshes, geom);
@@ -977,6 +990,7 @@ static void OBJECT_cache_init(void *vedata)
geom = DRW_cache_lamp_get();
stl->g_data->lamp_circle = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle);
+ geom = DRW_cache_lamp_shadows_get();
stl->g_data->lamp_circle_shadow = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircleShadow);
geom = DRW_cache_lamp_sunrays_get();
@@ -1110,15 +1124,22 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie
int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
static float zero = 0.0f;
- float **la_mats = (float **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL);
- if (*la_mats == NULL) {
- /* we need 2 matrices */
- *la_mats = MEM_mallocN(sizeof(float) * 16 * 2, "Lamp Object Mode Matrices");
- }
+ typedef struct LampEngineData {
+ ObjectEngineData engine_data;
+ float shape_mat[4][4];
+ float spot_blend_mat[4][4];
+ } LampEngineData;
+
+ LampEngineData *lamp_engine_data =
+ (LampEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_object_type,
+ sizeof(LampEngineData),
+ NULL,
+ NULL);
- float (*shapemat)[4], (*spotblendmat)[4];
- shapemat = (float (*)[4])(*la_mats);
- spotblendmat = (float (*)[4])(*la_mats + 16);
+ float (*shapemat)[4] = lamp_engine_data->shape_mat;
+ float (*spotblendmat)[4] = lamp_engine_data->spot_blend_mat;
/* Don't draw the center if it's selected or active */
if (theme_id == TH_GROUP)
@@ -1213,9 +1234,11 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v
const DRWContextState *draw_ctx = DRW_context_state_get();
View3D *v3d = draw_ctx->v3d;
Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
Camera *cam = ob->data;
const bool is_active = (ob == v3d->camera);
+ const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
float *color;
DRW_object_wire_theme_get(ob, view_layer, &color);
@@ -1228,7 +1251,7 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v
BKE_camera_view_frame_ex(scene, cam, cam->drawsize, false, scale,
asp, shift, &drawsize, vec);
- // /* Frame coords */
+ /* Frame coords */
copy_v2_v2(cam->drwcorners[0], vec[0]);
copy_v2_v2(cam->drwcorners[1], vec[1]);
copy_v2_v2(cam->drwcorners[2], vec[2]);
@@ -1243,13 +1266,23 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v
cam->drwtria[1][0] = shift[0];
cam->drwtria[1][1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
- DRW_shgroup_call_dynamic_add(stl->g_data->camera, color, cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
-
- /* Active cam */
- if (is_active) {
+ if (look_through) {
+ /* Only draw the frame. */
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_frame, color, cam->drwcorners,
+ &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
+ else {
DRW_shgroup_call_dynamic_add(
- stl->g_data->camera_tria, color,
- cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
+ stl->g_data->camera, color, cam->drwcorners,
+ &cam->drwdepth, cam->drwtria, ob->obmat);
+
+ /* Active cam */
+ if (is_active) {
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_tria, color,
+ cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
}
/* draw the rest in normalize object space */
@@ -1455,13 +1488,13 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0);
DRW_object_wire_theme_get(ob, view_layer, &color);
- OBJECT_LightProbeEngineData *prb_data;
- OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL);
- if (*prb_data_pt == NULL) {
- *prb_data_pt = MEM_mallocN(sizeof(OBJECT_LightProbeEngineData), "Probe Clip distances Matrices");
- }
-
- prb_data = *prb_data_pt;
+ OBJECT_LightProbeEngineData *prb_data =
+ (OBJECT_LightProbeEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_object_type,
+ sizeof(OBJECT_LightProbeEngineData),
+ NULL,
+ NULL);
if ((DRW_state_is_select() || do_outlines) && ((prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) != 0)) {
@@ -1499,9 +1532,6 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
sub_v3_v3(prb_data->increment_z, prb_data->corner);
DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.lightprobe_grid_sh, psl->lightprobes, DRW_cache_sphere_get());
- /* Dummy call just to save select ID */
- DRW_shgroup_call_dynamic_add_empty(grp);
- /* Then overide the instance count */
DRW_shgroup_set_instance_count(grp, prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z);
DRW_shgroup_uniform_vec4(grp, "color", color, 1);
DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
@@ -1648,7 +1678,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
static void DRW_shgroup_relationship_lines(OBJECT_StorageList *stl, Object *ob)
{
- if (ob->parent && BKE_object_is_visible(ob->parent)) {
+ if (ob->parent && DRW_check_object_visible_within_active_context(ob->parent)) {
DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->obmat[3]);
DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->parent->obmat[3]);
}
@@ -1763,7 +1793,12 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
View3D *v3d = draw_ctx->v3d;
int theme_id = TH_UNDEFINED;
- if (!BKE_object_is_visible(ob)) {
+ /* Handle particles first in case the emitter itself shouldn't be rendered. */
+ if (ob->type == OB_MESH) {
+ OBJECT_cache_populate_particles(ob, psl);
+ }
+
+ if (DRW_check_object_visible_within_active_context(ob) == false) {
return;
}
@@ -1804,8 +1839,6 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
}
}
}
-
- OBJECT_cache_populate_particles(ob, psl);
break;
}
case OB_SURF:
@@ -2011,4 +2044,5 @@ DrawEngineType draw_engine_object_type = {
NULL,
&OBJECT_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c
index b49da0cba2f..2a5eabd08fa 100644
--- a/source/blender/draw/modes/paint_texture_mode.c
+++ b/source/blender/draw/modes/paint_texture_mode.c
@@ -414,4 +414,5 @@ DrawEngineType draw_engine_paint_texture_type = {
NULL, /* draw_background but not needed by mode engines */
&PAINT_TEXTURE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c
index e430fca5742..835fefdee26 100644
--- a/source/blender/draw/modes/paint_vertex_mode.c
+++ b/source/blender/draw/modes/paint_vertex_mode.c
@@ -213,4 +213,5 @@ DrawEngineType draw_engine_paint_vertex_type = {
NULL,
&PAINT_VERTEX_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c
index e139b4af97f..3cc2ad63ed4 100644
--- a/source/blender/draw/modes/paint_weight_mode.c
+++ b/source/blender/draw/modes/paint_weight_mode.c
@@ -251,4 +251,5 @@ DrawEngineType draw_engine_paint_weight_type = {
NULL,
&PAINT_WEIGHT_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
index 6a3e53a72c2..0d0758971d5 100644
--- a/source/blender/draw/modes/particle_mode.c
+++ b/source/blender/draw/modes/particle_mode.c
@@ -261,4 +261,5 @@ DrawEngineType draw_engine_particle_type = {
NULL, /* draw_background but not needed by mode engines */
&PARTICLE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
index 1c2acd56085..560773f2d05 100644
--- a/source/blender/draw/modes/pose_mode.c
+++ b/source/blender/draw/modes/pose_mode.c
@@ -195,4 +195,5 @@ DrawEngineType draw_engine_pose_type = {
NULL,
&POSE_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
index d9f1f5ebe91..d8c5bae522b 100644
--- a/source/blender/draw/modes/sculpt_mode.c
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -302,4 +302,5 @@ DrawEngineType draw_engine_sculpt_type = {
NULL, /* draw_background but not needed by mode engines */
&SCULPT_draw_scene,
NULL,
+ NULL,
};
diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl
index dc36d252926..0c14c1e7db0 100644
--- a/source/blender/draw/modes/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl
@@ -37,6 +37,20 @@ layout(std140) uniform globalsBlock {
vec4 colorBackground;
+ vec4 colorHandleFree;
+ vec4 colorHandleAuto;
+ vec4 colorHandleVect;
+ vec4 colorHandleAlign;
+ vec4 colorHandleAutoclamp;
+ vec4 colorHandleSelFree;
+ vec4 colorHandleSelAuto;
+ vec4 colorHandleSelVect;
+ vec4 colorHandleSelAlign;
+ vec4 colorHandleSelAutoclamp;
+ vec4 colorNurbUline;
+ vec4 colorNurbSelUline;
+ vec4 colorActiveSpline;
+
vec4 colorGrid;
vec4 colorGridEmphasise;
vec4 colorGridAxisX;
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
new file mode 100644
index 00000000000..419a25f91b4
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
@@ -0,0 +1,79 @@
+
+#define ACTIVE_NURB 1 << 7 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
+
+layout(lines) in;
+layout(line_strip, max_vertices = 6) out;
+
+uniform vec2 viewportSize;
+
+flat in int vertFlag[];
+
+flat out vec4 finalColor;
+
+void main()
+{
+ /* TODO: vertex size */
+
+ vec4 v1 = gl_in[0].gl_Position;
+ vec4 v2 = gl_in[1].gl_Position;
+
+ int is_active_nurb = vertFlag[1] & ACTIVE_NURB;
+ int color_id = vertFlag[1] ^ is_active_nurb;
+
+ if (is_active_nurb != 0) {
+ /* draw the outline. */
+ vec2 v1_2 = v2.xy - v1.xy;
+ vec2 offset;
+
+ if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) {
+ offset = vec2(2.0 / viewportSize.x, 0.0);
+ }
+ else {
+ offset = vec2(0.0, 2.0 / viewportSize.y);
+ }
+
+ finalColor = colorActiveSpline;
+
+ gl_Position = v1;
+ gl_Position.xy += offset * v1.w;
+ EmitVertex();
+
+ gl_Position = v2;
+ gl_Position.xy += offset * v2.w;
+ EmitVertex();
+
+ EndPrimitive();
+
+ gl_Position = v1;
+ gl_Position.xy -= offset * v1.w;
+ EmitVertex();
+
+ gl_Position = v2;
+ gl_Position.xy -= offset * v2.w;
+ EmitVertex();
+
+ EndPrimitive();
+ }
+
+ if (color_id == 0) finalColor = colorHandleFree;
+ else if (color_id == 1) finalColor = colorHandleAuto;
+ else if (color_id == 2) finalColor = colorHandleVect;
+ else if (color_id == 3) finalColor = colorHandleAlign;
+ else if (color_id == 4) finalColor = colorHandleAutoclamp;
+ else if (color_id == 5) finalColor = colorHandleSelFree;
+ else if (color_id == 6) finalColor = colorHandleSelAuto;
+ else if (color_id == 7) finalColor = colorHandleSelVect;
+ else if (color_id == 8) finalColor = colorHandleSelAlign;
+ else if (color_id == 9) finalColor = colorHandleSelAutoclamp;
+ else if (color_id == 10) finalColor = colorNurbUline;
+ else if (color_id == 11) finalColor = colorNurbSelUline;
+ else finalColor = colorVertexSelect;
+
+ gl_Position = v1;
+ EmitVertex();
+
+ gl_Position = v2;
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
index 049333c8e4f..23b794d9b8b 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
@@ -10,7 +10,7 @@ flat in int faceActive;
out vec4 FragColor;
-const mat4 stipple_matrix = mat4(
+const vec4 stipple_matrix[4] = vec4[4](
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
index ed7421c1b1d..cf1051b70b3 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
@@ -5,12 +5,16 @@
/* This shader follows the principles of
* http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+/* This is not perfect. Only a subset of intel gpus are affected.
+ * This fix have some performance impact.
+ * TODO Refine the range to only affect GPUs. */
+
uniform float faceAlphaMod;
flat in vec3 edgesCrease;
flat in vec3 edgesBweight;
-flat in ivec3 flag;
flat in vec4 faceColor;
+flat in ivec3 flag;
flat in int clipCase;
#ifdef VERTEX_SELECTION
in vec3 vertexColor;
@@ -28,16 +32,16 @@ in float facing;
* in the first 2 components of the first vec4.
* This needs noperspective interpolation.
* The rest is filled with vertex screen positions.
- * eData1.zw actually contain v2
- * eData2.xy actually contain v1
- * eData2.zw actually contain v0
+ * eData2[0] actually contain v2
+ * eData2[1] actually contain v1
+ * eData2[2] actually contain v0
*
* - Hard case : two 2d edge corner are described by each
* vec4 as origin and direction. This is constant over
* the triangle and use to detect the correct case. */
-noperspective in vec4 eData1;
-flat in vec4 eData2;
+noperspective in vec2 eData1;
+flat in vec2 eData2[3];
out vec4 FragColor;
@@ -72,7 +76,7 @@ const ivec3 clipPointIdx[6] = ivec3[6](
ivec3(2, 1, 0)
);
-const mat4 stipple_matrix = mat4(
+const vec4 stipple_matrix[4] = vec4[4](
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
@@ -107,34 +111,34 @@ void main()
/* Step 1 : Computing Distances */
if (clipCase == 0) {
- e.xy = eData1.xy;
+ e.xy = eData1;
/* computing missing distance */
- vec2 dir = normalize(eData2.zw - eData2.xy);
- e.z = distToEdge(eData2.zw, dir);
+ vec2 dir = normalize(eData2[2] - eData2[1]);
+ e.z = distToEdge(eData2[2], dir);
- p.x = distance(eData2.zw, gl_FragCoord.xy);
- p.y = distance(eData2.xy, gl_FragCoord.xy);
- p.z = distance(eData1.zw, gl_FragCoord.xy);
+ p.x = distance(eData2[2], gl_FragCoord.xy);
+ p.y = distance(eData2[1], gl_FragCoord.xy);
+ p.z = distance(eData2[0], gl_FragCoord.xy);
}
else {
ivec3 eidxs = clipEdgeIdx[clipCase - 1];
ivec3 pidxs = clipPointIdx[clipCase - 1];
- e[eidxs.x] = distToEdge(eData1.xy, eData1.zw);
- e[eidxs.y] = distToEdge(eData2.xy, eData2.zw);
+ e[eidxs.x] = distToEdge(eData1, eData2[0]);
+ e[eidxs.y] = distToEdge(eData2[1], eData2[2]);
/* Three edges visible cases */
if (clipCase == 1 || clipCase == 2 || clipCase == 4) {
- e[eidxs.z] = distToEdge(eData1.xy, normalize(eData2.xy - eData1.xy));
- p[pidxs.y] = distance(eData2.xy, gl_FragCoord.xy);
+ e[eidxs.z] = distToEdge(eData1, normalize(eData2[1] - eData1));
+ p[pidxs.y] = distance(eData2[1], gl_FragCoord.xy);
}
else {
e[eidxs.z] = 1e10; /* off screen */
p[pidxs.y] = 1e10; /* off screen */
}
- p[pidxs.x] = distance(eData1.xy, gl_FragCoord.xy);
+ p[pidxs.x] = distance(eData1, gl_FragCoord.xy);
p[pidxs.z] = 1e10; /* off screen */
}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
index 7d71e1540d5..77bc8a25695 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
@@ -22,8 +22,8 @@ in float vFacing[];
* and does not need interpolation */
flat out vec3 edgesCrease;
flat out vec3 edgesBweight;
-flat out ivec3 flag;
flat out vec4 faceColor;
+flat out ivec3 flag;
flat out int clipCase;
#ifdef VERTEX_SELECTION
out vec3 vertexColor;
@@ -33,8 +33,8 @@ out float facing;
#endif
/* See fragment shader */
-noperspective out vec4 eData1;
-flat out vec4 eData2;
+noperspective out vec2 eData1;
+flat out vec2 eData2[3];
#define VERTEX_ACTIVE (1 << 0)
#define VERTEX_SELECTED (1 << 1)
@@ -128,9 +128,10 @@ void main()
}
/* Edge / Vert data */
- eData1 = vec4(1e10);
- eData2.zw = pos[0];
- eData2.xy = pos[1];
+ eData1 = vec2(1e10);
+ eData2[0] = vec2(1e10);
+ eData2[2] = pos[0];
+ eData2[1] = pos[1];
flag[0] = (vData[0].x << 8);
flag[1] = (vData[1].x << 8);
flag[2] = 0;
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
index f83402e3869..d9c902697b6 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
@@ -7,6 +7,10 @@
layout(triangles) in;
+/* This is not perfect. Only a subset of intel gpus are affected.
+ * This fix have some performance impact.
+ * TODO Refine the range to only affect GPUs. */
+
#ifdef EDGE_FIX
/* To fix the edge artifacts, we render
* an outline strip around the screenspace
@@ -37,8 +41,8 @@ in float vFacing[];
* and does not need interpolation */
flat out vec3 edgesCrease;
flat out vec3 edgesBweight;
-flat out ivec3 flag;
flat out vec4 faceColor;
+flat out ivec3 flag;
flat out int clipCase;
#ifdef VERTEX_SELECTION
out vec3 vertexColor;
@@ -48,9 +52,8 @@ out float facing;
#endif
/* See fragment shader */
-noperspective out vec4 eData1;
-flat out vec4 eData2;
-
+noperspective out vec2 eData1;
+flat out vec2 eData2[3];
#define VERTEX_ACTIVE (1 << 0)
#define VERTEX_SELECTED (1 << 1)
@@ -103,7 +106,7 @@ vec4 getClipData(vec2 pos[3], ivec2 vidx)
return vec4(A, Adir);
}
-void doVertex(int v, vec4 pos)
+void doVertex(int v)
{
#ifdef VERTEX_SELECTION
vertexColor = getVertexColor(v);
@@ -113,7 +116,16 @@ void doVertex(int v, vec4 pos)
facing = vFacing[v];
#endif
- gl_Position = pos;
+ gl_Position = pPos[v];
+
+ EmitVertex();
+}
+
+void doLoopStrip(int v, vec3 offset)
+{
+ doVertex(v);
+
+ gl_Position.xyz += offset;
EmitVertex();
}
@@ -164,18 +176,19 @@ void main()
if (clipCase == 0) {
/* Packing screen positions and 2 distances */
- eData1 = vec4(0.0, 0.0, pos[2]);
- eData2 = vec4(pos[1], pos[0]);
+ eData2[0] = pos[2];
+ eData2[1] = pos[1];
+ eData2[2] = pos[0];
/* Only pass the first 2 distances */
for (int v = 0; v < 2; ++v) {
eData1[v] = dist(pos, pos[v], v);
- doVertex(v, pPos[v]);
+ doVertex(v);
eData1[v] = 0.0;
}
/* and the last vertex */
- doVertex(2, pPos[2]);
+ doVertex(2);
#ifdef EDGE_FIX
vec2 fixvec[6];
@@ -233,7 +246,8 @@ void main()
faceColor.a = 0.0;
/* we don't want other edges : make them far */
- eData1 = vec4(1e10);
+ eData1 = vec2(1e10);
+ eData2[0] = vec2(1e10);
/* Start with the same last vertex to create a
* degenerate triangle in order to "create"
@@ -244,49 +258,49 @@ void main()
int v = i % 3;
/* Position of the "hidden" third vertex */
- eData1.zw = pos[vbe];
-
- doVertex(v, pPos[v]);
- doVertex(v, pPos[v] + vec4(fixvec[v], Z_OFFSET, 0.0));
+ eData2[0] = pos[vbe];
+ doLoopStrip(v, vec3(fixvec[v], Z_OFFSET));
/* Now one triangle only shade one edge
* so we use the edge distance calculated
* in the fragment shader, the third edge;
* we do this because we need flat interp to
* draw a continuous triangle strip */
- eData2.xy = pos[vaf];
- eData2.zw = pos[v];
+ eData2[1] = pos[vaf];
+ eData2[2] = pos[v];
flag[0] = (vData[v].x << 8);
flag[1] = (vData[vaf].x << 8);
flag[2] = eflag[vbe];
edgesCrease[2] = ecrease[vbe];
edgesBweight[2] = ebweight[vbe];
- doVertex(vaf, pPos[vaf]);
- doVertex(vaf, pPos[vaf] + vec4(fixvecaf[v], Z_OFFSET, 0.0));
+ doLoopStrip(vaf, vec3(fixvecaf[v], Z_OFFSET));
/* corner vertices should not draw edges but draw point only */
flag[2] = (vData[vbe].x << 8);
#ifdef VERTEX_SELECTION
- doVertex(vaf, pPos[vaf]);
- doVertex(vaf, pPos[vaf] + vec4(cornervec[vaf], Z_OFFSET, 0.0));
+ doLoopStrip(vaf, vec3(cornervec[vaf], Z_OFFSET));
#endif
}
/* finish the loop strip */
- doVertex(2, pPos[2]);
- doVertex(2, pPos[2] + vec4(fixvec[2], Z_OFFSET, 0.0));
+ doLoopStrip(2, vec3(fixvec[2], Z_OFFSET));
#endif
}
/* Harder case : compute visible edges vectors */
else {
ivec4 vindices = clipPointsIdx[clipCase - 1];
- eData1 = getClipData(pos, vindices.xz);
- eData2 = getClipData(pos, vindices.yw);
+ vec4 tmp;
+ tmp = getClipData(pos, vindices.xz);
+ eData1 = tmp.xy;
+ eData2[0] = tmp.zw;
+ tmp = getClipData(pos, vindices.yw);
+ eData2[1] = tmp.xy;
+ eData2[2] = tmp.zw;
for (int v = 0; v < 3; ++v)
- doVertex(v, pPos[v]);
+ doVertex(v);
}
EndPrimitive();
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
index 0a396a5325f..53e5b09cb70 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
@@ -15,16 +15,16 @@ in ivec4 data;
* and does not need interpolation */
flat out vec3 edgesCrease;
flat out vec3 edgesBweight;
-flat out ivec3 flag;
flat out vec4 faceColor;
+flat out ivec3 flag;
flat out int clipCase;
#ifdef VERTEX_SELECTION
out vec3 vertexColor;
#endif
/* See fragment shader */
-noperspective out vec4 eData1;
-flat out vec4 eData2;
+noperspective out vec2 eData1;
+flat out vec2 eData2[3];
/* project to screen space */
vec2 proj(vec4 pos)
@@ -48,11 +48,13 @@ void main()
#endif
/* only vertex position 0 is used */
- eData1 = eData2 = vec4(1e10);
- eData2.zw = proj(pPos);
+ eData1 = vec2(1e10);
+ eData2[0] = vec2(1e10);
+ eData2[1] = vec2(1e10);
+ eData2[2] = proj(pPos);
- flag = ivec3(0);
flag[0] = (data.x << 8);
+ flag[1] = flag[2] = 0;
gl_PointSize = sizeEdgeFix;
gl_Position = pPos;
diff --git a/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl b/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl
deleted file mode 100644
index aa455a85cf0..00000000000
--- a/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-
-flat in vec4 finalColor;
-
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor;
-}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index afbd8e5bd41..24f6a2dab2c 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -147,7 +147,7 @@ bAction *verify_adt_action(ID *id, short add)
BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2);
/* create action */
- adt->action = add_empty_action(G.main, actname);
+ adt->action = BKE_action_add(G.main, actname);
/* set ID-type from ID-block that this is going to be assigned to
* so that users can't accidentally break actions by assigning them
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 1d63b3aee43..de2611f7092 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -126,50 +126,40 @@ typedef struct tJoinArmature_AdtFixData {
GHash *names_map;
} tJoinArmature_AdtFixData;
-/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */
+/* Callback to pass to 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)
+static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, 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;
- }
+ if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) {
+ 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);
- // 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);
- /* 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;
- }
+ /* 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) {
+ if (fcu->driver) {
ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
@@ -373,7 +363,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
}
/* Fix all the drivers (and animation data) */
- BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
+ BKE_fcurves_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,
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 4dd8e4bd6fa..f4bebfd85e0 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -929,7 +929,7 @@ static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end,
float pval[2] = {0, 0};
ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP);
- ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal, false);
+ ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, pval, ray_start, ray_normal, false);
mul_v3_fl(ray_normal, distance * progress / length);
add_v3_v3(stk->points[i].p, ray_normal);
@@ -1486,6 +1486,7 @@ static int cmpIntersections(const void *i1, const void *i2)
/* returns the maximum number of intersections per stroke */
static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
@@ -1526,7 +1527,7 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S
mval[0] = vi[0];
mval[1] = vi[1];
- ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end, true);
+ ED_view3d_win_to_segment(depsgraph, ar, v3d, mval, ray_start, ray_end, true);
isect_line_line_v3(stk->points[s_i].p,
stk->points[s_i + 1].p,
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 0dbe3ddaa0a..d89b2fcfe84 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -201,7 +201,7 @@ static bAction *poselib_init_new(Object *ob)
if (ob->poselib)
id_us_min(&ob->poselib->id);
- ob->poselib = add_empty_action(G.main, "PoseLib");
+ ob->poselib = BKE_action_add(G.main, "PoseLib");
ob->poselib->idroot = ID_OB;
return ob->poselib;
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index f808f09f1f4..9bc678cd9e6 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -156,7 +156,7 @@ bool ED_do_pose_selectbuffer(
* always give predictable behavior in weight paint mode - campbell */
if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)) {
/* when we are entering into posemode via toggle-select,
- * frop another active object - always select the bone. */
+ * from another active object - always select the bone. */
if (!extend && !deselect && toggle) {
/* re-select below */
nearBone->flag &= ~BONE_SELECTED;
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 18d6408f026..bfe365d04fd 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -158,6 +158,28 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
curbone->roll = eul[1];
}
+ /* combine pose and rest values for bendy bone settings,
+ * then clear the pchan values (so we don't get a double-up)
+ */
+ if (pchan->bone->segments > 1) {
+ curbone->curveInX += pchan->curveInX;
+ curbone->curveInY += pchan->curveInY;
+ curbone->curveOutX += pchan->curveOutX;
+ curbone->curveOutY += pchan->curveOutY;
+ curbone->roll1 += pchan->roll1;
+ curbone->roll2 += pchan->roll2;
+ curbone->ease1 += pchan->ease1;
+ curbone->ease2 += pchan->ease2;
+ curbone->scaleIn += pchan->scaleIn;
+ curbone->scaleOut += pchan->scaleOut;
+
+ pchan->curveInX = pchan->curveOutX = 0.0f;
+ pchan->curveInY = pchan->curveOutY = 0.0f;
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->ease1 = pchan->ease2 = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
+ }
+
/* clear transform values for pchan */
zero_v3(pchan->loc);
zero_v3(pchan->eul);
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 4dfd4a5c0f0..71cccdfa33d 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -241,6 +241,9 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", TABLET_STYLUS, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", AKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 79b63f36b76..4b578ba389e 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -6135,8 +6135,10 @@ int join_curve_exec(bContext *C, wmOperator *op)
cu = ob->data;
BLI_movelisttolist(&cu->nurb, &tempbase);
- /* Account for mixed 2D/3D curves when joining */
- BKE_curve_curve_dimension_update(cu);
+ if (ob->type == OB_CURVE) {
+ /* Account for mixed 2D/3D curves when joining */
+ BKE_curve_curve_dimension_update(cu);
+ }
DEG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 5a71cc39f80..062b9c94a1b 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -93,6 +93,8 @@ struct StrokeElem {
};
struct CurveDrawData {
+ const Depsgraph *depsgraph;
+
short init_event_type;
short curve_type;
@@ -199,7 +201,7 @@ static bool stroke_elem_project(
if (cdd->project.use_plane) {
/* get the view vector to 'location' */
float ray_origin[3], ray_direction[3];
- ED_view3d_win_to_ray(cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false);
+ ED_view3d_win_to_ray(cdd->depsgraph, cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false);
float lambda;
if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) {
@@ -603,6 +605,8 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+ cdd->depsgraph = CTX_data_depsgraph(C);
+
if (is_invoke) {
view3d_set_viewcontext(C, &cdd->vc);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 2a84ca7f297..65c55b6cd22 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -31,6 +31,500 @@ set(SRC
)
+# Order matches "UI_icons.h", final name will be formatted: "icons{size}_{name}.dat"
+set(ICON_NAMES
+ question
+ error
+ cancel
+ tria_right
+ tria_down
+ tria_left
+ tria_up
+ arrow_leftright
+ plus
+ disclosure_tri_down
+ disclosure_tri_right
+ radiobut_off
+ radiobut_on
+ menu_panel
+ blender
+ grip
+ dot
+ collapsemenu
+ x
+ go_left
+ plug
+ ui
+ node
+ node_sel
+ fullscreen
+ splitscreen
+ rightarrow_thin
+ bordermove
+ viewzoom
+ zoomin
+ zoomout
+ panel_close
+ copy_id
+ eyedropper
+ link_area
+ auto
+ checkbox_dehlt
+ checkbox_hlt
+ unlocked
+ locked
+ unpinned
+ pinned
+ screen_back
+ rightarrow
+ downarrow_hlt
+ dotsup
+ dotsdown
+ link
+ inlink
+ plugin
+ help
+ ghost_enabled
+ color
+ linked
+ unlinked
+ hand
+ zoom_all
+ zoom_selected
+ zoom_previous
+ zoom_in
+ zoom_out
+ render_region
+ border_rect
+ border_lasso
+ freeze
+ stylus_pressure
+ ghost_disabled
+ new
+ file_tick
+ quit
+ url
+ recover_last
+ fullscreen_enter
+ fullscreen_exit
+ lamp
+ material
+ texture
+ anim
+ world
+ scene
+ edit
+ game
+ radio
+ script
+ particles
+ physics
+ speaker
+ texture_shaded
+ view3d
+ ipo
+ oops
+ buts
+ filesel
+ image_col
+ info
+ sequence
+ text
+ imasel
+ sound
+ action
+ nla
+ scriptwin
+ time
+ nodetree
+ logic
+ console
+ preferences
+ clip
+ asset_manager
+ object_datamode
+ editmode_hlt
+ facesel_hlt
+ vpaint_hlt
+ tpaint_hlt
+ wpaint_hlt
+ sculptmode_hlt
+ pose_hlt
+ particlemode
+ lightpaint
+ greasepencil_stroke_paint
+ scene_data
+ renderlayers
+ world_data
+ object_data
+ mesh_data
+ curve_data
+ meta_data
+ lattice_data
+ lamp_data
+ material_data
+ texture_data
+ anim_data
+ camera_data
+ particle_data
+ library_data_direct
+ group
+ armature_data
+ pose_data
+ bone_data
+ constraint
+ shapekey_data
+ constraint_bone
+ camera_stereo
+ package
+ uglypackage
+ brush_data
+ image_data
+ file
+ fcurve
+ font_data
+ render_result
+ surface_data
+ empty_data
+ settings
+ render_animation
+ render_still
+ library_data_broken
+ boids
+ strands
+ library_data_indirect
+ greasepencil
+ line_data
+ library_data_override
+ group_bone
+ group_vertex
+ group_vcol
+ group_uvs
+ rna
+ rna_add
+ outliner_ob_empty
+ outliner_ob_mesh
+ outliner_ob_curve
+ outliner_ob_lattice
+ outliner_ob_meta
+ outliner_ob_lamp
+ outliner_ob_camera
+ outliner_ob_armature
+ outliner_ob_font
+ outliner_ob_surface
+ outliner_ob_speaker
+ outliner_ob_force_field
+ outliner_ob_group_instance
+ outliner_ob_greasepencil
+ restrict_color_off
+ restrict_color_on
+ restrict_view_off
+ restrict_view_on
+ restrict_select_off
+ restrict_select_on
+ restrict_render_off
+ restrict_render_on
+ outliner_data_empty
+ outliner_data_mesh
+ outliner_data_curve
+ outliner_data_lattice
+ outliner_data_meta
+ outliner_data_lamp
+ outliner_data_camera
+ outliner_data_armature
+ outliner_data_font
+ outliner_data_surface
+ outliner_data_speaker
+ outliner_data_pose
+ outliner_data_greasepencil
+ mesh_plane
+ mesh_cube
+ mesh_circle
+ mesh_uvsphere
+ mesh_icosphere
+ mesh_grid
+ mesh_monkey
+ mesh_cylinder
+ mesh_torus
+ mesh_cone
+ mesh_capsule
+ lamp_point
+ lamp_sun
+ lamp_spot
+ lamp_hemi
+ lamp_area
+ meta_empty
+ meta_plane
+ meta_cube
+ meta_ball
+ meta_ellipsoid
+ meta_capsule
+ surface_ncurve
+ surface_ncircle
+ surface_nsurface
+ surface_ncylinder
+ surface_nsphere
+ surface_ntorus
+ curve_bezcurve
+ curve_bezcircle
+ curve_ncurve
+ curve_ncircle
+ curve_path
+ color_red
+ color_green
+ color_blue
+ tria_right_bar
+ tria_down_bar
+ tria_left_bar
+ tria_up_bar
+ force_force
+ force_wind
+ force_vortex
+ force_magnetic
+ force_harmonic
+ force_charge
+ force_lennardjones
+ force_texture
+ force_curve
+ force_boid
+ force_turbulence
+ force_drag
+ force_smokeflow
+ node_insert_on
+ node_insert_off
+ modifier
+ mod_wave
+ mod_build
+ mod_decim
+ mod_mirror
+ mod_soft
+ mod_subsurf
+ hook
+ mod_physics
+ mod_particles
+ mod_boolean
+ mod_edgesplit
+ mod_array
+ mod_uvproject
+ mod_displace
+ mod_curve
+ mod_lattice
+ constraint_data
+ mod_armature
+ mod_shrinkwrap
+ mod_cast
+ mod_meshdeform
+ mod_bevel
+ mod_smooth
+ mod_simpledeform
+ mod_mask
+ mod_cloth
+ mod_explode
+ mod_fluidsim
+ mod_multires
+ mod_smoke
+ mod_solidify
+ mod_screw
+ mod_vertex_weight
+ mod_dynamicpaint
+ mod_remesh
+ mod_ocean
+ mod_warp
+ mod_skin
+ mod_triangulate
+ mod_wireframe
+ mod_data_transfer
+ mod_normaledit
+ rec
+ play
+ ff
+ rew
+ pause
+ prev_keyframe
+ next_keyframe
+ play_audio
+ play_reverse
+ preview_range
+ action_tweak
+ pmarker_act
+ pmarker_sel
+ pmarker
+ marker_hlt
+ marker
+ space2
+ space3
+ keyingset
+ key_dehlt
+ key_hlt
+ mute_ipo_off
+ mute_ipo_on
+ visible_ipo_off
+ visible_ipo_on
+ driver
+ solo_off
+ solo_on
+ frame_prev
+ frame_next
+ nla_pushdown
+ ipo_constant
+ ipo_linear
+ ipo_bezier
+ ipo_sine
+ ipo_quad
+ ipo_cubic
+ ipo_quart
+ ipo_quint
+ ipo_expo
+ ipo_circ
+ ipo_bounce
+ ipo_elastic
+ ipo_back
+ ipo_ease_in
+ ipo_ease_out
+ ipo_ease_in_out
+ normalize_fcurves
+ vertexsel
+ edgesel
+ facesel
+ loopsel
+ rotate
+ cursor
+ rotatecollection
+ rotatecenter
+ rotactive
+ align
+ smoothcurve
+ spherecurve
+ rootcurve
+ sharpcurve
+ lincurve
+ nocurve
+ rndcurve
+ prop_off
+ prop_on
+ prop_con
+ particle_point
+ particle_tip
+ particle_path
+ man_trans
+ man_rot
+ man_scale
+ manipul
+ snap_off
+ snap_on
+ snap_normal
+ snap_grid
+ snap_vertex
+ snap_edge
+ snap_face
+ snap_volume
+ snap_increment
+ sticky_uvs_loc
+ sticky_uvs_disable
+ sticky_uvs_vert
+ clipuv_dehlt
+ clipuv_hlt
+ snap_peel_object
+ grid
+ object_origin
+ pastedown
+ copydown
+ pasteflipup
+ pasteflipdown
+ snap_surface
+ automerge_on
+ automerge_off
+ retopo
+ uv_vertexsel
+ uv_edgesel
+ uv_facesel
+ uv_islandsel
+ uv_sync_select
+ bbox
+ wire
+ solid
+ smooth
+ potato
+ ortho
+ lockview_off
+ lockview_on
+ axis_side
+ axis_front
+ axis_top
+ ndof_dom
+ ndof_turn
+ ndof_fly
+ ndof_trans
+ layer_used
+ layer_active
+ sortalpha
+ sortbyext
+ sorttime
+ sortsize
+ longdisplay
+ shortdisplay
+ ghost
+ imgdisplay
+ save_as
+ save_copy
+ bookmarks
+ fontpreview
+ filter
+ newfolder
+ open_recent
+ file_parent
+ file_refresh
+ file_folder
+ file_blend
+ file_image
+ file_movie
+ file_script
+ file_sound
+ file_font
+ file_text
+ recover_auto
+ save_prefs
+ link_blend
+ append_blend
+ import
+ export
+ external_data
+ load_factory
+ loop_back
+ loop_forwards
+ back
+ forward
+ file_hidden
+ file_backup
+ disk_drive
+ matplane
+ matsphere
+ matcube
+ monkey
+ hair
+ aliased
+ antialiased
+ mat_sphere_sky
+ wordwrap_off
+ wordwrap_on
+ syntax_off
+ syntax_on
+ linenumbers_off
+ linenumbers_on
+ scriptplugins
+ seq_sequencer
+ seq_preview
+ seq_luma_waveform
+ seq_chroma_scope
+ seq_histogram
+ seq_splitview
+ image_rgb
+ image_rgb_alpha
+ image_alpha
+ image_zdepth
+ imagefile
+)
+
data_to_c_simple(../../../../release/datafiles/bfont.pfb SRC)
data_to_c_simple(../../../../release/datafiles/bfont.ttf SRC)
data_to_c_simple(../../../../release/datafiles/bmonofont.ttf SRC)
@@ -53,12 +547,12 @@ if(WITH_BLENDER)
#../../../../release/datafiles/blender_icons16.png
#90 SRC)
- data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 SRC)
+ data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 "icon16_" "${ICON_NAMES}" SRC)
#data_to_c_simple(../../../../release/datafiles/blender_icons16.png SRC)
#svg_to_png(../../../../release/datafiles/blender_icons.svg
#../../../../release/datafiles/blender_icons32.png
#180 SRC)
- data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 SRC)
+ data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 "icon32_" "${ICON_NAMES}" SRC)
#data_to_c_simple(../../../../release/datafiles/blender_icons32.png SRC)
#svg_to_png(../../../../release/datafiles/prvicons.svg
#../../../../release/datafiles/prvicons.png
@@ -130,4 +624,6 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/startup.blend SRC)
endif()
+unset(ICON_NAMES)
+
blender_add_lib(bf_editor_datafiles "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 1674091f138..4a95027528b 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -1672,6 +1672,7 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
void ED_gpencil_draw_view3d(wmWindowManager *wm,
Scene *scene,
ViewLayer *view_layer,
+ const struct Depsgraph *depsgraph,
View3D *v3d,
ARegion *ar,
bool only3d)
@@ -1688,7 +1689,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm,
* deal with the camera border, otherwise map the coords to the camera border. */
if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
rctf rectf;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
offsx = round_fl_to_int(rectf.xmin);
offsy = round_fl_to_int(rectf.ymin);
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index f3b12b9bc85..76fa3b3f9ea 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1111,7 +1111,8 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect)
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
Scene *scene = CTX_data_scene(C);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, subrect, true); /* no shift */
return 1;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index a82148788c8..22a3224e563 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -105,7 +105,8 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
ED_gpencil_reset_layers_parent(gpd);
}
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
return OPERATOR_FINISHED;
@@ -153,7 +154,8 @@ static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
ts->gp_sculpt.alpha = 1.0f;
}
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 09ccc4600ef..472b88cb18b 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1609,7 +1609,7 @@ static void gp_session_cleanup(tGPsdata *p)
}
/* init new stroke */
-static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
+static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, const Depsgraph *depsgraph)
{
Scene *scene = p->scene;
ToolSettings *ts = scene->toolsettings;
@@ -1738,7 +1738,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(p->scene, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */
+ ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */
p->subrect = &p->subrect_data;
}
}
@@ -1979,7 +1979,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
}
/* init painting data */
- gp_paint_initstroke(p, paintmode);
+ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
if (p->status == GP_STATUS_ERROR) {
gpencil_draw_exit(C, op);
return 0;
@@ -2056,7 +2056,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
+static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, const Depsgraph *depsgraph)
{
/* handle drawing/erasing -> test for erasing first */
if (p->paintmode == GP_PAINTMODE_ERASER) {
@@ -2078,7 +2078,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
/* finish off old stroke */
gp_paint_strokeend(p);
/* And start a new one!!! Else, projection errors! */
- gp_paint_initstroke(p, p->paintmode);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
/* start a new stroke, starting from previous point */
/* XXX Must manually reset inittime... */
@@ -2111,7 +2111,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
}
/* handle draw event */
-static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
+static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, const Depsgraph *depsgraph)
{
tGPsdata *p = op->customdata;
PointerRNA itemptr;
@@ -2216,7 +2216,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(op, p);
+ gpencil_draw_apply(op, p, depsgraph);
/* force refresh */
ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
@@ -2228,6 +2228,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
static int gpencil_draw_exec(bContext *C, wmOperator *op)
{
tGPsdata *p = NULL;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
/* printf("GPencil - Starting Re-Drawing\n"); */
@@ -2265,7 +2266,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
/* TODO: both of these ops can set error-status, but we probably don't need to worry */
gp_paint_strokeend(p);
- gp_paint_initstroke(p, p->paintmode);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
}
}
@@ -2280,7 +2281,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(op, p);
+ gpencil_draw_apply(op, p, depsgraph);
}
RNA_END;
@@ -2339,7 +2340,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(op, event);
+ gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -2380,7 +2381,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
* it'd be nice to allow changing paint-mode when in sketching-sessions */
if (gp_session_initdata(C, p))
- gp_paint_initstroke(p, p->paintmode);
+ gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
if (p->status != GP_STATUS_ERROR) {
p->status = GP_STATUS_PAINTING;
@@ -2671,7 +2672,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
- gpencil_draw_apply_event(op, event);
+ gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index e1e4f850039..94689fb59fa 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -553,7 +553,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */
+ ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */
r_gsc->subrect = &r_gsc->subrect_data;
}
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 7e384e0056b..3ea754b242c 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -35,6 +35,7 @@
struct ID;
struct ListBase;
struct bContext;
+struct Depsgraph;
struct ScrArea;
struct ARegion;
struct View3D;
@@ -152,6 +153,7 @@ void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
void ED_gpencil_draw_view3d(struct wmWindowManager *wm,
struct Scene *scene,
struct ViewLayer *view_layer,
+ const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct ARegion *ar,
bool only3d);
diff --git a/source/blender/editors/include/ED_manipulator_library.h b/source/blender/editors/include/ED_manipulator_library.h
index 80703321490..7166292147e 100644
--- a/source/blender/editors/include/ED_manipulator_library.h
+++ b/source/blender/editors/include/ED_manipulator_library.h
@@ -33,6 +33,7 @@
/* initialize manipulators */
void ED_manipulatortypes_arrow_2d(void);
void ED_manipulatortypes_arrow_3d(void);
+void ED_manipulatortypes_button_2d(void);
void ED_manipulatortypes_cage_2d(void);
void ED_manipulatortypes_cage_3d(void);
void ED_manipulatortypes_dial_3d(void);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 1fd7756df77..78497b29313 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -40,6 +40,7 @@ struct EvaluationContext;
struct View3D;
struct ARegion;
struct bContext;
+struct Depsgraph;
struct wmOperator;
struct wmKeyConfig;
struct ReportList;
@@ -126,6 +127,7 @@ void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
+ const struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
/* editmesh_select.c */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d931109b941..32e6ddf6f54 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -141,7 +141,9 @@ int ED_region_global_size_y(void);
/* screens */
void ED_screens_initialize(struct wmWindowManager *wm);
-void ED_screen_draw(struct wmWindow *win);
+void ED_screen_draw_edges(struct wmWindow *win);
+void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2);
+void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm, struct wmWindow *win, struct bScreen *screen);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 69061bdcd26..7eee053061e 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -70,6 +70,7 @@ struct wmWindowManager;
struct GPUFX;
struct GPUOffScreen;
struct GPUFXSettings;
+struct GPUViewport;
struct WorkSpace;
enum eGPUFXFlags;
@@ -223,12 +224,16 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspm
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
+float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
+
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
bool ED_view3d_win_to_ray(
+ const struct Depsgraph *depsgraph,
const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
float ray_start[3], float ray_normal[3], const bool do_clip);
bool ED_view3d_win_to_ray_ex(
+ const struct Depsgraph *depsgraph,
const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]);
@@ -243,7 +248,8 @@ void ED_view3d_win_to_3d_int(
void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]);
void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
-bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
+bool ED_view3d_win_to_segment(const struct Depsgraph *depsgraph,
+ const struct ARegion *ar, struct View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
@@ -258,24 +264,29 @@ void ED_view3d_dist_range_get(
const struct View3D *v3d,
float r_dist_range[2]);
bool ED_view3d_clip_range_get(
+ const struct Depsgraph *depsgraph,
const struct View3D *v3d, const struct RegionView3D *rv3d,
float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
bool ED_view3d_viewplane_get(
+ const struct Depsgraph *depsgraph,
const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi,
struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
void ED_view3d_calc_camera_border(
- const struct Scene *scene, const struct ARegion *ar,
+ const struct Scene *scene, const struct Depsgraph *depsgraph,
+ const struct ARegion *ar,
const struct View3D *v3d, const struct RegionView3D *rv3d,
struct rctf *r_viewborder, const bool no_shift);
void ED_view3d_calc_camera_border_size(
- const struct Scene *scene, const struct ARegion *ar,
+ const struct Scene *scene, const struct Depsgraph *depsgraph,
+ const struct ARegion *ar,
const struct View3D *v3d, const struct RegionView3D *rv3d,
float r_size[2]);
bool ED_view3d_calc_render_border(
- const struct Scene *scene, struct View3D *v3d,
+ const struct Scene *scene, const struct Depsgraph *depsgraph,
+ struct View3D *v3d,
struct ARegion *ar, struct rcti *rect);
void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
@@ -287,8 +298,6 @@ void ED_view3d_clipping_set(struct RegionView3D *rv3d);
void ED_view3d_clipping_enable(void);
void ED_view3d_clipping_disable(void);
-float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
-
float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
float ED_view3d_radius_to_dist(
@@ -380,7 +389,7 @@ void ED_view3d_draw_offscreen(
struct ViewLayer *view_layer, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
struct GPUFX *fx, struct GPUFXSettings *fx_settings,
- struct GPUOffScreen *ofs);
+ struct GPUOffScreen *ofs, struct GPUViewport *viewport);
void ED_view3d_draw_setup_view(
struct wmWindow *win, const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
@@ -425,6 +434,9 @@ uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d)
uint64_t ED_view3d_screen_datamask(const struct Scene *scene, const struct bScreen *screen);
bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
+void ED_view3d_persp_switch_from_camera(struct View3D *v3d, struct RegionView3D *rv3d, const char persp);
+bool ED_view3d_persp_ensure(struct View3D *v3d, struct ARegion *ar);
+
/* camera lock functions */
bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
@@ -441,7 +453,7 @@ bool ED_view3d_camera_lock_autokey(
struct View3D *v3d, struct RegionView3D *rv3d,
struct bContext *C, const bool do_rotate, const bool do_translate);
-void ED_view3D_lock_clear(struct View3D *v3d);
+void ED_view3d_lock_clear(struct View3D *v3d);
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
@@ -471,4 +483,11 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View
void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id);
+/* view3d_draw_legacy.c */
+/* Try avoid using these more move out of legacy. */
+void ED_view3d_draw_bgpic_test(
+ struct Scene *scene, const struct Depsgraph *depsgraph,
+ struct ARegion *ar, struct View3D *v3d,
+ const bool do_foreground, const bool do_camera_frame);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 0c83038b7a3..923038a7490 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -190,8 +190,8 @@ DEF_ICON(SCULPTMODE_HLT)
DEF_ICON(POSE_HLT)
DEF_ICON(PARTICLEMODE)
DEF_ICON(LIGHTPAINT)
+DEF_ICON(GREASEPENCIL_STROKE_PAINT)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK063)
DEF_ICON(BLANK064)
DEF_ICON(BLANK065)
DEF_ICON(BLANK066)
@@ -257,9 +257,7 @@ DEF_ICON(STRANDS)
DEF_ICON(LIBRARY_DATA_INDIRECT)
DEF_ICON(GREASEPENCIL)
DEF_ICON(LINE_DATA)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK084)
-#endif
+DEF_ICON(LIBRARY_DATA_OVERRIDE)
DEF_ICON(GROUP_BONE)
DEF_ICON(GROUP_VERTEX)
DEF_ICON(GROUP_VCOL)
@@ -315,8 +313,8 @@ DEF_ICON(OUTLINER_OB_SURFACE)
DEF_ICON(OUTLINER_OB_SPEAKER)
DEF_ICON(OUTLINER_OB_FORCE_FIELD)
DEF_ICON(OUTLINER_OB_GROUP_INSTANCE)
+DEF_ICON(OUTLINER_OB_GREASEPENCIL)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK122)
DEF_ICON(BLANK123)
DEF_ICON(BLANK124)
DEF_ICON(BLANK125)
@@ -346,8 +344,8 @@ DEF_ICON(OUTLINER_DATA_FONT)
DEF_ICON(OUTLINER_DATA_SURFACE)
DEF_ICON(OUTLINER_DATA_SPEAKER)
DEF_ICON(OUTLINER_DATA_POSE)
+DEF_ICON(OUTLINER_DATA_GREASEPENCIL)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK130)
DEF_ICON(BLANK131)
DEF_ICON(BLANK132)
DEF_ICON(BLANK133)
@@ -715,8 +713,8 @@ DEF_ICON(CLIPUV_DEHLT)
DEF_ICON(CLIPUV_HLT)
DEF_ICON(SNAP_PEEL_OBJECT)
DEF_ICON(GRID)
+DEF_ICON(OBJECT_ORIGIN)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK221)
DEF_ICON(BLANK222)
DEF_ICON(BLANK224)
DEF_ICON(BLANK225)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9a816f21fb8..c1f2f68dbeb 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -73,6 +73,7 @@ struct bNodeSocket;
struct wmDropBox;
struct wmDrag;
struct wmEvent;
+struct wmManipulator;
struct wmMsgBus;
typedef struct uiBut uiBut;
@@ -667,8 +668,18 @@ void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0
#define UI_ID_FAKE_USER (1 << 8)
#define UI_ID_PIN (1 << 9)
#define UI_ID_PREVIEWS (1 << 10)
+#define UI_ID_OVERRIDE (1 << 11)
#define UI_ID_FULL (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL)
+/**
+ * Ways to limit what is displayed in ID-search popup.
+ * \note We may want to add LOCAL, LIBRARY ... as needed.
+ */
+enum {
+ UI_TEMPLATE_ID_FILTER_ALL = 0,
+ UI_TEMPLATE_ID_FILTER_AVAILABLE = 1,
+};
+
int UI_icon_from_id(struct ID *id);
int UI_icon_from_report_type(int type);
@@ -952,16 +963,20 @@ uiLayout *uiLayoutRadial(uiLayout *layout);
/* templates */
void uiTemplateHeader(uiLayout *layout, struct bContext *C);
-void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop);
-void uiTemplateIDBrowse(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop);
-void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop, int rows, int cols);
+void uiTemplateID(
+ uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
+ const char *newop, const char *openop, const char *unlinkop, int filter);
+void uiTemplateIDBrowse(
+ uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
+ const char *newop, const char *openop, const char *unlinkop, int filter);
+void uiTemplateIDPreview(
+ uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
+ const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter);
void uiTemplateIDTabs(
uiLayout *layout, struct bContext *C,
PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop);
+ const char *newop, const char *openop, const char *unlinkop,
+ int filter);
void uiTemplateAnyID(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
const char *proptypename, const char *text);
void uiTemplateSearch(
@@ -1125,6 +1140,8 @@ void UI_context_active_but_prop_get_templateID(
struct bContext *C,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
+uiBut *UI_region_active_but_get(struct ARegion *ar);
+
/* Styled text draw */
void UI_fontstyle_set(const struct uiFontStyle *fs);
void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
@@ -1168,6 +1185,13 @@ void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
+/* ui_interface_region_tooltip.c */
+struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but);
+struct ARegion *UI_tooltip_create_from_manipulator(struct bContext *C, struct wmManipulator *mpr);
+void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar);
+
+/* How long before a tool-tip shows. */
+#define UI_TOOLTIP_DELAY 0.5
/* Float precision helpers */
#define UI_PRECISION_FLOAT_MAX 6
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 03a2c1ec414..94f377fb35e 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -45,6 +45,11 @@ set(SRC
interface_anim.c
interface_draw.c
interface_eyedropper.c
+ interface_eyedropper_color.c
+ interface_eyedropper_colorband.c
+ interface_eyedropper_datablock.c
+ interface_eyedropper_depth.c
+ interface_eyedropper_driver.c
interface_handlers.c
interface_icons.c
interface_layout.c
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index e46c6a0e267..3ecb72353bc 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -40,9 +40,9 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_node.h"
-#include "BKE_texture.h"
#include "BKE_tracking.h"
@@ -1335,7 +1335,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
- do_colorband(coba, pos, colf);
+ BKE_colorband_evaluate(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
@@ -1354,7 +1354,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
- do_colorband(coba, pos, colf);
+ BKE_colorband_evaluate(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index e92139ada0c..8cb55b724fb 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -27,55 +27,23 @@
* \ingroup edinterface
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_anim_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
-#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
-#include "BLT_translation.h"
-
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "BKE_report.h"
-#include "BKE_animsys.h"
-#include "BKE_idcode.h"
-#include "BKE_unit.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "BIF_gl.h"
#include "UI_interface.h"
-#include "IMB_colormanagement.h"
-
#include "WM_api.h"
#include "WM_types.h"
#include "interface_intern.h"
-/* for HDR color sampling */
-#include "ED_image.h"
-#include "ED_node.h"
-#include "ED_clip.h"
-
-/* for ID data eyedropper */
-#include "ED_space_api.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-
-/* for Driver eyedropper */
-#include "ED_keyframing.h"
-
+#include "interface_eyedropper_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/* Keymap
@@ -83,12 +51,6 @@
/** \name Modal Keymap
* \{ */
-enum {
- EYE_MODAL_CANCEL = 1,
- EYE_MODAL_SAMPLE_CONFIRM,
- EYE_MODAL_SAMPLE_BEGIN,
- EYE_MODAL_SAMPLE_RESET,
-};
wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
{
@@ -118,6 +80,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET);
/* assign to operators */
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
@@ -126,6 +89,37 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
return keymap;
}
+wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items_point[] = {
+ {EYE_MODAL_POINT_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {EYE_MODAL_POINT_SAMPLE, "SAMPLE_SAMPLE", 0, "Sample a point", ""},
+ {EYE_MODAL_POINT_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
+ {EYE_MODAL_POINT_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorBand PointSampling Map");
+ if (keymap && keymap->modal_items)
+ return keymap;
+
+ keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE);
+ WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET);
+
+ /* assign to operators */
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point");
+
+ return keymap;
+}
+
/** \} */
@@ -135,7 +129,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
/** \name Generic Shared Functions
* \{ */
-static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name)
+void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, const char *name)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
wmWindow *win = CTX_wm_window(C);
@@ -169,14 +163,14 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
*
* \return A button under the mouse which relates to some RNA Property, or NULL
*/
-static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
+uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
-
+
uiBut *but = ui_but_find_mouse_over(ar, event);
-
+
if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) {
return NULL;
}
@@ -187,1128 +181,3 @@ static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEv
/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Eyedropper
- */
-
-/** \name Eyedropper (RGB Color)
- * \{ */
-
-typedef struct Eyedropper {
- struct ColorManagedDisplay *display;
-
- PointerRNA ptr;
- PropertyRNA *prop;
- int index;
-
- float init_col[3]; /* for resetting on cancel */
-
- bool accum_start; /* has mouse been pressed */
- float accum_col[3];
- int accum_tot;
-} Eyedropper;
-
-static bool eyedropper_init(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Eyedropper *eye;
-
- op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
-
- UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
-
- if ((eye->ptr.data == NULL) ||
- (eye->prop == NULL) ||
- (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
- (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
- (RNA_property_type(eye->prop) != PROP_FLOAT))
- {
- return false;
- }
-
- if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
- const char *display_device;
- float col[4];
-
- display_device = scene->display_settings.display_device;
- eye->display = IMB_colormanagement_display_get_named(display_device);
-
- /* store inital color */
- RNA_property_float_get_array(&eye->ptr, eye->prop, col);
- if (eye->display) {
- IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
- }
- copy_v3_v3(eye->init_col, col);
- }
-
- return true;
-}
-
-static void eyedropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- MEM_freeN(op->customdata);
- op->customdata = NULL;
- }
-}
-
-/* *** eyedropper_color_ helper functions *** */
-
-/**
- * \brief get the color from the screen.
- *
- * Special check for image or nodes where we MAY have HDR pixels which don't display.
- */
-static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3])
-{
- /* we could use some clever */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- const char *display_device = CTX_data_scene(C)->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
-
- if (sa) {
- if (sa->spacetype == SPACE_IMAGE) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- SpaceImage *sima = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
- return;
- }
- }
- }
- else if (sa->spacetype == SPACE_NODE) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- SpaceNode *snode = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
- return;
- }
- }
- }
- else if (sa->spacetype == SPACE_CLIP) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- SpaceClip *sc = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
- return;
- }
- }
- }
- }
-
- /* fallback to simple opengl picker */
- glReadBuffer(GL_FRONT);
- glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
- glReadBuffer(GL_BACK);
-
- IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
-}
-
-/* sets the sample color RGB, maintaining A */
-static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
-{
- float col_conv[4];
-
- /* to maintain alpha */
- RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
-
- /* convert from linear rgb space to display space */
- if (eye->display) {
- copy_v3_v3(col_conv, col);
- IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
- }
- else {
- copy_v3_v3(col_conv, col);
- }
-
- RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
-
- RNA_property_update(C, &eye->ptr, eye->prop);
-}
-
-/* set sample from accumulated values */
-static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
-{
- float col[3];
- mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
- eyedropper_color_set(C, eye, col);
-}
-
-/* single point sample & set */
-static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
-{
- float col[3];
- eyedropper_color_sample_fl(C, eye, mx, my, col);
- eyedropper_color_set(C, eye, col);
-}
-
-static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
-{
- float col[3];
- eyedropper_color_sample_fl(C, eye, mx, my, col);
- /* delay linear conversion */
- add_v3_v3(eye->accum_col, col);
- eye->accum_tot++;
-}
-
-static void eyedropper_cancel(bContext *C, wmOperator *op)
-{
- Eyedropper *eye = op->customdata;
- eyedropper_color_set(C, eye, eye->init_col);
- eyedropper_exit(C, op);
-}
-
-/* main modal status check */
-static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Eyedropper *eye = (Eyedropper *)op->customdata;
-
- /* handle modal keymap */
- if (event->type == EVT_MODAL_MAP) {
- switch (event->val) {
- case EYE_MODAL_CANCEL:
- eyedropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case EYE_MODAL_SAMPLE_CONFIRM:
- if (eye->accum_tot == 0) {
- eyedropper_color_sample(C, eye, event->x, event->y);
- }
- else {
- eyedropper_color_set_accum(C, eye);
- }
- eyedropper_exit(C, op);
- return OPERATOR_FINISHED;
- case EYE_MODAL_SAMPLE_BEGIN:
- /* enable accum and make first sample */
- eye->accum_start = true;
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- break;
- case EYE_MODAL_SAMPLE_RESET:
- eye->accum_tot = 0;
- zero_v3(eye->accum_col);
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- eyedropper_color_set_accum(C, eye);
- break;
- }
- }
- else if (event->type == MOUSEMOVE) {
- if (eye->accum_start) {
- /* button is pressed so keep sampling */
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- eyedropper_color_set_accum(C, eye);
- }
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Modal Operator init */
-static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
-
- /* add temp handler */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
- }
- else {
- eyedropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int eyedropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (eyedropper_init(C, op)) {
-
- /* do something */
-
- /* cleanup */
- eyedropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int eyedropper_poll(bContext *C)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* Only color buttons */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_COLOR))
- {
- return 1;
- }
-
- return 0;
-}
-
-void UI_OT_eyedropper_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper";
- ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
-
- /* api callbacks */
- ot->invoke = eyedropper_invoke;
- ot->modal = eyedropper_modal;
- ot->cancel = eyedropper_cancel;
- ot->exec = eyedropper_exec;
- ot->poll = eyedropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-/* Data Dropper */
-
-/** \name Eyedropper (ID data-blocks)
- *
- * \note: datadropper is only internal name to avoid confusion in this file.
- * \{ */
-
-typedef struct DataDropper {
- PointerRNA ptr;
- PropertyRNA *prop;
- short idcode;
- const char *idcode_name;
-
- ID *init_id; /* for resetting on cancel */
-
- ARegionType *art;
- void *draw_handle_pixel;
- char name[200];
-} DataDropper;
-
-
-static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
-{
- DataDropper *ddr = arg;
- eyedropper_draw_cursor_text(C, ar, ddr->name);
-}
-
-
-static int datadropper_init(bContext *C, wmOperator *op)
-{
- DataDropper *ddr;
- int index_dummy;
- StructRNA *type;
-
- SpaceType *st;
- ARegionType *art;
-
- st = BKE_spacetype_from_id(SPACE_VIEW3D);
- art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
-
- op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
-
- UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
-
- if ((ddr->ptr.data == NULL) ||
- (ddr->prop == NULL) ||
- (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
- (RNA_property_type(ddr->prop) != PROP_POINTER))
- {
- return false;
- }
-
- ddr->art = art;
- ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
-
- type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
- ddr->idcode = RNA_type_to_ID_code(type);
- BLI_assert(ddr->idcode != 0);
- /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
- ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
-
- PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
- ddr->init_id = ptr.id.data;
-
- return true;
-}
-
-static void datadropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- DataDropper *ddr = (DataDropper *)op->customdata;
-
- if (ddr->art) {
- ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
- }
-
- MEM_freeN(op->customdata);
-
- op->customdata = NULL;
- }
-
- WM_event_add_mousemove(C);
-}
-
-/* *** datadropper id helper functions *** */
-/**
- * \brief get the ID from the screen.
- *
- */
-static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
-{
- /* we could use some clever */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
-
- ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
-
- ddr->name[0] = '\0';
-
- if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- const int mval[2] = {
- mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
- 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 (id) {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
- ddr->idcode_name, id->name + 2);
- *r_id = id;
- }
- }
- }
- }
- }
-
- CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
-}
-
-/* sets the ID, returns success */
-static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
-{
- PointerRNA ptr_value;
-
- RNA_id_pointer_create(id, &ptr_value);
-
- RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value);
-
- RNA_property_update(C, &ddr->ptr, ddr->prop);
-
- ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
-
- return (ptr_value.id.data == id);
-}
-
-/* single point sample & set */
-static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
-{
- ID *id = NULL;
-
- datadropper_id_sample_pt(C, ddr, mx, my, &id);
- return datadropper_id_set(C, ddr, id);
-}
-
-static void datadropper_cancel(bContext *C, wmOperator *op)
-{
- DataDropper *ddr = op->customdata;
- datadropper_id_set(C, ddr, ddr->init_id);
- datadropper_exit(C, op);
-}
-
-/* main modal status check */
-static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- DataDropper *ddr = (DataDropper *)op->customdata;
-
- /* handle modal keymap */
- if (event->type == EVT_MODAL_MAP) {
- switch (event->val) {
- case EYE_MODAL_CANCEL:
- datadropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case EYE_MODAL_SAMPLE_CONFIRM:
- {
- bool success;
-
- success = datadropper_id_sample(C, ddr, event->x, event->y);
- datadropper_exit(C, op);
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "Failed to set value");
- return OPERATOR_CANCELLED;
- }
- }
- }
- }
- else if (event->type == MOUSEMOVE) {
- ID *id = NULL;
- datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Modal Operator init */
-static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
-
- /* add temp handler */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
- }
- else {
- datadropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int datadropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (datadropper_init(C, op)) {
- /* cleanup */
- datadropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int datadropper_poll(bContext *C)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* data dropper only supports object data */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_VALUE_CLEAR))
- {
- if (prop && RNA_property_type(prop) == PROP_POINTER) {
- StructRNA *type = RNA_property_pointer_type(&ptr, prop);
- const short idcode = RNA_type_to_ID_code(type);
- if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-void UI_OT_eyedropper_id(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper Data-Block";
- ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a data-block from the 3D View to store in a property";
-
- /* api callbacks */
- ot->invoke = datadropper_invoke;
- ot->modal = datadropper_modal;
- ot->cancel = datadropper_cancel;
- ot->exec = datadropper_exec;
- ot->poll = datadropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-/* Depth Dropper */
-
-/** \name Eyedropper (Depth)
- *
- * \note: depthdropper is only internal name to avoid confusion in this file.
- * \{ */
-
-typedef struct DepthDropper {
- PointerRNA ptr;
- PropertyRNA *prop;
-
- float init_depth; /* for resetting on cancel */
-
- bool accum_start; /* has mouse been presed */
- float accum_depth;
- int accum_tot;
-
- ARegionType *art;
- void *draw_handle_pixel;
- char name[200];
-} DepthDropper;
-
-
-static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
-{
- DepthDropper *ddr = arg;
- eyedropper_draw_cursor_text(C, ar, ddr->name);
-}
-
-
-static int depthdropper_init(bContext *C, wmOperator *op)
-{
- DepthDropper *ddr;
- int index_dummy;
-
- SpaceType *st;
- ARegionType *art;
-
- st = BKE_spacetype_from_id(SPACE_VIEW3D);
- art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
-
- op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
-
- UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
-
- /* fallback to the active camera's dof */
- if (ddr->prop == NULL) {
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d && rv3d->persp == RV3D_CAMOB) {
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
- RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
- ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
- }
- }
- }
-
- if ((ddr->ptr.data == NULL) ||
- (ddr->prop == NULL) ||
- (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
- (RNA_property_type(ddr->prop) != PROP_FLOAT))
- {
- return false;
- }
-
- ddr->art = art;
- ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
- ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
-
- return true;
-}
-
-static void depthdropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- DepthDropper *ddr = (DepthDropper *)op->customdata;
-
- if (ddr->art) {
- ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
- }
-
- MEM_freeN(op->customdata);
-
- op->customdata = NULL;
- }
-}
-
-/* *** depthdropper id helper functions *** */
-/**
- * \brief get the ID from the screen.
- *
- */
-static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
-{
- /* we could use some clever */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- Scene *scene = CTX_data_scene(C);
- UnitSettings *unit = &scene->unit;
- const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
-
- ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
-
- ddr->name[0] = '\0';
-
- if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- struct Depsgraph *graph = CTX_data_depsgraph(C);
- 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];
-
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
-
- 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(&eval_ctx, graph, 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(v3d, 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));
- }
- }
- }
- }
-
- CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
-}
-
-/* sets the sample depth RGB, maintaining A */
-static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
-{
- RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
- RNA_property_update(C, &ddr->ptr, ddr->prop);
-}
-
-/* set sample from accumulated values */
-static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
-{
- float depth = ddr->accum_depth;
- if (ddr->accum_tot) {
- depth /= (float)ddr->accum_tot;
- }
- depthdropper_depth_set(C, ddr, depth);
-}
-
-/* single point sample & set */
-static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
-{
- float depth = -1.0f;
- if (depth != -1.0f) {
- depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
- depthdropper_depth_set(C, ddr, depth);
- }
-}
-
-static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
-{
- float depth = -1.0f;
- depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
- if (depth != -1.0f) {
- ddr->accum_depth += depth;
- ddr->accum_tot++;
- }
-}
-
-static void depthdropper_cancel(bContext *C, wmOperator *op)
-{
- DepthDropper *ddr = op->customdata;
- depthdropper_depth_set(C, ddr, ddr->init_depth);
- depthdropper_exit(C, op);
-}
-
-/* main modal status check */
-static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- DepthDropper *ddr = (DepthDropper *)op->customdata;
-
- /* handle modal keymap */
- if (event->type == EVT_MODAL_MAP) {
- switch (event->val) {
- case EYE_MODAL_CANCEL:
- depthdropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case EYE_MODAL_SAMPLE_CONFIRM:
- if (ddr->accum_tot == 0) {
- depthdropper_depth_sample(C, ddr, event->x, event->y);
- }
- else {
- depthdropper_depth_set_accum(C, ddr);
- }
- depthdropper_exit(C, op);
- return OPERATOR_FINISHED;
- case EYE_MODAL_SAMPLE_BEGIN:
- /* enable accum and make first sample */
- ddr->accum_start = true;
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- break;
- case EYE_MODAL_SAMPLE_RESET:
- ddr->accum_tot = 0;
- ddr->accum_depth = 0.0f;
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- depthdropper_depth_set_accum(C, ddr);
- break;
- }
- }
- else if (event->type == MOUSEMOVE) {
- if (ddr->accum_start) {
- /* button is pressed so keep sampling */
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- depthdropper_depth_set_accum(C, ddr);
- }
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Modal Operator init */
-static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
-
- /* add temp handler */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
- }
- else {
- depthdropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int depthdropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (depthdropper_init(C, op)) {
- /* cleanup */
- depthdropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int depthdropper_poll(bContext *C)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* check if there's an active button taking depth value */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_NUM) &&
- (prop != NULL))
- {
- if ((RNA_property_type(prop) == PROP_FLOAT) &&
- (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
- (RNA_property_array_check(prop) == false))
- {
- return 1;
- }
- }
- else {
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d && rv3d->persp == RV3D_CAMOB) {
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-void UI_OT_eyedropper_depth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper Depth";
- ot->idname = "UI_OT_eyedropper_depth";
- ot->description = "Sample depth from the 3D view";
-
- /* api callbacks */
- ot->invoke = depthdropper_invoke;
- ot->modal = depthdropper_modal;
- ot->cancel = depthdropper_cancel;
- ot->exec = depthdropper_exec;
- ot->poll = depthdropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Eyedropper
- */
-
-/* NOTE: This is here (instead of in drivers.c) because we need access the button internals,
- * which we cannot access outside of the interface module
- */
-
-/** \name Eyedropper (Driver Target)
- * \{ */
-
-typedef struct DriverDropper {
- /* Destination property (i.e. where we'll add a driver) */
- PointerRNA ptr;
- PropertyRNA *prop;
- int index;
-
- // TODO: new target?
-} DriverDropper;
-
-static bool driverdropper_init(bContext *C, wmOperator *op)
-{
- DriverDropper *ddr;
- uiBut *but;
-
- op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
-
- but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
-
- if ((ddr->ptr.data == NULL) ||
- (ddr->prop == NULL) ||
- (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
- (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) ||
- (but->flag & UI_BUT_DRIVEN))
- {
- return false;
- }
-
- return true;
-}
-
-static void driverdropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- MEM_freeN(op->customdata);
- op->customdata = NULL;
- }
-}
-
-static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event)
-{
- DriverDropper *ddr = (DriverDropper *)op->customdata;
- uiBut *but = eyedropper_get_property_button_under_mouse(C, event);
-
- short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
- short flag = 0;
-
- /* we can only add a driver if we know what RNA property it corresponds to */
- if (but == NULL) {
- return;
- }
- else {
- /* Get paths for src... */
- PointerRNA *target_ptr = &but->rnapoin;
- PropertyRNA *target_prop = but->rnaprop;
- int target_index = but->rnaindex;
-
- char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
-
- /* ... and destination */
- char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
-
- /* Now create driver(s) */
- if (target_path && dst_path) {
- int success = ANIM_add_driver_with_target(op->reports,
- ddr->ptr.id.data, dst_path, ddr->index,
- target_ptr->id.data, target_path, target_index,
- flag, DRIVER_TYPE_PYTHON, mapping_type);
-
- if (success) {
- /* send updates */
- UI_context_update_anim_flag(C);
- DEG_relations_tag_update(CTX_data_main(C));
- DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
- }
- }
-
- /* cleanup */
- if (target_path)
- MEM_freeN(target_path);
- if (dst_path)
- MEM_freeN(dst_path);
- }
-}
-
-static void driverdropper_cancel(bContext *C, wmOperator *op)
-{
- driverdropper_exit(C, op);
-}
-
-/* main modal status check */
-static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- /* handle modal keymap */
- if (event->type == EVT_MODAL_MAP) {
- switch (event->val) {
- case EYE_MODAL_CANCEL:
- driverdropper_cancel(C, op);
- return OPERATOR_CANCELLED;
-
- case EYE_MODAL_SAMPLE_CONFIRM:
- driverdropper_sample(C, op, event);
- driverdropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Modal Operator init */
-static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
-
- /* add temp handler */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
- }
- else {
- driverdropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int driverdropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (driverdropper_init(C, op)) {
- /* cleanup */
- driverdropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int driverdropper_poll(bContext *C)
-{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
-}
-
-void UI_OT_eyedropper_driver(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper Driver";
- ot->idname = "UI_OT_eyedropper_driver";
- ot->description = "Pick a property to use as a driver target";
-
- /* api callbacks */
- ot->invoke = driverdropper_invoke;
- ot->modal = driverdropper_modal;
- ot->cancel = driverdropper_cancel;
- ot->exec = driverdropper_exec;
- ot->poll = driverdropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
- "Mapping Type", "Method used to match target and driven properties");
-}
-
-/** \} */
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
new file mode 100644
index 00000000000..f3301d55284
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -0,0 +1,356 @@
+/*
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_color.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (RGB Color)
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_color
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "BIF_gl.h"
+
+#include "UI_interface.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "interface_intern.h"
+
+#include "ED_image.h"
+#include "ED_node.h"
+#include "ED_clip.h"
+
+#include "interface_eyedropper_intern.h"
+
+typedef struct Eyedropper {
+ struct ColorManagedDisplay *display;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ float init_col[3]; /* for resetting on cancel */
+
+ bool accum_start; /* has mouse been pressed */
+ float accum_col[3];
+ int accum_tot;
+} Eyedropper;
+
+static bool eyedropper_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Eyedropper *eye;
+
+ op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
+
+ UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
+
+ if ((eye->ptr.data == NULL) ||
+ (eye->prop == NULL) ||
+ (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
+ (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
+ (RNA_property_type(eye->prop) != PROP_FLOAT))
+ {
+ return false;
+ }
+
+ if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
+ const char *display_device;
+ float col[4];
+
+ display_device = scene->display_settings.display_device;
+ eye->display = IMB_colormanagement_display_get_named(display_device);
+
+ /* store inital color */
+ RNA_property_float_get_array(&eye->ptr, eye->prop, col);
+ if (eye->display) {
+ IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
+ }
+ copy_v3_v3(eye->init_col, col);
+ }
+
+ return true;
+}
+
+static void eyedropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+ }
+}
+
+/* *** eyedropper_color_ helper functions *** */
+
+/**
+ * \brief get the color from the screen.
+ *
+ * Special check for image or nodes where we MAY have HDR pixels which don't display.
+ *
+ * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
+ */
+void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
+{
+ /* we could use some clever */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ const char *display_device = CTX_data_scene(C)->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
+
+ if (sa) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceImage *sima = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
+ return;
+ }
+ }
+ }
+ else if (sa->spacetype == SPACE_NODE) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceNode *snode = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
+ return;
+ }
+ }
+ }
+ else if (sa->spacetype == SPACE_CLIP) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceClip *sc = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
+ return;
+ }
+ }
+ }
+ }
+
+ /* fallback to simple opengl picker */
+ glReadBuffer(GL_FRONT);
+ glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
+ glReadBuffer(GL_BACK);
+
+ IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
+}
+
+/* sets the sample color RGB, maintaining A */
+static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
+{
+ float col_conv[4];
+
+ /* to maintain alpha */
+ RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
+
+ /* convert from linear rgb space to display space */
+ if (eye->display) {
+ copy_v3_v3(col_conv, col);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
+ }
+ else {
+ copy_v3_v3(col_conv, col);
+ }
+
+ RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
+
+ RNA_property_update(C, &eye->ptr, eye->prop);
+}
+
+/* set sample from accumulated values */
+static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
+{
+ float col[3];
+ mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
+ eyedropper_color_set(C, eye, col);
+}
+
+/* single point sample & set */
+static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
+{
+ float col[3];
+ eyedropper_color_sample_fl(C, mx, my, col);
+ eyedropper_color_set(C, eye, col);
+}
+
+static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
+{
+ float col[3];
+ eyedropper_color_sample_fl(C, mx, my, col);
+ /* delay linear conversion */
+ add_v3_v3(eye->accum_col, col);
+ eye->accum_tot++;
+}
+
+static void eyedropper_cancel(bContext *C, wmOperator *op)
+{
+ Eyedropper *eye = op->customdata;
+ eyedropper_color_set(C, eye, eye->init_col);
+ eyedropper_exit(C, op);
+}
+
+/* main modal status check */
+static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Eyedropper *eye = (Eyedropper *)op->customdata;
+
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ eyedropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ if (eye->accum_tot == 0) {
+ eyedropper_color_sample(C, eye, event->x, event->y);
+ }
+ else {
+ eyedropper_color_set_accum(C, eye);
+ }
+ eyedropper_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_SAMPLE_BEGIN:
+ /* enable accum and make first sample */
+ eye->accum_start = true;
+ eyedropper_color_sample_accum(C, eye, event->x, event->y);
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ eye->accum_tot = 0;
+ zero_v3(eye->accum_col);
+ eyedropper_color_sample_accum(C, eye, event->x, event->y);
+ eyedropper_color_set_accum(C, eye);
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (eye->accum_start) {
+ /* button is pressed so keep sampling */
+ eyedropper_color_sample_accum(C, eye, event->x, event->y);
+ eyedropper_color_set_accum(C, eye);
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (eyedropper_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ eyedropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int eyedropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_init(C, op)) {
+
+ /* do something */
+
+ /* cleanup */
+ eyedropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int eyedropper_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* Only color buttons */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_COLOR))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+void UI_OT_eyedropper_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper";
+ ot->idname = "UI_OT_eyedropper_color";
+ ot->description = "Sample a color from the Blender Window to store in a property";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_invoke;
+ ot->modal = eyedropper_modal;
+ ot->cancel = eyedropper_cancel;
+ ot->exec = eyedropper_exec;
+ ot->poll = eyedropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
new file mode 100644
index 00000000000..b13d552dbeb
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -0,0 +1,337 @@
+/*
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_colorband.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (Color Band).
+ *
+ * Operates by either:
+ * - Dragging a straight line, sampling pixels formed by the line to extract a gradient.
+ * - Clicking on points, adding each color to the end of the color-band.
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_colorband
+ * - #UI_OT_eyedropper_colorband_point
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_colorband.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "interface_intern.h"
+
+#include "interface_eyedropper_intern.h"
+
+typedef struct Colorband_RNAUpdateCb {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+} Colorband_RNAUpdateCb;
+
+typedef struct EyedropperColorband {
+ int last_x, last_y;
+ /* Alpha is currently fixed at 1.0, may support in future. */
+ float (*color_buffer)[4];
+ int color_buffer_alloc;
+ int color_buffer_len;
+ bool sample_start;
+ ColorBand init_color_band;
+ ColorBand *color_band;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+} EyedropperColorband;
+
+/* For user-data only. */
+struct EyedropperColorband_Context {
+ bContext *context;
+ EyedropperColorband *eye;
+};
+
+static bool eyedropper_colorband_init(bContext *C, wmOperator *op)
+{
+ ColorBand *band = NULL;
+ EyedropperColorband *eye;
+
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but == NULL) {
+ /* pass */
+ }
+ else if (but->type == UI_BTYPE_COLORBAND) {
+ /* When invoked with a hotkey, we can find the band in 'but->poin'. */
+ band = (ColorBand *)but->poin;
+ }
+ else {
+ /* When invoked from a button it's in custom_data field. */
+ band = (ColorBand *)but->custom_data;
+ }
+
+ if (!band)
+ return false;
+
+ op->customdata = eye = MEM_callocN(sizeof(EyedropperColorband), __func__);
+ eye->color_buffer_alloc = 16;
+ eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__);
+ eye->color_buffer_len = 0;
+ eye->color_band = band;
+ eye->init_color_band = *eye->color_band;
+ eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr;
+ eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop;
+
+ return true;
+}
+
+static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, int mx, int my)
+{
+ if (eye->last_x != mx || eye->last_y != my) {
+ float col[4];
+ col[3] = 1.0f; /* TODO: sample alpha */
+ eyedropper_color_sample_fl(C, mx, my, col);
+ if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) {
+ eye->color_buffer_alloc *= 2;
+ eye->color_buffer = MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc);
+ }
+ copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col);
+ eye->color_buffer_len += 1;
+ eye->last_x = mx;
+ eye->last_y = my;
+ }
+}
+
+static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata)
+{
+ struct EyedropperColorband_Context *data = userdata;
+ bContext *C = data->context;
+ EyedropperColorband *eye = data->eye;
+ eyedropper_colorband_sample_point(C, eye, mx, my);
+ return true;
+}
+
+static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, int mx, int my)
+{
+ /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i
+ * to interpolate between the reported coordinates */
+ struct EyedropperColorband_Context userdata = {C, eye};
+ int p1[2] = {eye->last_x, eye->last_y};
+ int p2[2] = {mx, my};
+ BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata);
+}
+
+static void eyedropper_colorband_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ EyedropperColorband *eye = op->customdata;
+ MEM_freeN(eye->color_buffer);
+ MEM_freeN(eye);
+ op->customdata = NULL;
+ }
+}
+
+static void eyedropper_colorband_apply(bContext *C, wmOperator *op)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* Always filter, avoids noise in resulting color-band. */
+ bool filter_samples = true;
+ BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples);
+ RNA_property_update(C, &eye->ptr, eye->prop);
+}
+
+static void eyedropper_colorband_cancel(bContext *C, wmOperator *op)
+{
+ EyedropperColorband *eye = op->customdata;
+ *eye->color_band = eye->init_color_band;
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ eyedropper_colorband_exit(C, op);
+}
+
+/* main modal status check */
+static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ eyedropper_colorband_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_SAMPLE_BEGIN:
+ /* enable accum and make first sample */
+ eye->sample_start = true;
+ eyedropper_colorband_sample_point(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ eye->last_x = event->x;
+ eye->last_y = event->y;
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (eye->sample_start) {
+ eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_POINT_CANCEL:
+ eyedropper_colorband_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_POINT_CONFIRM:
+ eyedropper_colorband_apply(C, op);
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_POINT_REMOVE_LAST:
+ if (eye->color_buffer_len > 0) {
+ eye->color_buffer_len -= 1;
+ eyedropper_colorband_apply(C, op);
+ }
+ break;
+ case EYE_MODAL_POINT_SAMPLE:
+ eyedropper_colorband_sample_point(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ if (eye->color_buffer_len == MAXCOLORBAND ) {
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ *eye->color_band = eye->init_color_band;
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ eye->color_buffer_len = 0;
+ break;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+/* Modal Operator init */
+static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (eyedropper_colorband_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int eyedropper_colorband_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_colorband_init(C, op)) {
+
+ /* do something */
+
+ /* cleanup */
+ eyedropper_colorband_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int eyedropper_colorband_poll(bContext *C)
+{
+ uiBut *but = UI_context_active_but_get(C);
+ return (but && but->type == UI_BTYPE_COLORBAND);
+}
+
+
+void UI_OT_eyedropper_colorband(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper colorband";
+ ot->idname = "UI_OT_eyedropper_colorband";
+ ot->description = "Sample a color band";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_colorband_invoke;
+ ot->modal = eyedropper_colorband_modal;
+ ot->cancel = eyedropper_colorband_cancel;
+ ot->exec = eyedropper_colorband_exec;
+ ot->poll = eyedropper_colorband_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
+
+void UI_OT_eyedropper_colorband_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper colorband (points)";
+ ot->idname = "UI_OT_eyedropper_colorband_point";
+ ot->description = "Pointsample a color band";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_colorband_invoke;
+ ot->modal = eyedropper_colorband_point_modal;
+ ot->cancel = eyedropper_colorband_cancel;
+ ot->exec = eyedropper_colorband_exec;
+ ot->poll = eyedropper_colorband_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
new file mode 100644
index 00000000000..f814048c0c0
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -0,0 +1,351 @@
+/*
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_datablock.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (ID data-blocks)
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_id
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_string.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_report.h"
+#include "BKE_idcode.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_space_api.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+/**
+ * \note #DataDropper is only internal name to avoid confusion with other kinds of eye-droppers.
+ */
+typedef struct DataDropper {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ short idcode;
+ const char *idcode_name;
+
+ ID *init_id; /* for resetting on cancel */
+
+ ARegionType *art;
+ void *draw_handle_pixel;
+ char name[200];
+} DataDropper;
+
+
+static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
+{
+ DataDropper *ddr = arg;
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
+}
+
+
+static int datadropper_init(bContext *C, wmOperator *op)
+{
+ DataDropper *ddr;
+ int index_dummy;
+ StructRNA *type;
+
+ SpaceType *st;
+ ARegionType *art;
+
+ st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
+
+ op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_type(ddr->prop) != PROP_POINTER))
+ {
+ return false;
+ }
+
+ ddr->art = art;
+ ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+
+ type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
+ ddr->idcode = RNA_type_to_ID_code(type);
+ BLI_assert(ddr->idcode != 0);
+ /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
+ ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
+
+ PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
+ ddr->init_id = ptr.id.data;
+
+ return true;
+}
+
+static void datadropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ DataDropper *ddr = (DataDropper *)op->customdata;
+
+ if (ddr->art) {
+ ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
+ }
+
+ MEM_freeN(op->customdata);
+
+ op->customdata = NULL;
+ }
+
+ WM_event_add_mousemove(C);
+}
+
+/* *** datadropper id helper functions *** */
+/**
+ * \brief get the ID from the screen.
+ *
+ */
+static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
+{
+ /* we could use some clever */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+
+ ddr->name[0] = '\0';
+
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ 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 (id) {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
+ ddr->idcode_name, id->name + 2);
+ *r_id = id;
+ }
+ }
+ }
+ }
+ }
+
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+}
+
+/* sets the ID, returns success */
+static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
+{
+ PointerRNA ptr_value;
+
+ RNA_id_pointer_create(id, &ptr_value);
+
+ RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value);
+
+ RNA_property_update(C, &ddr->ptr, ddr->prop);
+
+ ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
+
+ return (ptr_value.id.data == id);
+}
+
+/* single point sample & set */
+static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
+{
+ ID *id = NULL;
+
+ datadropper_id_sample_pt(C, ddr, mx, my, &id);
+ return datadropper_id_set(C, ddr, id);
+}
+
+static void datadropper_cancel(bContext *C, wmOperator *op)
+{
+ DataDropper *ddr = op->customdata;
+ datadropper_id_set(C, ddr, ddr->init_id);
+ datadropper_exit(C, op);
+}
+
+/* main modal status check */
+static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ DataDropper *ddr = (DataDropper *)op->customdata;
+
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ datadropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ {
+ bool success;
+
+ success = datadropper_id_sample(C, ddr, event->x, event->y);
+ datadropper_exit(C, op);
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Failed to set value");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ ID *id = NULL;
+ datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (datadropper_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ datadropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int datadropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (datadropper_init(C, op)) {
+ /* cleanup */
+ datadropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int datadropper_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* data dropper only supports object data */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_VALUE_CLEAR))
+ {
+ if (prop && RNA_property_type(prop) == PROP_POINTER) {
+ StructRNA *type = RNA_property_pointer_type(&ptr, prop);
+ const short idcode = RNA_type_to_ID_code(type);
+ if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void UI_OT_eyedropper_id(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Data-Block";
+ ot->idname = "UI_OT_eyedropper_id";
+ ot->description = "Sample a data-block from the 3D View to store in a property";
+
+ /* api callbacks */
+ ot->invoke = datadropper_invoke;
+ ot->modal = datadropper_modal;
+ ot->cancel = datadropper_cancel;
+ ot->exec = datadropper_exec;
+ ot->poll = datadropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
new file mode 100644
index 00000000000..6e85d091fdb
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -0,0 +1,391 @@
+/*
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_depth.c
+ * \ingroup edinterface
+ *
+ * This file defines an eyedropper for picking 3D depth value (primary use is depth-of-field).
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_depth
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_string.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_unit.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+/**
+ * \note #DepthDropper is only internal name to avoid confusion with other kinds of eye-droppers.
+ */
+typedef struct DepthDropper {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ float init_depth; /* for resetting on cancel */
+
+ bool accum_start; /* has mouse been presed */
+ float accum_depth;
+ int accum_tot;
+
+ ARegionType *art;
+ void *draw_handle_pixel;
+ char name[200];
+} DepthDropper;
+
+
+static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
+{
+ DepthDropper *ddr = arg;
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
+}
+
+
+static int depthdropper_init(bContext *C, wmOperator *op)
+{
+ DepthDropper *ddr;
+ int index_dummy;
+
+ SpaceType *st;
+ ARegionType *art;
+
+ st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
+
+ op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
+
+ /* fallback to the active camera's dof */
+ if (ddr->prop == NULL) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
+ RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
+ ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
+ }
+ }
+ }
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_type(ddr->prop) != PROP_FLOAT))
+ {
+ return false;
+ }
+
+ ddr->art = art;
+ ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+ ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
+
+ return true;
+}
+
+static void depthdropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ DepthDropper *ddr = (DepthDropper *)op->customdata;
+
+ if (ddr->art) {
+ ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
+ }
+
+ MEM_freeN(op->customdata);
+
+ op->customdata = NULL;
+ }
+}
+
+/* *** depthdropper id helper functions *** */
+/**
+ * \brief get the ID from the screen.
+ *
+ */
+static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
+{
+ /* we could use some clever */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ Scene *scene = CTX_data_scene(C);
+
+ UnitSettings *unit = &scene->unit;
+ const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+
+ ddr->name[0] = '\0';
+
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
+ 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];
+
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
+
+ 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(&eval_ctx, graph, 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(v3d, 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));
+ }
+ }
+ }
+ }
+
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+}
+
+/* sets the sample depth RGB, maintaining A */
+static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
+{
+ RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
+ RNA_property_update(C, &ddr->ptr, ddr->prop);
+}
+
+/* set sample from accumulated values */
+static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
+{
+ float depth = ddr->accum_depth;
+ if (ddr->accum_tot) {
+ depth /= (float)ddr->accum_tot;
+ }
+ depthdropper_depth_set(C, ddr, depth);
+}
+
+/* single point sample & set */
+static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
+{
+ float depth = -1.0f;
+ if (depth != -1.0f) {
+ depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
+ depthdropper_depth_set(C, ddr, depth);
+ }
+}
+
+static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
+{
+ float depth = -1.0f;
+ depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
+ if (depth != -1.0f) {
+ ddr->accum_depth += depth;
+ ddr->accum_tot++;
+ }
+}
+
+static void depthdropper_cancel(bContext *C, wmOperator *op)
+{
+ DepthDropper *ddr = op->customdata;
+ depthdropper_depth_set(C, ddr, ddr->init_depth);
+ depthdropper_exit(C, op);
+}
+
+/* main modal status check */
+static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ DepthDropper *ddr = (DepthDropper *)op->customdata;
+
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ depthdropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ if (ddr->accum_tot == 0) {
+ depthdropper_depth_sample(C, ddr, event->x, event->y);
+ }
+ else {
+ depthdropper_depth_set_accum(C, ddr);
+ }
+ depthdropper_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_SAMPLE_BEGIN:
+ /* enable accum and make first sample */
+ ddr->accum_start = true;
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ ddr->accum_tot = 0;
+ ddr->accum_depth = 0.0f;
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_set_accum(C, ddr);
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (ddr->accum_start) {
+ /* button is pressed so keep sampling */
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_set_accum(C, ddr);
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (depthdropper_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ depthdropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int depthdropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (depthdropper_init(C, op)) {
+ /* cleanup */
+ depthdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int depthdropper_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* check if there's an active button taking depth value */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_NUM) &&
+ (prop != NULL))
+ {
+ if ((RNA_property_type(prop) == PROP_FLOAT) &&
+ (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
+ (RNA_property_array_check(prop) == false))
+ {
+ return 1;
+ }
+ }
+ else {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void UI_OT_eyedropper_depth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Depth";
+ ot->idname = "UI_OT_eyedropper_depth";
+ ot->description = "Sample depth from the 3D view";
+
+ /* api callbacks */
+ ot->invoke = depthdropper_invoke;
+ ot->modal = depthdropper_modal;
+ ot->cancel = depthdropper_cancel;
+ ot->exec = depthdropper_exec;
+ ot->poll = depthdropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
new file mode 100644
index 00000000000..50a8473135a
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -0,0 +1,234 @@
+/*
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_driver.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (Animation Driver Targets).
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_driver
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_animsys.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_keyframing.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+typedef struct DriverDropper {
+ /* Destination property (i.e. where we'll add a driver) */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ // TODO: new target?
+} DriverDropper;
+
+static bool driverdropper_init(bContext *C, wmOperator *op)
+{
+ DriverDropper *ddr;
+ uiBut *but;
+
+ op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
+
+ but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) ||
+ (but->flag & UI_BUT_DRIVEN))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static void driverdropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+ }
+}
+
+static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ DriverDropper *ddr = (DriverDropper *)op->customdata;
+ uiBut *but = eyedropper_get_property_button_under_mouse(C, event);
+
+ short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
+ short flag = 0;
+
+ /* we can only add a driver if we know what RNA property it corresponds to */
+ if (but == NULL) {
+ return;
+ }
+ else {
+ /* Get paths for src... */
+ PointerRNA *target_ptr = &but->rnapoin;
+ PropertyRNA *target_prop = but->rnaprop;
+ int target_index = but->rnaindex;
+
+ char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
+
+ /* ... and destination */
+ char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
+
+ /* Now create driver(s) */
+ if (target_path && dst_path) {
+ int success = ANIM_add_driver_with_target(op->reports,
+ ddr->ptr.id.data, dst_path, ddr->index,
+ target_ptr->id.data, target_path, target_index,
+ flag, DRIVER_TYPE_PYTHON, mapping_type);
+
+ if (success) {
+ /* send updates */
+ UI_context_update_anim_flag(C);
+ DEG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
+ }
+ }
+
+ /* cleanup */
+ if (target_path)
+ MEM_freeN(target_path);
+ if (dst_path)
+ MEM_freeN(dst_path);
+ }
+}
+
+static void driverdropper_cancel(bContext *C, wmOperator *op)
+{
+ driverdropper_exit(C, op);
+}
+
+/* main modal status check */
+static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ driverdropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ driverdropper_sample(C, op, event);
+ driverdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (driverdropper_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ driverdropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int driverdropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (driverdropper_init(C, op)) {
+ /* cleanup */
+ driverdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int driverdropper_poll(bContext *C)
+{
+ if (!CTX_wm_window(C)) return 0;
+ else return 1;
+}
+
+void UI_OT_eyedropper_driver(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Driver";
+ ot->idname = "UI_OT_eyedropper_driver";
+ ot->description = "Pick a property to use as a driver target";
+
+ /* api callbacks */
+ ot->invoke = driverdropper_invoke;
+ ot->modal = driverdropper_modal;
+ ot->cancel = driverdropper_cancel;
+ ot->exec = driverdropper_exec;
+ ot->poll = driverdropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
+ "Mapping Type", "Method used to match target and driven properties");
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
new file mode 100644
index 00000000000..18935c6cc9f
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -0,0 +1,54 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_intern.h
+ * \ingroup edinterface
+ *
+ * Share between interface_eyedropper_*.c files.
+ */
+
+#ifndef __INTERFACE_EYEDROPPER_INTERN_H__
+#define __INTERFACE_EYEDROPPER_INTERN_H__
+
+/* interface_eyedropper.c */
+void eyedropper_draw_cursor_text(const struct bContext *C, const struct ARegion *ar, const char *name);
+uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event);
+
+/* interface_eyedropper_color.c (expose for color-band picker) */
+void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]);
+
+/* Used for most eye-dropper operators. */
+enum {
+ EYE_MODAL_CANCEL = 1,
+ EYE_MODAL_SAMPLE_CONFIRM,
+ EYE_MODAL_SAMPLE_BEGIN,
+ EYE_MODAL_SAMPLE_RESET,
+};
+
+/* Color-band point sample. */
+enum {
+ EYE_MODAL_POINT_CANCEL = 1,
+ EYE_MODAL_POINT_SAMPLE,
+ EYE_MODAL_POINT_CONFIRM,
+ EYE_MODAL_POINT_RESET,
+ EYE_MODAL_POINT_REMOVE_LAST,
+};
+
+#endif /* __INTERFACE_EYEDROPPER_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 53505fc39a4..9ccb47938d2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -61,6 +61,7 @@
#include "PIL_time.h"
+#include "BKE_colorband.h"
#include "BKE_blender_undo.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
@@ -68,7 +69,6 @@
#include "BKE_idprop.h"
#include "BKE_report.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "BKE_tracking.h"
#include "BKE_unit.h"
#include "BKE_paint.h"
@@ -130,7 +130,6 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
/***************** structs and defines ****************/
-#define BUTTON_TOOLTIP_DELAY 0.500
#define BUTTON_FLASH_DELAY 0.020
#define MENU_SCROLL_INTERVAL 0.1
#define PIE_MENU_INTERVAL 0.01
@@ -297,8 +296,6 @@ typedef struct uiHandleButtonData {
ColorBand *coba;
/* tooltip */
- ARegion *tooltip;
- wmTimer *tooltiptimer;
unsigned int tooltip_force : 1;
/* auto open */
@@ -2295,7 +2292,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
char buf_copy[UI_MAX_DRAW_STR];
if (array_length == 4) {
- values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
+ values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
}
else {
values[3] = 0.0f;
@@ -5971,7 +5968,7 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
data->dragcbd->pos += dx;
CLAMP(data->dragcbd->pos, 0.0f, 1.0f);
- colorband_update_sort(data->coba);
+ BKE_colorband_update_sort(data->coba);
data->dragcbd = data->coba->data + data->coba->cur; /* because qsort */
data->draglastx = mx;
@@ -6001,7 +5998,7 @@ static int ui_do_but_COLORBAND(
if (event->ctrl) {
/* insert new key on mouse location */
float pos = ((float)(mx - but->rect.xmin)) / BLI_rctf_size_x(&but->rect);
- colorband_element_add(coba, pos);
+ BKE_colorband_element_add(coba, pos);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else {
@@ -6022,6 +6019,7 @@ static int ui_do_but_COLORBAND(
}
data->dragcbd = coba->data + coba->cur;
+ data->dragfstart = data->dragcbd->pos;
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
}
@@ -6038,7 +6036,15 @@ static int ui_do_but_COLORBAND(
else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
-
+ else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ data->dragcbd->pos = data->dragfstart;
+ BKE_colorband_update_sort(data->coba);
+ data->cancel = true;
+ data->escapecancel = true;
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ }
return WM_UI_HANDLER_BREAK;
}
@@ -6047,8 +6053,8 @@ static int ui_do_but_COLORBAND(
static bool ui_numedit_but_CURVE(
uiBlock *block, uiBut *but, uiHandleButtonData *data,
- int evtx, int evty,
- bool snap, const bool shift)
+ int evtx, int evty,
+ bool snap, const bool shift)
{
CurveMapping *cumap = (CurveMapping *)but->poin;
CurveMap *cuma = cumap->cm + cumap->cur;
@@ -7733,12 +7739,12 @@ static bool button_modal_state(uiHandleButtonState state)
*/
void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
- uiHandleButtonData *data;
-
- data = but->active;
- if (data && data->tooltip) {
- ui_tooltip_free(C, data->tooltip);
- data->tooltip = ui_tooltip_create(C, data->region, but);
+ uiHandleButtonData *data = but->active;
+ if (data) {
+ bScreen *sc = WM_window_get_active_screen(data->window);
+ if (sc->tool_tip && sc->tool_tip->region) {
+ WM_tooltip_refresh(C, data->window);
+ }
}
}
@@ -7749,39 +7755,38 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
data = but->active;
if (data) {
-
- if (data->tooltiptimer) {
- WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
- data->tooltiptimer = NULL;
- }
- if (data->tooltip) {
- ui_tooltip_free(C, data->tooltip);
- data->tooltip = NULL;
- }
-
if (data->autoopentimer) {
WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
data->autoopentimer = NULL;
}
+
+ if (data->window) {
+ WM_tooltip_clear(C, data->window);
+ }
}
}
+static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event)
+{
+ uiBut *but = UI_region_active_but_get(ar);
+ *r_exit_on_event = false;
+ if (but) {
+ return UI_tooltip_create_from_button(C, ar, but);
+ }
+ return NULL;
+}
+
static void button_tooltip_timer_reset(bContext *C, uiBut *but)
{
wmWindowManager *wm = CTX_wm_manager(C);
- uiHandleButtonData *data;
-
- data = but->active;
+ uiHandleButtonData *data = but->active;
- if (data->tooltiptimer) {
- WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
- data->tooltiptimer = NULL;
- }
+ WM_tooltip_timer_clear(C, data->window);
if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) {
if (!but->block->tooltipdisabled) {
if (!wm->drags.first) {
- data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY);
+ WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init);
}
}
}
@@ -8141,12 +8146,10 @@ void ui_but_active_free(const bContext *C, uiBut *but)
}
/* returns the active button with an optional checking function */
-static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *))
+static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *))
{
uiBut *but_found = NULL;
- ARegion *ar = CTX_wm_region(C);
-
while (ar) {
uiBlock *block;
uiBut *but, *activebut = NULL;
@@ -8189,12 +8192,17 @@ static bool ui_context_rna_button_active_test(uiBut *but)
}
static uiBut *ui_context_rna_button_active(const bContext *C)
{
- return ui_context_button_active(C, ui_context_rna_button_active_test);
+ return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test);
}
uiBut *UI_context_active_but_get(const struct bContext *C)
{
- return ui_context_button_active(C, NULL);
+ return ui_context_button_active(CTX_wm_region(C), NULL);
+}
+
+uiBut *UI_region_active_but_get(ARegion *ar)
+{
+ return ui_context_button_active(ar, NULL);
}
/**
@@ -8477,16 +8485,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
case TIMER:
{
- /* handle tooltip timer */
- if (event->customdata == data->tooltiptimer) {
- WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
- data->tooltiptimer = NULL;
-
- if (!data->tooltip)
- data->tooltip = ui_tooltip_create(C, data->region, but);
- }
/* handle menu auto open timer */
- else if (event->customdata == data->autoopentimer) {
+ if (event->customdata == data->autoopentimer) {
WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
data->autoopentimer = NULL;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 6f450093d30..b2f7d400254 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -595,8 +595,7 @@ struct uiPopupBlockHandle {
/* interface_region_*.c */
/* interface_region_tooltip.c */
-struct ARegion *ui_tooltip_create(struct bContext *C, struct ARegion *butregion, uiBut *but);
-void ui_tooltip_free(struct bContext *C, struct ARegion *ar);
+/* exposed as public API in UI_interface.h */
/* interface_region_color_picker.c */
void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]);
@@ -764,9 +763,22 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl
/* interface_eyedropper.c */
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
+struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
+
+/* interface_eyedropper_color.c */
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
+
+/* interface_eyedropper_colorband.c */
+void UI_OT_eyedropper_colorband(struct wmOperatorType *ot);
+void UI_OT_eyedropper_colorband_point(struct wmOperatorType *ot);
+
+/* interface_eyedropper_datablock.c */
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
+
+/* interface_eyedropper_depth.c */
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
+
+/* interface_eyedropper_driver.c */
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
/* interface_util.c */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 645afc03603..27d58c3be1b 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1746,7 +1746,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
}
else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */
- but->type = UI_BTYPE_LABEL;
+ but->flag |= UI_BUT_DISABLED;
}
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index bbcd10270d5..16525dfbc9e 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1466,6 +1466,8 @@ void ED_operatortypes_ui(void)
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
+ WM_operatortype_append(UI_OT_eyedropper_colorband);
+ WM_operatortype_append(UI_OT_eyedropper_colorband_point);
WM_operatortype_append(UI_OT_eyedropper_id);
WM_operatortype_append(UI_OT_eyedropper_depth);
WM_operatortype_append(UI_OT_eyedropper_driver);
@@ -1482,6 +1484,8 @@ void ED_keymap_ui(wmKeyConfig *keyconf)
/* eyedroppers - notice they all have the same shortcut, but pass the event
* through until a suitable eyedropper for the active button is found */
WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0);
@@ -1504,4 +1508,5 @@ void ED_keymap_ui(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0);
eyedropper_modal_keymap(keyconf);
+ eyedropper_colorband_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index f71b71fce43..07fbefa42e1 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -29,6 +29,14 @@
* ToolTip Region and Construction
*/
+/* TODO(campbell):
+ * We may want to have a higher level API that initializes a timer,
+ * checks for mouse motion and clears the tool-tip afterwards.
+ * We never want multiple tool-tips at once so this could be handled on the window / window-manager level.
+ *
+ * For now it's not a priority, so leave as-is.
+ */
+
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -97,7 +105,6 @@ typedef struct uiTooltipField {
} uiTooltipField;
-#define MAX_TOOLTIP_LINES 8
typedef struct uiTooltipData {
rcti bbox;
uiTooltipField *fields;
@@ -314,8 +321,6 @@ static uiTooltipData *ui_tooltip_data_from_keymap(bContext *C, wmKeyMap *keymap)
/* create tooltip data */
uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
- BLI_assert(data->fields_len < MAX_TOOLTIP_LINES);
-
for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
if (ot != NULL) {
@@ -609,8 +614,6 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
if (rna_prop.strinfo)
MEM_freeN(rna_prop.strinfo);
- BLI_assert(data->fields_len < MAX_TOOLTIP_LINES);
-
if (data->fields_len == 0) {
MEM_freeN(data);
return NULL;
@@ -620,13 +623,116 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
-/** \} */
+static uiTooltipData *ui_tooltip_data_from_manipulator(bContext *C, wmManipulator *mpr)
+{
+ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
-/* -------------------------------------------------------------------- */
-/** \name ToolTip Public API
- * \{ */
+ /* TODO(campbell): a way for manipulators to have their own descriptions (low priority). */
+
+ /* Operator Actions */
+ {
+ bool use_drag = mpr->drag_part != -1 && mpr->highlight_part != mpr->drag_part;
+
+ const struct {
+ int part;
+ const char *prefix;
+ } mpop_actions[] = {
+ {
+ .part = mpr->highlight_part,
+ .prefix = use_drag ? TIP_("Click") : NULL,
+ }, {
+ .part = use_drag ? mpr->drag_part : -1,
+ .prefix = use_drag ? TIP_("Drag") : NULL,
+ },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(mpop_actions); i++) {
+ wmManipulatorOpElem *mpop = (mpop_actions[i].part != -1) ? WM_manipulator_operator_get(mpr, mpop_actions[i].part) : NULL;
+ if (mpop != NULL) {
+ /* Description */
+ const char *info = RNA_struct_ui_description(mpop->type->srna);
+ if (!(info && info[0])) {
+ info = RNA_struct_ui_name(mpop->type->srna);
+ }
-ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
+ if (info && info[0]) {
+ char *text = NULL;
+ if (mpop_actions[i].prefix != NULL) {
+ text = BLI_sprintfN("%s: %s", mpop_actions[i].prefix, info);
+ }
+ else {
+ text = BLI_strdup(info);
+ }
+
+ if (text != NULL) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_HEADER,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = text;
+ }
+ }
+
+ /* Shortcut */
+ {
+ bool found = false;
+ IDProperty *prop = mpop->ptr.data;
+ char buf[128];
+ if (WM_key_event_operator_string(
+ C, mpop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true,
+ buf, ARRAY_SIZE(buf)))
+ {
+ found = true;
+ }
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None");
+ }
+ }
+ }
+ }
+
+ /* Property Actions */
+ if (mpr->type->target_property_defs_len) {
+ wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
+ for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
+ /* TODO(campbell): function callback descriptions. */
+ wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
+ if (mpr_prop->prop != NULL) {
+ const char *info = RNA_property_ui_description(mpr_prop->prop);
+ if (info && info[0]) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(info);
+ }
+ }
+ }
+ }
+
+ if (data->fields_len == 0) {
+ MEM_freeN(data);
+ return NULL;
+ }
+ else {
+ return data;
+ }
+}
+
+
+static ARegion *ui_tooltip_create_with_data(
+ bContext *C, uiTooltipData *data,
+ const float init_position[2],
+ const float aspect)
{
const float pad_px = UI_TIP_PADDING;
wmWindow *win = CTX_wm_window(C);
@@ -634,43 +740,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
uiStyle *style = UI_style_get();
static ARegionType type;
ARegion *ar;
-/* IDProperty *prop;*/
- /* aspect values that shrink text are likely unreadable */
- const float aspect = min_ff(1.0f, but->block->aspect);
int fonth, fontw;
- int ofsx, ofsy, h, i;
+ int h, i;
rctf rect_fl;
rcti rect_i;
int font_flag = 0;
- if (but->drawflag & UI_BUT_NO_TOOLTIP) {
- return NULL;
- }
- uiTooltipData *data = NULL;
-
- /* custom tips for pre-defined operators */
- if (but->optype) {
- if (STREQ(but->optype->idname, "WM_OT_tool_set")) {
- char keymap[64] = "";
- RNA_string_get(but->opptr, "keymap", keymap);
- if (keymap[0]) {
- ScrArea *sa = CTX_wm_area(C);
- wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW);
- if (km != NULL) {
- data = ui_tooltip_data_from_keymap(C, km);
- }
- }
- }
- }
- /* toolsystem exception */
-
- if (data == NULL) {
- data = ui_tooltip_data_from_button(C, but);
- }
- if (data == NULL) {
- return NULL;
- }
-
/* create area region */
ar = ui_region_temp_add(CTX_wm_screen(C));
@@ -748,31 +823,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->lineh = h;
/* compute position */
- ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0;
- ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0;
- rect_fl.xmin = BLI_rctf_cent_x(&but->rect) + ofsx - TIP_BORDER_X;
+ rect_fl.xmin = init_position[0] - TIP_BORDER_X;
rect_fl.xmax = rect_fl.xmin + fontw + pad_px;
- rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y;
+ rect_fl.ymax = init_position[1] - TIP_BORDER_Y;
rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y;
- /* since the text has beens caled already, the size of tooltips is defined now */
- /* here we try to figure out the right location */
- if (butregion) {
- float mx, my;
- float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax;
- ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl);
-
-#if 1
- /* use X mouse location */
- mx = (win->eventstate->x + (TIP_BORDER_X * 2)) - BLI_rctf_cent_x(&but->rect);
-#else
- mx = ofsx_fl - rect_fl.xmin;
-#endif
- my = ofsy_fl - rect_fl.ymax;
-
- BLI_rctf_translate(&rect_fl, mx, my);
- }
BLI_rcti_rctf_copy(&rect_i, &rect_fl);
#undef TIP_BORDER_X
@@ -827,9 +883,79 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
return ar;
}
-void ui_tooltip_free(bContext *C, ARegion *ar)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ToolTip Public API
+ * \{ */
+
+
+ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but)
+{
+ wmWindow *win = CTX_wm_window(C);
+ /* aspect values that shrink text are likely unreadable */
+ const float aspect = min_ff(1.0f, but->block->aspect);
+ float init_position[2];
+
+ if (but->drawflag & UI_BUT_NO_TOOLTIP) {
+ return NULL;
+ }
+ uiTooltipData *data = NULL;
+
+ /* custom tips for pre-defined operators */
+ if (but->optype) {
+ if (STREQ(but->optype->idname, "WM_OT_tool_set")) {
+ char keymap[64] = "";
+ RNA_string_get(but->opptr, "keymap", keymap);
+ if (keymap[0]) {
+ ScrArea *sa = CTX_wm_area(C);
+ wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW);
+ if (km != NULL) {
+ data = ui_tooltip_data_from_keymap(C, km);
+ }
+ }
+ }
+ }
+ /* toolsystem exception */
+
+ if (data == NULL) {
+ data = ui_tooltip_data_from_button(C, but);
+ }
+ if (data == NULL) {
+ return NULL;
+ }
+
+ init_position[0] = BLI_rctf_cent_x(&but->rect);
+ init_position[1] = but->rect.ymin;
+
+ if (butregion) {
+ ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
+ init_position[0] = win->eventstate->x;
+ }
+
+ return ui_tooltip_create_with_data(C, data, init_position, aspect);
+}
+
+ARegion *UI_tooltip_create_from_manipulator(bContext *C, wmManipulator *mpr)
+{
+ wmWindow *win = CTX_wm_window(C);
+ const float aspect = 1.0f;
+ float init_position[2];
+
+ uiTooltipData *data = ui_tooltip_data_from_manipulator(C, mpr);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ init_position[0] = win->eventstate->x;
+ init_position[1] = win->eventstate->y;
+
+ return ui_tooltip_create_with_data(C, data, init_position, aspect);
+}
+
+void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar)
{
- ui_region_temp_remove(C, CTX_wm_screen(C), ar);
+ ui_region_temp_remove(C, sc, ar);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 78874076b92..ce2d3bebb97 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -53,6 +53,7 @@
#include "BLF_api.h"
#include "BLT_translation.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -60,6 +61,7 @@
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
@@ -70,7 +72,6 @@
#include "BKE_report.h"
#include "BKE_sca.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -233,6 +234,8 @@ typedef struct TemplateID {
PropertyRNA *prop;
ListBase *idlb;
+ short idcode;
+ short filter;
int prv_rows, prv_cols;
bool preview;
} TemplateID;
@@ -240,73 +243,147 @@ typedef struct TemplateID {
/* Search browse menu, assign */
static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item)
{
- TemplateID *template = (TemplateID *)arg_template;
+ TemplateID *template_ui = (TemplateID *)arg_template;
/* ID */
if (item) {
PointerRNA idptr;
RNA_id_pointer_create(item, &idptr);
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
}
}
+static bool id_search_add(
+ const bContext *C, TemplateID *template_ui,
+ const int flag, const char *str, uiSearchItems *items,
+ ID *id)
+{
+ ID *id_from = template_ui->ptr.id.data;
+
+ if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
+
+ /* use filter */
+ if (RNA_property_type(template_ui->prop) == PROP_POINTER) {
+ PointerRNA ptr;
+ RNA_id_pointer_create(id, &ptr);
+ if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) {
+ return true;
+ }
+ }
+
+ /* hide dot-datablocks, but only if filter does not force it visible */
+ if (U.uiflag & USER_HIDE_DOT) {
+ if ((id->name[2] == '.') && (str[0] != '.')) {
+ return true;
+ }
+ }
+
+ if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) {
+ /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
+ * followed by ID_NAME-2 characters from id->name
+ */
+ char name_ui[MAX_ID_NAME + 1];
+ BKE_id_ui_prefix(name_ui, id);
+
+ int iconid = ui_id_icon_get(C, id, template_ui->preview);
+
+ if (false == UI_search_item_add(items, name_ui, id, iconid)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/* ID Search browse menu, do the search */
static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
{
- TemplateID *template = (TemplateID *)arg_template;
- ListBase *lb = template->idlb;
- ID *id, *id_from = template->ptr.id.data;
- int iconid;
- int flag = RNA_property_flag(template->prop);
+ TemplateID *template_ui = (TemplateID *)arg_template;
+ ListBase *lb = template_ui->idlb;
+ ID *id;
+ int flag = RNA_property_flag(template_ui->prop);
/* ID listbase */
for (id = lb->first; id; id = id->next) {
- if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
-
- /* use filter */
- if (RNA_property_type(template->prop) == PROP_POINTER) {
- PointerRNA ptr;
- RNA_id_pointer_create(id, &ptr);
- if (RNA_property_pointer_poll(&template->ptr, template->prop, &ptr) == 0)
- continue;
+ if (!id_search_add(C, template_ui, flag, str, items, id)) {
+ break;
+ }
+ }
+}
+
+/**
+ * Use id tags for filtering.
+ */
+static void id_search_cb_tagged(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
+{
+ TemplateID *template_ui = (TemplateID *)arg_template;
+ ListBase *lb = template_ui->idlb;
+ ID *id;
+ int flag = RNA_property_flag(template_ui->prop);
+
+ /* ID listbase */
+ for (id = lb->first; id; id = id->next) {
+ if (id->tag & LIB_TAG_DOIT) {
+ if (!id_search_add(C, template_ui, flag, str, items, id)) {
+ break;
}
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+}
- /* hide dot-datablocks, but only if filter does not force it visible */
- if (U.uiflag & USER_HIDE_DOT)
- if ((id->name[2] == '.') && (str[0] != '.'))
- continue;
+/**
+ * A version of 'id_search_cb' that lists scene objects.
+ */
+static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
+{
+ TemplateID *template_ui = (TemplateID *)arg_template;
+ ListBase *lb = template_ui->idlb;
+ Scene *scene = NULL;
+ ID *id_from = template_ui->ptr.id.data;
- if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) {
- /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
- * followed by ID_NAME-2 characters from id->name
- */
- char name_ui[MAX_ID_NAME + 1];
- BKE_id_ui_prefix(name_ui, id);
+ if (id_from && GS(id_from->name) == ID_SCE) {
+ scene = (Scene *)id_from;
+ }
+ else {
+ scene = CTX_data_scene(C);
+ }
- iconid = ui_id_icon_get(C, id, template->preview);
+ BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false);
- if (false == UI_search_item_add(items, name_ui, id, iconid))
- break;
- }
- }
+ FOREACH_SCENE_OBJECT(scene, ob_iter)
+ {
+ ob_iter->id.tag |= LIB_TAG_DOIT;
}
+ FOREACH_SCENE_OBJECT_END
+ id_search_cb_tagged(C, arg_template, str, items);
}
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
{
- static TemplateID template;
+ static TemplateID template_ui;
PointerRNA active_item_ptr;
+ void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
/* arg_litem is malloced, can be freed by parent button */
- template = *((TemplateID *)arg_litem);
- active_item_ptr = RNA_property_pointer_get(&template.ptr, template.prop);
+ template_ui = *((TemplateID *)arg_litem);
+ active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
+
+ if (template_ui.filter) {
+ /* Currently only used for objects. */
+ if (template_ui.idcode == ID_OB) {
+ if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) {
+ id_search_cb_p = id_search_cb_objects_from_scene;
+ }
+ }
+ }
return template_common_search_menu(
- C, ar, id_search_cb, &template, template_ID_set_property_cb, active_item_ptr.data,
- template.prv_rows, template.prv_cols);
+ C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data,
+ template_ui.prv_rows, template_ui.prv_cols);
}
/************************ ID Template ***************************/
@@ -317,7 +394,7 @@ void UI_context_active_but_prop_get_templateID(
bContext *C,
PointerRNA *r_ptr, PropertyRNA **r_prop)
{
- TemplateID *template;
+ TemplateID *template_ui;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
@@ -333,9 +410,9 @@ void UI_context_active_but_prop_get_templateID(
/* find the button before the active one */
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
- template = but->func_argN;
- *r_ptr = template->ptr;
- *r_prop = template->prop;
+ template_ui = but->func_argN;
+ *r_ptr = template_ui->ptr;
+ *r_prop = template_ui->prop;
return;
}
}
@@ -346,8 +423,8 @@ void UI_context_active_but_prop_get_templateID(
static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
{
- TemplateID *template = (TemplateID *)arg_litem;
- PointerRNA idptr = RNA_property_pointer_get(&template->ptr, template->prop);
+ TemplateID *template_ui = (TemplateID *)arg_litem;
+ PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
ID *id = idptr.data;
int event = GET_INT_FROM_POINTER(arg_event);
@@ -362,8 +439,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_DELETE:
memset(&idptr, 0, sizeof(idptr));
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
if (id && CTX_wm_window(C)->eventstate->shift) {
/* only way to force-remove data (on save) */
@@ -384,20 +461,40 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
case UI_ID_LOCAL:
if (id) {
Main *bmain = CTX_data_main(C);
- if (id_make_local(bmain, id, false, false)) {
- BKE_main_id_clear_newpoins(bmain);
+ if (CTX_wm_window(C)->eventstate->shift) {
+ ID *override_id = BKE_override_static_create_from_id(bmain, id);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
- /* reassign to get get proper updates/notifiers */
- idptr = RNA_property_pointer_get(&template->ptr, template->prop);
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
+ /* Assign new pointer, takes care of updates/notifiers */
+ RNA_id_pointer_create(override_id, &idptr);
+ }
}
+ else {
+ if (id_make_local(bmain, id, false, false)) {
+ BKE_main_id_clear_newpoins(bmain);
+
+ /* reassign to get get proper updates/notifiers */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ }
+ }
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
+ }
+ break;
+ case UI_ID_OVERRIDE:
+ if (id && id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ /* reassign to get get proper updates/notifiers */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
}
break;
case UI_ID_ALONE:
if (id) {
const bool do_scene_obj = (GS(id->name) == ID_OB) &&
- (template->ptr.type == &RNA_SceneObjects);
+ (template_ui->ptr.type == &RNA_SceneObjects);
/* make copy */
if (do_scene_obj) {
@@ -410,7 +507,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
else {
if (id) {
Main *bmain = CTX_data_main(C);
- id_single_user(C, id, &template->ptr, template->prop);
+ id_single_user(C, id, &template_ui->ptr, template_ui->prop);
DEG_relations_tag_update(bmain);
}
}
@@ -477,10 +574,10 @@ static const char *template_id_context(StructRNA *type)
#endif
static uiBut *template_id_def_new_but(
- uiBlock *block, const ID *id, const TemplateID *template, StructRNA *type,
+ uiBlock *block, const ID *id, const TemplateID *template_ui, StructRNA *type,
const char * const newop, const bool editable, const bool id_open, const bool use_tab_but)
{
- ID *idfrom = template->ptr.id.data;
+ ID *idfrom = template_ui->ptr.id.data;
uiBut *but;
const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT;
@@ -518,12 +615,12 @@ static uiBut *template_id_def_new_but(
if (newop) {
but = uiDefIconTextButO(block, but_type, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN,
(id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
}
else {
but = uiDefIconTextBut(block, but_type, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
}
if ((idfrom && idfrom->lib) || !editable) {
@@ -538,7 +635,7 @@ static uiBut *template_id_def_new_but(
}
static void template_ID(
- bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
+ bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag,
const char *newop, const char *openop, const char *unlinkop)
{
uiBut *but;
@@ -546,13 +643,13 @@ static void template_ID(
PointerRNA idptr;
// ListBase *lb; // UNUSED
ID *id, *idfrom;
- const bool editable = RNA_property_editable(&template->ptr, template->prop);
- const bool use_previews = template->preview = (flag & UI_ID_PREVIEWS) != 0;
+ const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop);
+ const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0;
- idptr = RNA_property_pointer_get(&template->ptr, template->prop);
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
id = idptr.data;
- idfrom = template->ptr.id.data;
- // lb = template->idlb;
+ idfrom = template_ui->ptr.id.data;
+ // lb = template_ui->idlb;
block = uiLayoutGetBlock(layout);
UI_block_align_begin(block);
@@ -562,8 +659,8 @@ static void template_ID(
if (flag & UI_ID_BROWSE) {
template_add_button_search_menu(
- C, layout, block, &template->ptr, template->prop,
- id_search_menu, MEM_dupallocN(template), TIP_(template_id_browse_tip(type)),
+ C, layout, block, &template_ui->ptr, template_ui->prop,
+ id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)),
use_previews, editable);
}
@@ -577,7 +674,7 @@ static void template_ID(
but = uiDefButR(
block, UI_BTYPE_TEXT, 0, name, 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT,
&idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_RENAME));
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib) {
@@ -587,13 +684,25 @@ static void template_ID(
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
+ const bool disabled = (!id_make_local(CTX_data_main(C), id, true /* test */, false) ||
+ (idfrom && idfrom->lib));
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local"));
- if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib))
+ NULL, 0, 0, 0, 0,
+ TIP_("Direct linked library data-block, click to make local, "
+ "Shift + Click to create a static override"));
+ if (disabled) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+ else {
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_LOCAL));
+ }
}
-
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
+ }
+ else if (ID_IS_STATIC_OVERRIDE(id)) {
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0,
+ TIP_("Static override of linked library data-block, click to make fully local"));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OVERRIDE));
}
if (id->us > 1) {
@@ -607,7 +716,7 @@ static void template_ID(
TIP_("Display number of users of this data (click to make a single-user copy)"));
but->flag |= UI_BUT_UNDO;
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ALONE));
if (/* test only */
(id_copy(CTX_data_main(C), id, NULL, true) == false) ||
(idfrom && idfrom->lib) ||
@@ -627,7 +736,7 @@ static void template_ID(
}
if (flag & UI_ID_ADD_NEW) {
- template_id_def_new_but(block, id, template, type, newop, editable, flag & UI_ID_OPEN, false);
+ template_id_def_new_but(block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false);
}
/* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
@@ -647,12 +756,12 @@ static void template_ID(
if (openop) {
but = uiDefIconTextButO(block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"),
0, 0, w, UI_UNIT_Y, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN));
}
else {
but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y,
NULL, 0, 0, 0, 0, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN));
}
if ((idfrom && idfrom->lib) || !editable)
@@ -668,16 +777,16 @@ static void template_ID(
if (unlinkop) {
but = uiDefIconButO(block, UI_BTYPE_BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
/* so we can access the template from operators, font unlinking needs this */
- UI_but_funcN_set(but, NULL, MEM_dupallocN(template), NULL);
+ UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL);
}
else {
- if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
+ if ((RNA_property_flag(template_ui->prop) & PROP_NEVER_UNLINK) == 0) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
TIP_("Unlink data-block "
"(Shift + Click to set users to zero, data will then not be saved)"));
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_DELETE));
- if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) {
+ if (RNA_property_flag(template_ui->prop) & PROP_NEVER_NULL) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
@@ -690,9 +799,9 @@ static void template_ID(
}
}
- if (idcode == ID_TE)
- uiTemplateTextureShow(layout, C, &template->ptr, template->prop);
-
+ if (template_ui->idcode == ID_TE) {
+ uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop);
+ }
UI_block_align_end(block);
}
@@ -746,9 +855,9 @@ static void ui_template_id(
uiLayout *layout, bContext *C,
PointerRNA *ptr, const char *propname,
const char *newop, const char *openop, const char *unlinkop,
- int flag, int prv_rows, int prv_cols, bool use_tabs)
+ int flag, int prv_rows, int prv_cols, int filter, bool use_tabs)
{
- TemplateID *template;
+ TemplateID *template_ui;
PropertyRNA *prop;
StructRNA *type;
short idcode;
@@ -760,11 +869,18 @@ static void ui_template_id(
return;
}
- template = MEM_callocN(sizeof(TemplateID), "TemplateID");
- template->ptr = *ptr;
- template->prop = prop;
- template->prv_rows = prv_rows;
- template->prv_cols = prv_cols;
+ template_ui = MEM_callocN(sizeof(TemplateID), "TemplateID");
+ template_ui->ptr = *ptr;
+ template_ui->prop = prop;
+ template_ui->prv_rows = prv_rows;
+ template_ui->prv_cols = prv_cols;
+
+ if ((flag & UI_ID_PIN) == 0) {
+ template_ui->filter = filter;
+ }
+ else {
+ template_ui->filter = 0;
+ }
if (newop)
flag |= UI_ID_ADD_NEW;
@@ -773,56 +889,57 @@ static void ui_template_id(
type = RNA_property_pointer_type(ptr, prop);
idcode = RNA_type_to_ID_code(type);
- template->idlb = which_libbase(CTX_data_main(C), idcode);
-
+ template_ui->idcode = idcode;
+ template_ui->idlb = which_libbase(CTX_data_main(C), idcode);
+
/* create UI elements for this template
* - template_ID makes a copy of the template data and assigns it to the relevant buttons
*/
- if (template->idlb) {
+ if (template_ui->idlb) {
if (use_tabs) {
uiLayoutRow(layout, false);
- template_ID_tabs(C, layout, template, type, flag, newop, openop, unlinkop);
+ template_ID_tabs(C, layout, template_ui, type, flag, newop, openop, unlinkop);
}
else {
uiLayoutRow(layout, true);
- template_ID(C, layout, template, type, idcode, flag, newop, openop, unlinkop);
+ template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop);
}
}
- MEM_freeN(template);
+ MEM_freeN(template_ui);
}
void uiTemplateID(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+ const char *openop, const char *unlinkop, int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
- 0, 0, false);
+ 0, 0, filter, false);
}
void uiTemplateIDBrowse(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+ const char *openop, const char *unlinkop, int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME,
- 0, 0, false);
+ 0, 0, filter, false);
}
void uiTemplateIDPreview(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int rows, int cols)
+ const char *openop, const char *unlinkop, int rows, int cols, int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
- rows, cols, false);
+ rows, cols, filter, false);
}
/**
@@ -831,13 +948,14 @@ void uiTemplateIDPreview(
void uiTemplateIDTabs(
uiLayout *layout, bContext *C,
PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop)
+ const char *newop, const char *openop, const char *unlinkop,
+ int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
- 0, 0, true);
+ 0, 0, filter, true);
}
/************************ ID Chooser Template ***************************/
@@ -1868,7 +1986,7 @@ static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
else pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f;
}
- if (colorband_element_add(coba, pos)) {
+ if (BKE_colorband_element_add(coba, pos)) {
rna_update_cb(C, cb_v, NULL);
ED_undo_push(C, "Add colorband");
}
@@ -1878,7 +1996,7 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
{
ColorBand *coba = coba_v;
- if (colorband_element_remove(coba, coba->cur)) {
+ if (BKE_colorband_element_remove(coba, coba->cur)) {
ED_undo_push(C, "Delete colorband");
rna_update_cb(C, cb_v, NULL);
}
@@ -1914,7 +2032,7 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
/* sneaky update here, we need to sort the colorband points to be in order,
* however the RNA pointer then is wrong, so we update it */
- colorband_update_sort(coba);
+ BKE_colorband_update_sort(coba);
bt->rnapoin.data = coba->data + coba->cur;
}
@@ -1949,6 +2067,11 @@ static void colorband_buttons_layout(
bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Flip the color ramp"));
UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
+
+ bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, xs + 6.0f * unit, ys + UI_UNIT_Y, UI_UNIT_X, UI_UNIT_Y, NULL);
+ bt->custom_data = coba;
+ bt->func_argN = MEM_dupallocN(cb);
+
UI_block_align_end(block);
UI_block_emboss_set(block, UI_EMBOSS);
@@ -3902,6 +4025,7 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(
uiLayout *col; /* needed to avoid alignment errors with previous buttons */
col = uiLayoutColumn(layout, false);
+ block = uiLayoutGetBlock(col);
but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults"));
UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
@@ -4493,7 +4617,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
- uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!file) {
return;
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 8c894c7852e..a9c3f973569 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -707,6 +707,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* backdrop non AA */
if (wtb->draw_inner) {
+ BLI_assert(wtb->totvert != 0);
if (wcol->shaded == 0) {
if (wcol->alpha_check) {
float inner_v_half[WIDGET_SIZE_MAX][2];
@@ -784,6 +785,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* for each AA step */
if (wtb->draw_outline) {
+ BLI_assert(wtb->totvert != 0);
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 */
@@ -2784,6 +2786,10 @@ static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int
if (!emboss) {
round_box_edges(&wtb, roundboxalign, rect, rad);
}
+ else {
+ wtb.draw_inner = false;
+ wtb.draw_outline = false;
+ }
/* decoration */
if (!(state & UI_STATE_TEXT_INPUT)) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index cd90da24951..ac5fb3e40cb 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -46,10 +46,10 @@
#include "BLI_math.h"
#include "BKE_appdir.h"
+#include "BKE_colorband.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BKE_texture.h"
#include "BIF_gl.h"
@@ -2011,7 +2011,7 @@ void init_userdef_do_versions(void)
rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
}
if (U.coba_weight.tot == 0)
- init_colorband(&U.coba_weight, true);
+ BKE_colorband_init(&U.coba_weight, true);
}
if (!USER_VERSION_ATLEAST(245, 3)) {
bTheme *btheme;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index b271b0b5bc6..dc68c8b58de 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1509,6 +1509,9 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), v2d->smooth_timer);
v2d->smooth_timer = NULL;
+
+ /* Event handling won't know if a UI item has been moved under the pointer. */
+ WM_event_add_mousemove(C);
}
else {
/* ease in/out */
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index fc227a2aa75..1b7fd319da0 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -40,6 +40,8 @@
#include "BKE_main.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "ED_screen.h"
#include "ED_object.h"
@@ -447,6 +449,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
min_chain_length,
keep_bind_info) )
{
+ DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE);
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/manipulator_library/CMakeLists.txt b/source/blender/editors/manipulator_library/CMakeLists.txt
index 9f7df8c6425..86e1bb3b6d7 100644
--- a/source/blender/editors/manipulator_library/CMakeLists.txt
+++ b/source/blender/editors/manipulator_library/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
geometry/geom_dial_manipulator.c
manipulator_types/arrow2d_manipulator.c
manipulator_types/arrow3d_manipulator.c
+ manipulator_types/button2d_manipulator.c
manipulator_types/cage2d_manipulator.c
manipulator_types/cage3d_manipulator.c
manipulator_types/dial3d_manipulator.c
diff --git a/source/blender/editors/manipulator_library/manipulator_library_utils.c b/source/blender/editors/manipulator_library/manipulator_library_utils.c
index 38b518b1992..12f9d1b48d3 100644
--- a/source/blender/editors/manipulator_library/manipulator_library_utils.c
+++ b/source/blender/editors/manipulator_library/manipulator_library_utils.c
@@ -195,7 +195,7 @@ bool manipulator_window_project_2d(
float ray_origin[3], ray_direction[3];
- if (ED_view3d_win_to_ray(ar, v3d, mval, ray_origin, ray_direction, false)) {
+ if (ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, mval, ray_origin, ray_direction, false)) {
float lambda;
if (isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, true)) {
float co[3];
diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c
index e9760e3e270..cc8fd72aa03 100644
--- a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c
+++ b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c
@@ -236,90 +236,65 @@ static int manipulator_arrow_modal(
{
ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
ManipulatorInteraction *inter = mpr->interaction_data;
+ View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
- float orig_origin[4];
- float viewvec[3], tangent[3], plane[3];
- float offset[4];
- float m_diff[2];
- float dir_2d[2], dir2d_final[2];
+ float offset[3];
float facdir = 1.0f;
- bool use_vertical = false;
+ /* (src, dst) */
+ struct {
+ float mval[2];
+ float ray_origin[3], ray_direction[3];
+ float location[3];
+ } proj[2] = {
+ {.mval = {UNPACK2(inter->init_mval)}},
+ {.mval = {UNPACK2(event->mval)}},
+ };
- copy_v3_v3(orig_origin, inter->init_matrix_basis[3]);
- orig_origin[3] = 1.0f;
- add_v3_v3v3(offset, orig_origin, arrow->manipulator.matrix_basis[2]);
- offset[3] = 1.0f;
-
- /* calculate view vector */
- if (rv3d->is_persp) {
- sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]);
- }
- else {
- copy_v3_v3(viewvec, rv3d->viewinv[2]);
- }
- normalize_v3(viewvec);
-
- /* first determine if view vector is really close to the direction. If it is, we use
- * vertical movement to determine offset, just like transform system does */
- if (RAD2DEGF(acosf(dot_v3v3(viewvec, arrow->manipulator.matrix_basis[2]))) > 5.0f) {
- /* multiply to projection space */
- mul_m4_v4(rv3d->persmat, orig_origin);
- mul_v4_fl(orig_origin, 1.0f / orig_origin[3]);
- mul_m4_v4(rv3d->persmat, offset);
- mul_v4_fl(offset, 1.0f / offset[3]);
-
- sub_v2_v2v2(dir_2d, offset, orig_origin);
- dir_2d[0] *= ar->winx;
- dir_2d[1] *= ar->winy;
- normalize_v2(dir_2d);
- }
- else {
- dir_2d[0] = 0.0f;
- dir_2d[1] = 1.0f;
- use_vertical = true;
- }
-
- /* find mouse difference */
- m_diff[0] = event->mval[0] - inter->init_mval[0];
- m_diff[1] = event->mval[1] - inter->init_mval[1];
-
- /* project the displacement on the screen space arrow direction */
- project_v2_v2v2(dir2d_final, m_diff, dir_2d);
+ float arrow_co[3];
+ float arrow_no[3];
+ copy_v3_v3(arrow_co, inter->init_matrix_basis[3]);
+ normalize_v3_v3(arrow_no, arrow->manipulator.matrix_basis[2]);
+
+ int ok = 0;
+
+ for (int j = 0; j < 2; j++) {
+ if (ED_view3d_win_to_ray(
+ CTX_data_depsgraph(C),
+ ar, v3d, proj[j].mval,
+ proj[j].ray_origin, proj[j].ray_direction, false))
+ {
+ /* Force Y axis if we're view aligned */
+ if (j == 0) {
+ if (RAD2DEGF(acosf(dot_v3v3(proj[j].ray_direction, arrow->manipulator.matrix_basis[2]))) < 5.0f) {
+ normalize_v3_v3(arrow_no, rv3d->viewinv[1]);
+ }
+ }
- float zfac = ED_view3d_calc_zfac(rv3d, orig_origin, NULL);
- ED_view3d_win_to_delta(ar, dir2d_final, offset, zfac);
+ float arrow_no_proj[3];
+ project_plane_v3_v3v3(arrow_no_proj, arrow_no, proj[j].ray_direction);
- add_v3_v3v3(orig_origin, offset, inter->init_matrix_basis[3]);
+ normalize_v3(arrow_no_proj);
- /* calculate view vector for the new position */
- if (rv3d->is_persp) {
- sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]);
- }
- else {
- copy_v3_v3(viewvec, rv3d->viewinv[2]);
- }
+ float plane[4];
+ plane_from_point_normal_v3(plane, proj[j].ray_origin, arrow_no_proj);
- normalize_v3(viewvec);
- if (!use_vertical) {
- /* now find a plane parallel to the view vector so we can intersect with the arrow direction */
- cross_v3_v3v3(tangent, viewvec, offset);
- cross_v3_v3v3(plane, tangent, viewvec);
-
- const float plane_offset = dot_v3v3(plane, offset);
- const float plane_dir = dot_v3v3(plane, arrow->manipulator.matrix_basis[2]);
- const float fac = (plane_dir != 0.0f) ? (plane_offset / plane_dir) : 0.0f;
- facdir = (fac < 0.0f) ? -1.0f : 1.0f;
- if (isfinite(fac)) {
- mul_v3_v3fl(offset, arrow->manipulator.matrix_basis[2], fac);
+ float lambda;
+ if (isect_ray_plane_v3(arrow_co, arrow_no, plane, &lambda, false)) {
+ madd_v3_v3v3fl(proj[j].location, arrow_co, arrow_no, lambda);
+ ok++;
+ }
}
}
- else {
- facdir = (m_diff[1] < 0.0f) ? -1.0f : 1.0f;
+
+ if (ok != 2) {
+ return OPERATOR_RUNNING_MODAL;
}
+ sub_v3_v3v3(offset, proj[1].location, proj[0].location);
+ facdir = dot_v3v3(arrow_no, offset) < 0.0f ? -1 : 1;
ManipulatorCommonData *data = &arrow->data;
const float ofs_new = facdir * len_v3(offset);
diff --git a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c
new file mode 100644
index 00000000000..7e57b48c77c
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c
@@ -0,0 +1,262 @@
+/*
+ * ***** 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 button2d_manipulator.c
+ * \ingroup wm
+ *
+ * \name Button Manipulator
+ *
+ * 2D Manipulator, also works in 3D views.
+ *
+ * \brief Single click button action for use in manipulator groups.
+ *
+ * \note Currently only basic icon & vector-shape buttons are supported.
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+#include "GPU_batch.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_manipulator_library.h"
+
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
+
+/* own includes */
+#include "../manipulator_geometry.h"
+#include "../manipulator_library_intern.h"
+
+typedef struct ButtonManipulator2D {
+ wmManipulator manipulator;
+ bool is_init;
+ /* Use an icon or shape */
+ int icon;
+ Gwn_Batch *shape_batch[2];
+} ButtonManipulator2D;
+
+#define CIRCLE_RESOLUTION 32
+
+/* -------------------------------------------------------------------- */
+
+static void button2d_geom_draw_backdrop(
+ const wmManipulator *mpr, const float color[4], const bool select)
+{
+ glLineWidth(mpr->line_width);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+
+ /* TODO, other draw styles */
+ imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
+
+ immUnbindProgram();
+
+ UNUSED_VARS(select);
+}
+
+static void button2d_draw_intern(
+ const bContext *UNUSED(C), wmManipulator *mpr,
+ const bool select, const bool highlight)
+{
+ ButtonManipulator2D *button = (ButtonManipulator2D *)mpr;
+
+ if (button->is_init == false) {
+ button->is_init = true;
+ PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "icon");
+ if (RNA_property_is_set(mpr->ptr, prop)) {
+ button->icon = RNA_property_enum_get(mpr->ptr, prop);
+ }
+ else {
+ prop = RNA_struct_find_property(mpr->ptr, "shape");
+ const uint polys_len = RNA_property_string_length(mpr->ptr, prop);
+ /* We shouldn't need the +1, but a NULL char is set. */
+ char *polys = MEM_mallocN(polys_len + 1, __func__);
+ RNA_property_string_get(mpr->ptr, prop, polys);
+ button->shape_batch[0] = GPU_batch_wire_from_poly_2d_encoded((uchar *)polys, polys_len, NULL);
+ button->shape_batch[1] = GPU_batch_tris_from_poly_2d_encoded((uchar *)polys, polys_len, NULL);
+ MEM_freeN(polys);
+ }
+ }
+
+ float color[4];
+ float matrix_final[4][4];
+
+ manipulator_color_get(mpr, highlight, color);
+ WM_manipulator_calc_matrix_final(mpr, matrix_final);
+
+ gpuPushMatrix();
+ gpuMultMatrix(matrix_final);
+
+ glEnable(GL_BLEND);
+
+ if (select == false) {
+ if (button->shape_batch[0] != NULL) {
+ glEnable(GL_LINE_SMOOTH);
+ glLineWidth(1.0f);
+ for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) {
+ /* Invert line color for wire. */
+ color[0] = 1.0f - color[0];
+ color[1] = 1.0f - color[1];
+ color[2] = 1.0f - color[2];
+
+ GWN_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR);
+ GWN_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color));
+ GWN_batch_draw(button->shape_batch[i]);
+ }
+ glDisable(GL_LINE_SMOOTH);
+ gpuPopMatrix();
+ }
+ else if (button->icon != ICON_NONE) {
+ button2d_geom_draw_backdrop(mpr, color, select);
+ gpuPopMatrix();
+ UI_icon_draw(
+ mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * U.ui_scale,
+ mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * U.ui_scale,
+ button->icon);
+ }
+ else {
+ gpuPopMatrix();
+ }
+ }
+ glDisable(GL_BLEND);
+}
+
+static void manipulator_button2d_draw_select(const bContext *C, wmManipulator *mpr, int select_id)
+{
+ GPU_select_load_id(select_id);
+ button2d_draw_intern(C, mpr, true, false);
+}
+
+static void manipulator_button2d_draw(const bContext *C, wmManipulator *mpr)
+{
+ const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
+
+ glEnable(GL_BLEND);
+ button2d_draw_intern(C, mpr, false, is_highlight);
+ glDisable(GL_BLEND);
+}
+
+static int manipulator_button2d_test_select(
+ bContext *C, wmManipulator *mpr, const wmEvent *event)
+{
+ float point_local[2];
+
+ if (0) {
+ /* correct, but unnecessarily slow. */
+ if (manipulator_window_project_2d(
+ C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false)
+ {
+ return -1;
+ }
+ }
+ else {
+ copy_v2_v2(point_local, (float [2]){UNPACK2(event->mval)});
+ sub_v2_v2(point_local, mpr->matrix_basis[3]);
+ mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale));
+ }
+ /* The 'mpr->scale_final' is already applied when projecting. */
+ if (len_squared_v2(point_local) < 1.0f) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static int manipulator_button2d_cursor_get(wmManipulator *mpr)
+{
+ if (RNA_boolean_get(mpr->ptr, "show_drag")) {
+ return BC_NSEW_SCROLLCURSOR;
+ }
+ return CURSOR_STD;
+}
+
+static void manipulator_button2d_free(wmManipulator *mpr)
+{
+ ButtonManipulator2D *shape = (ButtonManipulator2D *)mpr;
+
+ for (uint i = 0; i < ARRAY_SIZE(shape->shape_batch); i++) {
+ GWN_BATCH_DISCARD_SAFE(shape->shape_batch[i]);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Button Manipulator API
+ *
+ * \{ */
+
+static void MANIPULATOR_WT_button_2d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_button_2d";
+
+ /* api callbacks */
+ wt->draw = manipulator_button2d_draw;
+ wt->draw_select = manipulator_button2d_draw_select;
+ wt->test_select = manipulator_button2d_test_select;
+ wt->cursor_get = manipulator_button2d_cursor_get;
+ wt->free = manipulator_button2d_free;
+
+ wt->struct_size = sizeof(ButtonManipulator2D);
+
+ /* rna */
+ PropertyRNA *prop;
+ prop = RNA_def_property(wt->srna, "icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
+
+ /* Passed to 'GPU_batch_from_poly_2d_encoded' */
+ RNA_def_property(wt->srna, "shape", PROP_STRING, PROP_BYTESTRING);
+
+ /* Currently only used for cursor display. */
+ RNA_def_boolean(wt->srna, "show_drag", true, "Show Drag", "");
+}
+
+void ED_manipulatortypes_button_2d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_button_2d);
+}
+
+/** \} */ // Button Manipulator API
diff --git a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c
index f2f5851ff0c..2991c972f6e 100644
--- a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c
+++ b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c
@@ -191,6 +191,7 @@ static void dial_ghostarc_draw(
}
static void dial_ghostarc_get_angles(
+ const struct Depsgraph *depsgraph,
const wmManipulator *mpr,
const wmEvent *event,
const ARegion *ar, const View3D *v3d,
@@ -218,7 +219,7 @@ static void dial_ghostarc_get_angles(
plane_from_point_normal_v3(dial_plane, mpr->matrix_basis[3], axis_vec);
- if (!ED_view3d_win_to_ray(ar, v3d, inter->init_mval, ray_co, ray_no, false) ||
+ if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, inter->init_mval, ray_co, ray_no, false) ||
!isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false))
{
goto fail;
@@ -226,7 +227,7 @@ static void dial_ghostarc_get_angles(
madd_v3_v3v3fl(proj_mval_init_rel, ray_co, ray_no, ray_lambda);
sub_v3_v3(proj_mval_init_rel, mpr->matrix_basis[3]);
- if (!ED_view3d_win_to_ray(ar, v3d, mval, ray_co, ray_no, false) ||
+ if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, mval, ray_co, ray_no, false) ||
!isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false))
{
goto fail;
@@ -396,6 +397,7 @@ static int manipulator_dial_modal(
dial_calc_matrix(mpr, matrix);
dial_ghostarc_get_angles(
+ CTX_data_depsgraph(C),
mpr, event, CTX_wm_region(C), CTX_wm_view3d(C), matrix, co_outer, &angle_ofs, &angle_delta);
DialInteraction *inter = mpr->interaction_data;
diff --git a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c
index 151e173e5e6..4e62c9c396e 100644
--- a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c
+++ b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c
@@ -302,7 +302,8 @@ static int manipulator_grab_test_select(
return -1;
}
- if (len_squared_v2(point_local) < SQUARE(mpr->scale_final)) {
+ /* The 'mpr->scale_final' is already applied when projecting. */
+ if (len_squared_v2(point_local) < 1.0f) {
return 0;
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 77772cfc8cc..a21fc2fffde 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -60,30 +60,35 @@
/* ********* add primitive operators ************* */
+typedef struct MakePrimitiveData {
+ float mat[4][4];
+ bool was_editmode;
+} MakePrimitiveData;
+
static Object *make_prim_init(bContext *C, const char *idname,
- float *dia, float mat[4][4],
- bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer)
+ const float loc[3], const float rot[3], const unsigned int layer,
+ MakePrimitiveData *r_creation_data)
{
Object *obedit = CTX_data_edit_object(C);
- *was_editmode = false;
+ r_creation_data->was_editmode = false;
if (obedit == NULL || obedit->type != OB_MESH) {
obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer);
/* create editmode */
ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
- *was_editmode = true;
+ r_creation_data->was_editmode = true;
}
- *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
return obedit;
}
-static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int enter_editmode)
+static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const bool exit_editmode = ((was_editmode == true) && (enter_editmode == false));
+ const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false));
/* Primitive has all verts selected, use vert select flush
* to push this up to edges & faces. */
@@ -101,17 +106,17 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int
static int add_primitive_plane_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -121,12 +126,12 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
"create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
- 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
+ 1, 1, RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -152,17 +157,17 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot)
static int add_primitive_cube_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -172,13 +177,13 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
"create_cube matrix=%m4 size=%f calc_uvs=%b",
- mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs))
+ creation_data.mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs))
{
return OPERATOR_CANCELLED;
}
/* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -210,13 +215,13 @@ static const EnumPropertyItem fill_type_items[] = {
static int add_primitive_circle_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
int cap_end, cap_tri;
unsigned int layer;
- bool was_editmode;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
cap_end = RNA_enum_get(op->ptr, "fill_type");
@@ -224,7 +229,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -235,12 +240,12 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
- cap_end, cap_tri, mat, calc_uvs))
+ cap_end, cap_tri, creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -270,12 +275,12 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
unsigned int layer;
- bool was_editmode;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
@@ -283,7 +288,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -297,12 +302,12 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
RNA_float_get(op->ptr, "radius"),
RNA_float_get(op->ptr, "radius"),
cap_end, cap_tri,
- RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -333,12 +338,12 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
static int add_primitive_cone_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
unsigned int layer;
- bool was_editmode;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
@@ -346,7 +351,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -357,12 +362,13 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
- RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"),
+ creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -394,17 +400,17 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
static int add_primitive_grid_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -416,12 +422,12 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
"create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "x_subdivisions"),
RNA_int_get(op->ptr, "y_subdivisions"),
- RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -453,22 +459,21 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float mat[4][4];
float loc[3], rot[3];
float dia;
bool enter_editmode;
unsigned int layer;
- bool was_editmode;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, layer, &creation_data);
dia = RNA_float_get(op->ptr, "radius");
- mul_mat3_m4_fl(mat, dia);
+ mul_mat3_m4_fl(creation_data.mat, dia);
em = BKE_editmesh_from_object(obedit);
@@ -478,12 +483,12 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs))
+ "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -510,17 +515,17 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -531,12 +536,12 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"),
- RNA_float_get(op->ptr, "size"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -566,17 +571,17 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, layer, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -587,12 +592,12 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "subdivisions"),
- RNA_float_get(op->ptr, "size"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index afe52ec69f4..6fd4203e085 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -373,10 +373,12 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case PADENTER:
case RETKEY:
- edbm_inset_calc(op);
- edbm_inset_exit(C, op);
- return OPERATOR_FINISHED;
-
+ if (event->val == KM_PRESS) {
+ edbm_inset_calc(op);
+ edbm_inset_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
case LEFTSHIFTKEY:
case RIGHTSHIFTKEY:
if (event->val == KM_PRESS) {
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index c0501078424..5d5e54edf56 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1562,8 +1562,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
/* unproject screen line */
- ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true);
- ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s2, v2, v4, true);
+ ED_view3d_win_to_segment(kcd->eval_ctx.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true);
+ ED_view3d_win_to_segment(kcd->eval_ctx.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true);
mul_m4_v3(kcd->ob->imat, v1);
mul_m4_v3(kcd->ob->imat, v2);
@@ -2519,7 +2519,8 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]);
normalize_v3(kcd->proj_zaxis);
- kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
+ kcd->is_ortho = ED_view3d_clip_range_get(kcd->eval_ctx.depsgraph,
+ kcd->vc.v3d, kcd->vc.rv3d,
&kcd->clipsta, &kcd->clipend, true);
}
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 3ab56f2ebcb..793e5609d31 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -762,7 +762,15 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
handled = true;
break;
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
- if (!has_numinput) {
+
+ /* This is normally disabled for all modal operators.
+ * This is an exception since mouse movement doesn't relate to numeric input.
+ *
+ * If numeric input changes we'll need to add this back see: D2973 */
+#if 0
+ if (!has_numinput)
+#endif
+ {
lcd->vc.mval[0] = event->mval[0];
lcd->vc.mval[1] = event->mval[1];
loopcut_mouse_move(&eval_ctx, lcd, (int)lcd->cuts);
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index f398f087da9..dff501ece13 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -416,6 +416,7 @@ static BMElem *edbm_hover_preselect(
BMElem *ele_best = NULL;
if (ED_view3d_win_to_ray(
+ CTX_data_depsgraph(C),
vc.ar, vc.v3d, mval_fl,
ray_origin, ray_direction, true))
{
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 1a2f9fdb62b..0c8bd560bb2 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -590,7 +590,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- if (e_best && (is_manifold_region == false)) {
+ if (e_best && e_best->l && (is_manifold_region == false)) {
/* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
BMVert *v_new;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 27fe93b049a..a52f12ec055 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -398,7 +398,7 @@ void EDBM_mesh_load(Object *ob)
* of freed data on scene update, especially in cases when there are dependency
* cycles.
*/
- /*
+#if 0
for (Object *other_object = G.main->object.first;
other_object != NULL;
other_object = other_object->id.next)
@@ -407,7 +407,7 @@ void EDBM_mesh_load(Object *ob)
BKE_object_free_derived_caches(other_object);
}
}
- */
+#endif
}
/**
@@ -1392,7 +1392,9 @@ static void scale_point(float c1[3], const float p[3], const float s)
add_v3_v3(c1, p);
}
-bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit)
+bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e,
+ const struct Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d, Object *obedit)
{
BMFace *f;
float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3];
@@ -1402,7 +1404,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v
const float mval_f[2] = {ar->winx / 2.0f,
ar->winy / 2.0f};
- ED_view3d_win_to_segment(ar, v3d, mval_f, origin, end, false);
+ ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false);
invert_m4_m4(invmat, obedit->obmat);
mul_m4_v3(invmat, origin);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index d7e59a05772..bd2ad21d51c 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -75,7 +75,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs,
DerivedMesh *dm;
Scene *scene = CTX_data_scene(C);
EvaluationContext eval_ctx;
- LinkNode *dms = NULL;
+ LinkNodePair dms_pair = {NULL, NULL};
int nverts, ntris, *tris;
float *verts;
@@ -90,7 +90,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs,
ob = (Object *) oblink->link;
dm = mesh_create_derived_no_virtual(&eval_ctx, scene, ob, NULL, CD_MASK_MESH);
DM_ensure_tessface(dm);
- BLI_linklist_prepend(&dms, dm);
+ BLI_linklist_append(&dms_pair, dm);
nverts += dm->getNumVerts(dm);
nfaces = dm->getNumTessFaces(dm);
@@ -106,6 +106,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs,
*r_lay |= ob->lay;
}
+ LinkNode *dms = dms_pair.list;
/* create data */
verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts");
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index e8807432328..5c96c13ebed 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -92,7 +92,6 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_speaker.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -1101,6 +1100,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
/* works without this except if you try render right after, see: 22027 */
DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&group->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -2086,7 +2086,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer
#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
- Base *basen = NULL;
+ Base *base, *basen = NULL;
Material ***matarar;
Object *obn;
ID *id;
@@ -2099,7 +2099,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer
obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- BKE_collection_object_add_from(scene, ob, obn);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ if ((base != NULL) && (base->flag & BASE_VISIBLED)) {
+ BKE_collection_object_add_from(scene, ob, obn);
+ }
+ else {
+ LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer);
+ BKE_collection_object_add(&scene->id, layer_collection->scene_collection, obn);
+ }
basen = BKE_view_layer_base_find(view_layer, obn);
/* 1) duplis should end up in same group as the original
@@ -2449,13 +2456,13 @@ static int add_named_exec(bContext *C, wmOperator *op)
clear_sca_new_poins(); /* BGE logic */
basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag);
- BKE_scene_object_base_flag_sync_from_object(basen);
if (basen == NULL) {
BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
return OPERATOR_CANCELLED;
}
+ BKE_scene_object_base_flag_sync_from_object(basen);
basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
if (event) {
@@ -2473,9 +2480,11 @@ static int add_named_exec(bContext *C, wmOperator *op)
BKE_main_id_clear_newpoins(bmain);
+ /* TODO(sergey): Only update relations for the current scene. */
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index c38a7d58904..03aacc86ea7 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -68,7 +68,7 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot);
void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot);
void OBJECT_OT_make_local(struct wmOperatorType *ot);
-void OBJECT_OT_make_override(struct wmOperatorType *ot);
+void OBJECT_OT_make_override_static(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index ceea3b9c0ac..9c321f5cb79 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -84,7 +84,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_slow_parent_set);
WM_operatortype_append(OBJECT_OT_slow_parent_clear);
WM_operatortype_append(OBJECT_OT_make_local);
- WM_operatortype_append(OBJECT_OT_make_override);
+ WM_operatortype_append(OBJECT_OT_make_override_static);
WM_operatortype_append(OBJECT_OT_make_single_user);
WM_operatortype_append(OBJECT_OT_make_links_scene);
WM_operatortype_append(OBJECT_OT_make_links_data);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 436364ec6c3..d73e3aabaf0 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1678,9 +1678,6 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen
}
}
- /* we reset filter objects because they should be regenerated after this */
- BLI_freelistN(&sc->filter_objects);
-
for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups);
}
@@ -1740,9 +1737,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
libblock_relink_scene_collection(msc);
set_sca_new_poins();
-
- /* TODO redo filter */
- TODO_LAYER_SYNC_FILTER
}
/* not an especially efficient function, only added so the single user
@@ -2335,42 +2329,194 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
}
-static int make_override_exec(bContext *C, wmOperator *UNUSED(op))
+
+static void make_override_static_tag_object(Object *obact, Object *ob)
+{
+ if (ob == obact) {
+ return;
+ }
+
+ if (!ID_IS_LINKED(ob)) {
+ return;
+ }
+
+ /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full 'automatic', generic
+ * handling of all this, will probably require adding some override-aware stuff to library_query code... */
+
+ if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) {
+ for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) {
+ if (md->type == eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (amd->object == obact) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ break;
+ }
+ }
+ }
+ }
+ else if (ob->parent == obact) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ }
+
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name);
+ }
+}
+
+/* Set the object to override. */
+static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = ED_object_active_context(C);
+
+ /* Sanity checks. */
+ if (!scene || ID_IS_LINKED(scene) || !obact) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get object to work on - use a menu if we need to... */
+ if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) {
+ /* Gives menu with list of objects in group. */
+ WM_enum_search_invoke(C, op, event);
+ return OPERATOR_CANCELLED;
+ }
+ else if (ID_IS_LINKED(obact)) {
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ /* Create operator menu item with relevant properties filled in. */
+ PointerRNA opptr_dummy;
+ uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL,
+ WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy);
+
+ /* Present the menu and be done... */
+ UI_popup_menu_end(C, pup);
+
+ /* This invoke just calls another instance of this operator... */
+ return OPERATOR_INTERFACE;
+ }
+ else {
+ /* Error.. cannot continue. */
+ BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or group");
+ return OPERATOR_CANCELLED;
+ }
+
+}
+
+static int make_override_static_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Object *locobj, *refobj = CTX_data_active_object(C);
+ Object *obact = CTX_data_active_object(C);
+
+ bool success = false;
+
+ if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) {
+#if 0 /* Not working yet! */
+ Base *base = BLI_findlink(&obact->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object"));
+ Object *obgroup = obact;
+ obact = base->object;
+
+ /* First, we make a static override of the linked group itself. */
+ obgroup->dup_group->id.tag |= LIB_TAG_DOIT;
+
+ /* Then, we tag our 'main' object and its detected dependencies to be also overridden. */
+ obact->id.tag |= LIB_TAG_DOIT;
+
+ FOREACH_GROUP_OBJECT(obgroup->dup_group, ob)
+ {
+ make_override_tag_object(obact, ob);
+ }
+ FOREACH_GROUP_OBJECT_END;
+
+ success = BKE_override_static_create_from_tag(bmain);
+
+ /* Intantiate our 'main' newly overridden object in scene, if not yet done. */
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *new_obact = (Object *)obact->id.newid;
+ if (new_obact != NULL && (base = BKE_view_layer_base_find(view_layer, new_obact)) == NULL) {
+ BKE_collection_object_add_from(scene, obact, new_obact);
+ base = BKE_view_layer_base_find(view_layer, new_obact);
+ BKE_view_layer_base_select(view_layer, base);
+ }
+
+ /* Parent the group instantiating object to the new overridden one, or vice-versa, if possible. */
+ if (obgroup->parent == NULL) {
+ obgroup->parent = new_obact;
+ }
+ else if (new_obact->parent == NULL) {
+ new_obact->parent = obgroup;
+ }
+
+ /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */
+
+ /* Cleanup. */
+ BKE_main_id_clear_newpoins(bmain);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false);
+#else
+ UNUSED_VARS(op);
+#endif
+ }
+ /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
+ else if (obact->type == OB_ARMATURE) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- locobj = (Object *)BKE_override_static_create_from(bmain, &refobj->id);
- UNUSED_VARS(locobj);
+ obact->id.tag |= LIB_TAG_DOIT;
+
+ for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
+ make_override_static_tag_object(obact, ob);
+ }
+
+ success = BKE_override_static_create_from_tag(bmain);
+
+ /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */
+
+ /* Cleanup. */
+ BKE_main_id_clear_newpoins(bmain);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false);
+ }
+ /* TODO: probably more cases where we want ot do automated smart things in the future! */
+ else {
+ success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL);
+ }
WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static int make_override_poll(bContext *C)
+static int make_override_static_poll(bContext *C)
{
Object *obact = CTX_data_active_object(C);
/* Object must be directly linked to be overridable. */
- return (ED_operator_objectmode(C) && obact && obact->id.lib != NULL && obact->id.tag & LIB_TAG_EXTERN);
+ return (ED_operator_objectmode(C) && obact != NULL &&
+ ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) ||
+ (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group))));
}
-void OBJECT_OT_make_override(wmOperatorType *ot)
+void OBJECT_OT_make_override_static(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Make Override";
+ ot->name = "Make Static Override";
ot->description = "Make local override of this library linked data-block";
- ot->idname = "OBJECT_OT_make_override";
+ ot->idname = "OBJECT_OT_make_override_static";
/* api callbacks */
- ot->exec = make_override_exec;
- ot->poll = make_override_poll;
+ ot->invoke = make_override_static_invoke;
+ ot->exec = make_override_static_exec;
+ ot->poll = make_override_static_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object",
+ "Name of lib-linked/grouped object to make a proxy for");
+ RNA_def_enum_funcs(prop, proxy_group_object_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
}
enum {
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 552380cebdb..b20fe9a004c 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -625,9 +625,9 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob)
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
hmd = (HookModifierData *) md;
- if (hmd->object && !(hmd->object->flag & SELECT)) {
+ if (hmd->object) {
base = BKE_view_layer_base_find(view_layer, hmd->object);
- if (base && (BASE_SELECTABLE(base))) {
+ if (base && ((base->flag & BASE_SELECTED) == 0) && (BASE_SELECTABLE(base))) {
ED_object_base_select(base, BA_SELECT);
changed = true;
}
@@ -1107,12 +1107,12 @@ static bool object_select_more_less(bContext *C, const bool select)
bool changed = false;
const short select_mode = select ? BA_SELECT : BA_DESELECT;
- const short select_flag = select ? SELECT : 0;
+ const short select_flag = select ? BASE_SELECTED : 0;
for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) {
Base *base = ctx_base->ptr.data;
Object *ob = base->object;
- if ((ob->id.tag & LIB_TAG_DOIT) && ((ob->flag & SELECT) != select_flag)) {
+ if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) {
ED_object_base_select(base, select_mode);
changed = true;
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 53bc289d378..89dd46681cb 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -3517,6 +3517,7 @@ static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, De
static int brush_add(const bContext *C, PEData *data, short number)
{
EvaluationContext eval_ctx;
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene= data->scene;
Object *ob= data->ob;
DerivedMesh *dm;
@@ -3580,7 +3581,7 @@ static int brush_add(const bContext *C, PEData *data, short number)
mco[0] = data->mval[0] + dmx;
mco[1] = data->mval[1] + dmy;
- ED_view3d_win_to_segment(data->vc.ar, data->vc.v3d, mco, co1, co2, true);
+ ED_view3d_win_to_segment(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true);
mul_m4_v3(imat, co1);
mul_m4_v3(imat, co2);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 4fee14dc71d..1536c15525f 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -200,7 +200,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
if (psys->part)
part= BKE_particlesettings_copy(bmain, psys->part);
else
- part= psys_new_settings("ParticleSettings", bmain);
+ part= BKE_particlesettings_add(bmain, "ParticleSettings");
ob= ptr.id.data;
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 4e75ca3e6f1..3be890f2c36 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -295,6 +295,7 @@ static void screen_render_view_layer_set(wmOperator *op, Main *mainp, Scene **sc
static int screen_render_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id);
ViewLayer *view_layer = NULL;
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Render *re;
@@ -306,6 +307,11 @@ static int screen_render_exec(bContext *C, wmOperator *op)
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ /* Cannot do render if there is not this function. */
+ if (re_type->render_to_image == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
/* custom scene and single layer re-render */
screen_render_view_layer_set(op, mainp, &scene, &view_layer);
@@ -844,6 +850,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
Main *mainp;
ViewLayer *view_layer = NULL;
Scene *scene = CTX_data_scene(C);
+ RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id);
Render *re;
wmJob *wm_job;
RenderJob *rj;
@@ -856,6 +863,18 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
const char *name;
ScrArea *sa;
+
+ /* Cannot do render if there is not this function. */
+ if (re_type->render_to_image == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* XXX FIXME If engine is an OpenGL engine do not run modal.
+ * This is a problem for animation rendering since you cannot abort them.
+ * This also does not open an image editor space. */
+ if (RE_engine_is_opengl(re_type)) {
+ return screen_render_exec(C, op);
+ }
/* only one render job at a time */
if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER))
@@ -1067,6 +1086,7 @@ typedef struct RenderPreview {
wmJob *job;
Scene *scene;
+ Depsgraph *depsgraph;
ScrArea *sa;
ARegion *ar;
View3D *v3d;
@@ -1081,7 +1101,8 @@ typedef struct RenderPreview {
bool has_freestyle;
} RenderPreview;
-static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect)
+static int render_view3d_disprect(Scene *scene, const Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect)
{
/* copied code from view3d_draw.c */
rctf viewborder;
@@ -1094,7 +1115,7 @@ static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, Region
if (draw_border) {
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
disprect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
disprect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
@@ -1116,13 +1137,15 @@ static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, Region
}
/* returns true if OK */
-static bool render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine,
- float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho)
+static bool render_view3d_get_rects(
+ const Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine,
+ float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho)
{
if (ar->winx < 4 || ar->winy < 4) return false;
- *r_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize);
+ *r_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize);
engine->resolution_x = ar->winx;
engine->resolution_y = ar->winy;
@@ -1229,7 +1252,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
G.is_break = false;
- if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth))
+ if (false == render_view3d_get_rects(rp->depsgraph, rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth))
return;
rp->stop = stop;
@@ -1262,8 +1285,9 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
}
}
- use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d,
- rp->rv3d, &cliprct);
+ use_border = render_view3d_disprect(rp->scene, rp->depsgraph,
+ rp->ar, rp->v3d, rp->rv3d,
+ &cliprct);
if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) {
RenderData rdata;
@@ -1386,6 +1410,7 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C)
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Render *re;
rctf viewplane;
rcti disprect;
@@ -1435,14 +1460,14 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C)
job_update_flag |= PR_UPDATE_VIEW;
}
- render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth);
+ render_view3d_get_rects(depsgraph, ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth);
if (BLI_rctf_compare(&viewplane, &engine->last_viewplane, 0.00001f) == 0) {
engine->last_viewplane = viewplane;
job_update_flag |= PR_UPDATE_VIEW;
}
- render_view3d_disprect(scene, ar, v3d, rv3d, &disprect);
+ render_view3d_disprect(scene, depsgraph, ar, v3d, rv3d, &disprect);
if (BLI_rcti_compare(&disprect, &engine->last_disprect) == 0) {
engine->last_disprect = disprect;
job_update_flag |= PR_UPDATE_RENDERSIZE;
@@ -1462,6 +1487,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
wmJob *wm_job;
RenderPreview *rp;
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ARegion *ar = CTX_wm_region(C);
int width = ar->winx, height = ar->winy;
int divider = BKE_render_preview_pixel_size(&scene->r);
@@ -1486,6 +1512,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
/* customdata for preview thread */
rp->scene = scene;
+ rp->depsgraph = depsgraph;
rp->engine = engine;
rp->sa = CTX_wm_area(C);
rp->ar = CTX_wm_region(C);
@@ -1543,6 +1570,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
RegionView3D *rv3d = CTX_wm_region_view3d(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ARegion *ar = CTX_wm_region(C);
bool force_fallback = false;
bool need_fallback = true;
@@ -1551,7 +1579,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
rcti clip_rect;
int xof, yof;
- if (render_view3d_disprect(scene, ar, v3d, rv3d, &clip_rect)) {
+ if (render_view3d_disprect(scene, depsgraph, ar, v3d, rv3d, &clip_rect)) {
scale_x = (float) BLI_rcti_size_x(&clip_rect) / rres.rectx;
scale_y = (float) BLI_rcti_size_y(&clip_rect) / rres.recty;
xof = clip_rect.xmin;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 3c63aed9473..6e969067985 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -279,7 +279,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
const short view_context = (v3d != NULL);
bool draw_bgpic = true;
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- unsigned char *rect = NULL;
+ float *rectf = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
ImBuf *ibuf_result = NULL;
EvaluationContext eval_ctx;
@@ -360,7 +360,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ibuf_view = ED_view3d_draw_offscreen_imbuf(
&eval_ctx, scene, view_layer, v3d, ar, sizex, sizey,
- IB_rect, draw_flags, alpha_mode, oglrender->ofs_samples, viewname,
+ IB_rectfloat, draw_flags, alpha_mode, oglrender->ofs_samples, viewname,
oglrender->fx, oglrender->ofs, err_out);
/* for stamp only */
@@ -372,7 +372,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
draw_flags |= (V3D_OFSDRAW_USE_GPENCIL | V3D_OFSDRAW_USE_BACKGROUND);
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(
&eval_ctx, scene, view_layer, scene->camera, oglrender->sizex, oglrender->sizey,
- IB_rect, draw_flags, OB_SOLID,
+ IB_rectfloat, draw_flags, OB_SOLID,
alpha_mode, oglrender->ofs_samples, viewname,
oglrender->fx, oglrender->ofs, err_out);
camera = scene->camera;
@@ -380,7 +380,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (ibuf_view) {
ibuf_result = ibuf_view;
- rect = (unsigned char *)ibuf_view->rect;
+ rectf = (float *)ibuf_view->rect_float;
}
else {
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
@@ -389,7 +389,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (ibuf_result != NULL) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
@@ -652,7 +652,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
sizey = (scene->r.size * scene->r.ysch) / 100;
/* corrects render size with actual size, not every card supports non-power-of-two dimensions */
- ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out);
+ ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, err_out);
if (!ofs) {
BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 47794e0e357..2e3091268a9 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -313,11 +313,10 @@ static void set_preview_layer(ViewLayer *view_layer, char pr_type)
for (lc = view_layer->layer_collections.first; lc; lc = lc->next) {
if (STREQ(lc->scene_collection->name, collection_name)) {
- lc->flag = COLLECTION_VISIBLE | COLLECTION_DISABLED;
- BKE_collection_enable(view_layer, lc);
+ lc->flag = COLLECTION_VIEWPORT | COLLECTION_RENDER;
}
else {
- BKE_collection_disable(view_layer, lc);
+ lc->flag = COLLECTION_DISABLED;
}
}
}
@@ -330,7 +329,7 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
if (sp->worldcopy != NULL) {
return sp->worldcopy;
}
- sp->worldcopy = localize_world(world);
+ sp->worldcopy = BKE_world_localize(world);
BLI_addtail(&sp->pr_main->world, sp->worldcopy);
return sp->worldcopy;
}
@@ -396,7 +395,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
if (origmat) {
/* work on a copy */
- mat = localize_material(origmat);
+ mat = BKE_material_localize(origmat);
sp->matcopy = mat;
BLI_addtail(&pr_main->mat, mat);
@@ -551,7 +550,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
/* work on a copy */
if (origla) {
- la = localize_lamp(origla);
+ la = BKE_lamp_localize(origla);
sp->lampcopy = la;
BLI_addtail(&pr_main->lamp, la);
}
@@ -589,7 +588,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
World *wrld = NULL, *origwrld = (World *)id;
if (origwrld) {
- wrld = localize_world(origwrld);
+ wrld = BKE_world_localize(origwrld);
sp->worldcopy = wrld;
BLI_addtail(&pr_main->world, wrld);
}
@@ -722,7 +721,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
if (ok)
*rect = newrect;
- /* start a new preview render job if signalled through sbuts->preview,
+ /* start a new preview render job if signaled through sbuts->preview,
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
if ((sbuts != NULL && sbuts->preview) ||
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 04604feab6a..270ba2a7947 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -427,7 +427,8 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
MEM_freeN(slot_remap);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
return OPERATOR_FINISHED;
}
@@ -582,7 +583,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
wo = BKE_world_copy(bmain, wo);
}
else {
- wo = add_world(bmain, DATA_("World"));
+ wo = BKE_world_add(bmain, DATA_("World"));
if (BKE_scene_use_new_shading_nodes(scene)) {
ED_node_shader_default(C, &wo->id);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index a391b13a000..4943222f038 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -153,6 +153,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
DRW_notify_view_update(
(&(DRWUpdateContext){
.bmain = bmain,
+ .depsgraph = update_ctx->depsgraph,
.scene = scene,
.view_layer = view_layer,
.ar = ar,
@@ -201,7 +202,9 @@ void ED_render_engine_changed(Main *bmain)
update_ctx.bmain = bmain;
for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
update_ctx.scene = scene;
- LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ BLI_LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ /* TDODO(sergey): Iterate over depsgraphs instead? */
+ update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
update_ctx.view_layer = view_layer;
ED_render_id_flush_update(&update_ctx, &scene->id);
}
@@ -309,7 +312,7 @@ static void material_changed(Main *bmain, Material *ma)
BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
/* glsl */
- if (ma->id.tag & LIB_TAG_ID_RECALC) {
+ if (ma->id.recalc & ID_RECALC) {
if (!BLI_listbase_is_empty(&ma->gpumaterial)) {
GPU_material_free(&ma->gpumaterial);
}
@@ -493,7 +496,7 @@ static void world_changed(Main *UNUSED(bmain), World *wo)
wo->update_flag = 1;
/* glsl */
- if (wo->id.tag & LIB_TAG_ID_RECALC) {
+ if (wo->id.recalc & ID_RECALC) {
if (!BLI_listbase_is_empty(&defmaterial.gpumaterial)) {
GPU_material_free(&defmaterial.gpumaterial);
}
@@ -539,8 +542,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id)
return;
}
Main *bmain = update_ctx->bmain;
- Scene *scene = update_ctx->scene;
- ViewLayer *view_layer = update_ctx->view_layer;
/* Internal ID update handlers. */
switch (GS(id->name)) {
case ID_MA:
@@ -567,42 +568,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id)
render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER);
break;
}
- /* Inform all draw managers about changes.
- *
- * TODO(sergey): This code is run for every updated ID, via flushing
- * mechanism. How can we avoid iterating over the whole interface for
- * every of those IDs? One of the ideas would be to call draw manager's
- * ID update which is not bound to any of contexts.
- */
- {
- wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- bScreen *sc = WM_window_get_active_screen(win);
- WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
- ViewRender *view_render = BKE_viewrender_get(win->scene, workspace);
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype != SPACE_VIEW3D) {
- continue;
- }
- for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype != RGN_TYPE_WINDOW) {
- continue;
- }
- RenderEngineType *engine_type = RE_engines_find(view_render->engine_id);
- DRW_notify_id_update(
- (&(DRWUpdateContext){
- .bmain = bmain,
- .scene = scene,
- .view_layer = view_layer,
- .ar = ar,
- .v3d = (View3D *)sa->spacedata.first,
- .engine_type = engine_type
- }),
- id);
- }
- }
- }
- }
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index dbeac782e10..f886a6ad613 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -769,6 +769,10 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
return;
}
+ if (U.app_flag & USER_APP_LOCK_UI_LAYOUT) {
+ return;
+ }
+
/* can't click on bottom corners on OS X, already used for resizing */
#ifdef __APPLE__
if (!(sa->totrct.xmin == 0 && sa->totrct.ymin == 0) || WM_window_is_fullscreen(win))
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 5690076fedb..2e4e9127ed6 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -33,7 +33,6 @@
#include "screen_intern.h"
-
/**
* Draw horizontal shape visualizing future joining (left as well right direction of future joining).
*/
@@ -289,18 +288,15 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos
}
/**
- * Only for edge lines between areas, and the blended join arrows.
+ * Only for edge lines between areas.
*/
-void ED_screen_draw(wmWindow *win)
+void ED_screen_draw_edges(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
ScrArea *sa;
- ScrArea *sa1 = NULL;
- ScrArea *sa2 = NULL;
- ScrArea *sa3 = NULL;
wmSubWindowSet(win, screen->mainwin);
@@ -323,36 +319,47 @@ void ED_screen_draw(wmWindow *win)
for (sa = screen->areabase.first; sa; sa = sa->next) {
drawscredge_area(sa, winsize_x, winsize_y, pos);
-
- /* gather area split/join info */
- if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
- if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
- if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa;
}
+ immUnbindProgram();
+
+ screen->do_draw = false;
+}
+
+/**
+ * The blended join arrows.
+ *
+ * \param sa1: Area from which the resultant originates.
+ * \param sa2: Target area that will be replaced.
+ */
+void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2)
+{
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ glLineWidth(1);
+
/* blended join arrow */
- if (sa1 && sa2) {
- int dir = area_getorientation(sa1, sa2);
- int dira = -1;
- if (dir != -1) {
- switch (dir) {
- case 0: /* W */
- dir = 'r';
- dira = 'l';
- break;
- case 1: /* N */
- dir = 'd';
- dira = 'u';
- break;
- case 2: /* E */
- dir = 'l';
- dira = 'r';
- break;
- case 3: /* S */
- dir = 'u';
- dira = 'd';
- break;
- }
+ int dir = area_getorientation(sa1, sa2);
+ int dira = -1;
+ if (dir != -1) {
+ switch (dir) {
+ case 0: /* W */
+ dir = 'r';
+ dira = 'l';
+ break;
+ case 1: /* N */
+ dir = 'd';
+ dira = 'u';
+ break;
+ case 2: /* E */
+ dir = 'l';
+ dira = 'r';
+ break;
+ case 3: /* S */
+ dir = 'u';
+ dira = 'd';
+ break;
}
glEnable(GL_BLEND);
@@ -363,48 +370,59 @@ void ED_screen_draw(wmWindow *win)
glDisable(GL_BLEND);
}
- /* splitpoint */
- if (sa3) {
- glEnable(GL_BLEND);
- immUniformColor4ub(255, 255, 255, 100);
+ immUnbindProgram();
+}
- immBegin(GWN_PRIM_LINES, 2);
+void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
+{
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) {
- immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y);
- immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y);
+ /* splitpoint */
+ glEnable(GL_BLEND);
+ immUniformColor4ub(255, 255, 255, 100);
- immEnd();
+ immBegin(GWN_PRIM_LINES, 2);
- immUniformColor4ub(0, 0, 0, 100);
+ if (dir == 'h') {
+ const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax;
- immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, sa->totrct.xmin, y);
+ immVertex2f(pos, sa->totrct.xmax, y);
- immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y + 1);
- immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y + 1);
- }
- else {
- immVertex2f(pos, win->eventstate->x, sa3->totrct.ymin);
- immVertex2f(pos, win->eventstate->x, sa3->totrct.ymax);
+ immEnd();
- immEnd();
+ immUniformColor4ub(0, 0, 0, 100);
- immUniformColor4ub(0, 0, 0, 100);
+ immBegin(GWN_PRIM_LINES, 2);
- immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, sa->totrct.xmin, y + 1);
+ immVertex2f(pos, sa->totrct.xmax, y + 1);
- immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymin);
- immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymax);
- }
+ immEnd();
+ }
+ else {
+ BLI_assert(dir == 'v');
+ const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax;
+
+ immVertex2f(pos, x, sa->totrct.ymin);
+ immVertex2f(pos, x, sa->totrct.ymax);
immEnd();
- glDisable(GL_BLEND);
+ immUniformColor4ub(0, 0, 0, 100);
+
+ immBegin(GWN_PRIM_LINES, 2);
+
+ immVertex2f(pos, x + 1, sa->totrct.ymin);
+ immVertex2f(pos, x + 1, sa->totrct.ymax);
+
+ immEnd();
}
- immUnbindProgram();
+ glDisable(GL_BLEND);
- screen->do_draw = false;
+ immUnbindProgram();
}
@@ -481,7 +499,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect)
{
char err_out[256] = "unknown";
- GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, err_out);
+ GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, false, err_out);
GPU_offscreen_bind(offscreen, true);
glClearColor(0.0, 0.0, 0.0, 0.0);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 4b5ce2f4b81..57f45bf95ce 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -426,8 +426,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
/*printf("dir is : %i\n", dir);*/
if (dir == -1) {
- if (sa1) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
- if (sa2) sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
return 0;
}
@@ -458,7 +456,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
screen_delarea(C, scr, sa2);
BKE_screen_remove_double_scrverts(scr);
- sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
/* Update preview thumbnail */
BKE_icon_changed(scr->id.icon_id);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 39c3d72af6a..9214b4b7a68 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -31,6 +31,7 @@
#ifndef __SCREEN_INTERN_H__
#define __SCREEN_INTERN_H__
+struct bContext;
struct bContextDataResult;
struct Main;
@@ -65,7 +66,8 @@ ScrEdge *screen_find_active_scredge(const bScreen *sc,
struct AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2]);
/* screen_context.c */
-int ed_screen_context(const struct bContext *C, const char *member, struct bContextDataResult *result);
+int ed_screen_context(
+ const struct bContext *C, const char *member, struct bContextDataResult *result);
extern const char *screen_context_dir[]; /* doc access */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 4e8bf6ea769..09af0d86f84 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -90,10 +90,12 @@
#define KM_MODAL_CANCEL 1
#define KM_MODAL_APPLY 2
-#define KM_MODAL_STEP10 3
-#define KM_MODAL_STEP10_OFF 4
+#define KM_MODAL_SNAP_ON 3
+#define KM_MODAL_SNAP_OFF 4
-/* ************** Exported Poll tests ********************** */
+/* -------------------------------------------------------------------- */
+/** \name Public Poll API
+ * \{ */
int ED_operator_regionactive(bContext *C)
{
@@ -127,36 +129,6 @@ static int ED_operator_screenactive_norender(bContext *C)
return 1;
}
-
-static int screen_active_editable(bContext *C)
-{
- if (ED_operator_screenactive(C)) {
- /* no full window splitting allowed */
- if (CTX_wm_screen(C)->state != SCREENNORMAL)
- return 0;
- return 1;
- }
- return 0;
-}
-
-static ARegion *screen_find_region_type(bContext *C, int type)
-{
- ARegion *ar = CTX_wm_region(C);
-
- /* find the header region
- * - try context first, but upon failing, search all regions in area...
- */
- if ((ar == NULL) || (ar->regiontype != type)) {
- ScrArea *sa = CTX_wm_area(C);
- ar = BKE_area_find_region_type(sa, type);
- }
- else {
- ar = NULL;
- }
-
- return ar;
-}
-
/* when mouse is over area-edge */
int ED_operator_screen_mainwinactive(bContext *C)
{
@@ -589,7 +561,46 @@ int ED_operator_camera(bContext *C)
return (cam != NULL);
}
-/* *************************** action zone operator ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Screen Utilities
+ * \{ */
+
+static int screen_active_editable(bContext *C)
+{
+ if (ED_operator_screenactive(C)) {
+ /* no full window splitting allowed */
+ if (CTX_wm_screen(C)->state != SCREENNORMAL)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static ARegion *screen_find_region_type(bContext *C, int type)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ /* find the header region
+ * - try context first, but upon failing, search all regions in area...
+ */
+ if ((ar == NULL) || (ar->regiontype != type)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ar = BKE_area_find_region_type(sa, type);
+ }
+ else {
+ ar = NULL;
+ }
+
+ return ar;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Action Zone Operator
+ * \{ */
/* operator state vars used:
* none
@@ -807,8 +818,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* once we drag outside the actionzone, register a gesture
* check we're not on an edge so join finds the other area */
is_gesture = ((is_in_area_actionzone(sad->sa1, &event->x) != sad->az) &&
- (screen_find_active_scredge(sc, screen_size_x, screen_size_y,
- event->x, event->y) == NULL));
+ (screen_find_active_scredge(sc, screen_size_x, screen_size_y, event->x, event->y) == NULL));
}
else {
const int delta_min = 1;
@@ -1098,6 +1108,7 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
typedef struct sAreaMoveData {
int bigger, smaller, origval, step;
char dir;
+ bool do_snap;
} sAreaMoveData;
/* helper call to move area-edge, sets limits
@@ -1189,55 +1200,98 @@ static int area_move_init(bContext *C, wmOperator *op)
return 1;
}
+static int area_snap_calc_location(
+ const bScreen *sc, const int delta,
+ const int origval, const int dir,
+ const int bigger, const int smaller)
+{
+ int final_loc = -1;
+
+ const int m_loc = origval + delta;
+ const int axis = (dir == 'v') ? 0 : 1;
+ int snap_dist;
+ int dist;
+ {
+ /* Test the snap to middle. */
+ int middle = origval + (bigger - smaller) / 2;
+ middle -= (middle % AREAGRID);
+
+ snap_dist = abs(m_loc - middle);
+ final_loc = middle;
+ }
+
+ for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ if (v1->editflag) {
+ const int v_loc = (&v1->vec.x)[!axis];
+
+ for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
+ if (!v2->editflag) {
+ if (v_loc == (&v2->vec.x)[!axis]) {
+ const int v_loc2 = (&v2->vec.x)[axis];
+ /* Do not snap to the vertices at the ends. */
+ if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) {
+ dist = abs(m_loc - v_loc2);
+ if (dist <= snap_dist) {
+ snap_dist = dist;
+ final_loc = v_loc2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return final_loc;
+}
+
/* moves selected screen edge amount of delta, used by split & move */
-static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
+static void area_move_apply_do(
+ const bContext *C, int delta,
+ const int origval, const int dir,
+ const int bigger, const int smaller,
+ const bool do_snap)
{
- wmWindow *win = CTX_wm_window(C);
- const int screen_size_x = WM_window_screen_pixels_x(win);
- const int screen_size_y = WM_window_screen_pixels_y(win);
bScreen *sc = CTX_wm_screen(C);
ScrVert *v1;
- ScrArea *sa;
- int doredraw = 0;
- int oldval;
-
- delta = CLAMPIS(delta, -smaller, bigger);
-
+ bool doredraw = false;
+ CLAMP(delta, -smaller, bigger);
+
+ short final_loc = -1;
+
+ if (do_snap) {
+ final_loc = area_snap_calc_location(sc, delta, origval, dir, bigger, smaller);
+ }
+ else {
+ final_loc = origval + delta;
+ if (delta != bigger && delta != -smaller) {
+ final_loc -= (final_loc % AREAGRID);
+ }
+ }
+
+ BLI_assert(final_loc != -1);
+ short axis = (dir == 'v') ? 0 : 1;
+
for (v1 = sc->vertbase.first; v1; v1 = v1->next) {
if (v1->editflag) {
- /* that way a nice AREAGRID */
- if ((dir == 'v') && v1->vec.x > 0 && v1->vec.x < screen_size_x - 1) {
- oldval = v1->vec.x;
- v1->vec.x = origval + delta;
-
- if (delta != bigger && delta != -smaller) {
- v1->vec.x -= (v1->vec.x % AREAGRID);
- v1->vec.x = CLAMPIS(v1->vec.x, origval - smaller, origval + bigger);
- }
- if (oldval != v1->vec.x)
- doredraw = 1;
- }
- if ((dir == 'h') && v1->vec.y > 0 && v1->vec.y < screen_size_y - 1) {
- oldval = v1->vec.y;
- v1->vec.y = origval + delta;
-
- if (delta != bigger && delta != smaller) {
- v1->vec.y -= (v1->vec.y % AREAGRID);
- v1->vec.y = CLAMPIS(v1->vec.y, origval - smaller, origval + bigger);
- }
- if (oldval != v1->vec.y)
- doredraw = 1;
+ short oldval = (&v1->vec.x)[axis];
+ (&v1->vec.x)[axis] = final_loc;
+
+ if (oldval == final_loc) {
+ /* nothing will change to the other vertices either. */
+ break;
}
+ doredraw = true;
}
}
/* only redraw if we actually moved a screen vert, for AREAGRID */
if (doredraw) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag)
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) {
ED_area_tag_redraw(sa);
+ }
}
-
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
/* Update preview thumbnail */
BKE_icon_changed(sc->id.icon_id);
@@ -1247,10 +1301,9 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int
static void area_move_apply(bContext *C, wmOperator *op)
{
sAreaMoveData *md = op->customdata;
- int delta;
-
- delta = RNA_int_get(op->ptr, "delta");
- area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
+ int delta = RNA_int_get(op->ptr, "delta");
+
+ area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->do_snap);
}
static void area_move_exit(bContext *C, wmOperator *op)
@@ -1312,7 +1365,6 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
y = RNA_int_get(op->ptr, "y");
delta = (md->dir == 'v') ? event->x - x : event->y - y;
- if (md->step) delta = delta - (delta % md->step);
RNA_int_set(op->ptr, "delta", delta);
area_move_apply(C, op);
@@ -1328,12 +1380,12 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
case KM_MODAL_CANCEL:
area_move_cancel(C, op);
return OPERATOR_CANCELLED;
-
- case KM_MODAL_STEP10:
- md->step = 10;
+
+ case KM_MODAL_SNAP_ON:
+ md->do_snap = true;
break;
- case KM_MODAL_STEP10_OFF:
- md->step = 0;
+ case KM_MODAL_SNAP_OFF:
+ md->do_snap = false;
break;
}
break;
@@ -1365,7 +1417,11 @@ static void SCREEN_OT_area_move(wmOperatorType *ot)
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
}
-/* ************** split area operator *********************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Area Operator
+ * \{ */
/*
* operator state vars:
@@ -1402,13 +1458,13 @@ static void SCREEN_OT_area_move(wmOperatorType *ot)
*/
typedef struct sAreaSplitData {
- int x, y; /* last used mouse position */
-
int origval; /* for move areas */
int bigger, smaller; /* constraints for moving new edge */
int delta; /* delta move edge */
int origmin, origsize; /* to calculate fac, for property storage */
int previewmode; /* draw previewline, then split */
+ void *draw_callback; /* call `ED_screen_draw_split_preview` */
+ bool do_snap;
ScrEdge *nedge; /* new edge */
ScrArea *sarea; /* start area */
@@ -1416,6 +1472,19 @@ typedef struct sAreaSplitData {
} sAreaSplitData;
+static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata)
+{
+ const wmOperator *op = userdata;
+
+ sAreaSplitData *sd = op->customdata;
+ if (sd->sarea) {
+ int dir = RNA_enum_get(op->ptr, "direction");
+ float fac = RNA_float_get(op->ptr, "factor");
+
+ ED_screen_draw_split_preview(sd->sarea, dir, fac);
+ }
+}
+
/* generic init, menu case, doesn't need active area */
static int area_split_menu_init(bContext *C, wmOperator *op)
{
@@ -1426,15 +1495,7 @@ static int area_split_menu_init(bContext *C, wmOperator *op)
op->customdata = sd;
sd->sarea = CTX_wm_area(C);
-
- if (sd->sarea) {
- int dir = RNA_enum_get(op->ptr, "direction");
- if (dir == 'h')
- sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
- else
- sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
- }
return 1;
}
@@ -1545,9 +1606,9 @@ static void area_split_exit(bContext *C, wmOperator *op)
if (sd->sarea) ED_area_tag_redraw(sd->sarea);
if (sd->narea) ED_area_tag_redraw(sd->narea);
- if (sd->sarea)
- sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V);
-
+ if (sd->draw_callback)
+ WM_draw_cb_exit(CTX_wm_window(C), sd->draw_callback);
+
MEM_freeN(op->customdata);
op->customdata = NULL;
}
@@ -1560,6 +1621,12 @@ static void area_split_exit(bContext *C, wmOperator *op)
BKE_screen_remove_double_scredges(CTX_wm_screen(C));
}
+static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
+{
+ wmWindow *win = CTX_wm_window(C);
+ int dir = RNA_enum_get(op->ptr, "direction");
+ WM_cursor_set(win, (dir == 'v') ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
+}
/* UI callback, adds new handler */
static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1637,9 +1704,6 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
sd = (sAreaSplitData *)op->customdata;
- sd->x = event->x;
- sd->y = event->y;
-
if (event->type == EVT_ACTIONZONE_AREA) {
/* do the split */
@@ -1654,9 +1718,11 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
sd->previewmode = 1;
+ sd->draw_callback = WM_draw_cb_activate(win, area_split_draw_cb, op);
/* add temp handler for edge move or cancel */
WM_event_add_modal_handler(C, op);
-
+ area_split_preview_update_cursor(C, op);
+
return OPERATOR_RUNNING_MODAL;
}
@@ -1699,48 +1765,15 @@ static void area_split_cancel(bContext *C, wmOperator *op)
static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
- float fac;
- int dir;
-
+ PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
+ bool update_factor = false;
+
/* execute the events */
switch (event->type) {
case MOUSEMOVE:
- dir = RNA_enum_get(op->ptr, "direction");
-
- sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval;
- if (sd->previewmode == 0)
- area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
- else {
- if (sd->sarea) {
- sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V);
- ED_area_tag_redraw(sd->sarea);
- }
- /* 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);
- if (dir == 'v') {
- sd->origsize = sd->sarea->winx;
- sd->origmin = sd->sarea->totrct.xmin;
- sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
- }
- else {
- sd->origsize = sd->sarea->winy;
- sd->origmin = sd->sarea->totrct.ymin;
- sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
- }
- }
-
- CTX_wm_screen(C)->do_draw = true;
-
- }
-
- fac = (dir == 'v') ? event->x - sd->origmin : event->y - sd->origmin;
- RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
-
+ update_factor = true;
break;
-
+
case LEFTMOUSE:
if (sd->previewmode) {
area_split_apply(C, op);
@@ -1758,27 +1791,15 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MIDDLEMOUSE:
case TABKEY:
if (sd->previewmode == 0) {
+ /* pass */
}
else {
- dir = RNA_enum_get(op->ptr, "direction");
-
if (event->val == KM_PRESS) {
if (sd->sarea) {
- sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V);
- ED_area_tag_redraw(sd->sarea);
-
- if (dir == 'v') {
- RNA_enum_set(op->ptr, "direction", 'h');
- sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
-
- WM_cursor_set(CTX_wm_window(C), CURSOR_X_MOVE);
- }
- else {
- RNA_enum_set(op->ptr, "direction", 'v');
- sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
-
- WM_cursor_set(CTX_wm_window(C), CURSOR_Y_MOVE);
- }
+ int dir = RNA_property_enum_get(op->ptr, prop_dir);
+ RNA_property_enum_set(op->ptr, prop_dir, (dir == 'v') ? 'h' : 'v');
+ area_split_preview_update_cursor(C, op);
+ update_factor = true;
}
}
}
@@ -1789,8 +1810,64 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
case ESCKEY:
area_split_cancel(C, op);
return OPERATOR_CANCELLED;
+
+ case LEFTCTRLKEY:
+ sd->do_snap = event->val == KM_PRESS;
+ update_factor = true;
+ break;
}
-
+
+ if (update_factor) {
+ const int dir = RNA_property_enum_get(op->ptr, prop_dir);
+
+ sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval;
+
+ if (sd->previewmode == 0) {
+ if (sd->do_snap) {
+ const int snap_loc = area_snap_calc_location(
+ CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->bigger, sd->smaller);
+ sd->delta = snap_loc - sd->origval;
+ }
+ area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, false);
+ }
+ else {
+ if (sd->sarea) {
+ ED_area_tag_redraw(sd->sarea);
+ }
+ /* 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) {
+ ScrArea *sa = sd->sarea;
+ if (dir == 'v') {
+ sd->origsize = sa->winx;
+ sd->origmin = sa->totrct.xmin;
+ }
+ else {
+ sd->origsize = sa->winy;
+ sd->origmin = sa->totrct.ymin;
+ }
+
+ if (sd->do_snap) {
+ sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1;
+
+ const int snap_loc = area_snap_calc_location(
+ CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin);
+
+ sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0;
+ sd->delta = snap_loc - sd->origval;
+ }
+
+ ED_area_tag_redraw(sd->sarea);
+ }
+
+ CTX_wm_screen(C)->do_draw = true;
+ }
+
+ float fac = (float)(sd->delta + sd->origval - sd->origmin) / sd->origsize;
+ RNA_float_set(op->ptr, "factor", fac);
+ }
+
return OPERATOR_RUNNING_MODAL;
}
@@ -1823,9 +1900,11 @@ static void SCREEN_OT_area_split(wmOperatorType *ot)
RNA_def_int(ot->srna, "mouse_y", -100, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
}
+/** \} */
-
-/* ************** scale region edge operator *********************************** */
+/* -------------------------------------------------------------------- */
+/** \name Scale Region Edge Operator
+ * \{ */
typedef struct RegionMoveData {
AZone *az;
@@ -2094,8 +2173,11 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
}
+/** \} */
-/* ************** frame change operator ***************************** */
+/* -------------------------------------------------------------------- */
+/** \name Frame Change Operator
+ * \{ */
static void areas_do_frame_follow(bContext *C, bool middle)
{
@@ -2176,6 +2258,11 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Frame Jump Operator
+ * \{ */
/* function to be called outside UI context, or for redo */
static int frame_jump_exec(bContext *C, wmOperator *op)
@@ -2230,8 +2317,11 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
}
+/** \} */
-/* ************** jump to keyframe operator ***************************** */
+/* -------------------------------------------------------------------- */
+/** \name Jump to Key-Frame Operator
+ * \{ */
/* function to be called outside UI context, or for redo */
static int keyframe_jump_exec(bContext *C, wmOperator *op)
@@ -2340,7 +2430,11 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
}
-/* ************** jump to marker operator ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Jump to Marker Operator
+ * \{ */
/* function to be called outside UI context, or for redo */
static int marker_jump_exec(bContext *C, wmOperator *op)
@@ -2403,7 +2497,11 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
}
-/* ************** switch screen operator ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Screen Operator
+ * \{ */
/* function to be called outside UI context, or for redo */
static int screen_set_exec(bContext *C, wmOperator *op)
@@ -2431,8 +2529,11 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot)
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
}
-/* ************** screen full-area operator ***************************** */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Screen Full-Area Operator
+ * \{ */
/* function to be called outside UI context, or for redo */
static int screen_maximize_area_exec(bContext *C, wmOperator *op)
@@ -2491,7 +2592,11 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ************** join area operator ********************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Screen Join-Area Operator
+ * \{ */
/* operator state vars used:
* x1, y1 mouse coord in first area, which will disappear
@@ -2521,13 +2626,23 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
*/
typedef struct sAreaJoinData {
- ScrArea *sa1; /* first area to be considered */
- ScrArea *sa2; /* second area to be considered */
- ScrArea *scr; /* designed for removal */
+ ScrArea *sa1; /* first area to be considered */
+ ScrArea *sa2; /* second area to be considered */
+ void *draw_callback; /* call `ED_screen_draw_join_shape` */
} sAreaJoinData;
+static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata)
+{
+ const wmOperator *op = userdata;
+
+ sAreaJoinData *sd = op->customdata;
+ if (sd->sa1 && sd->sa2) {
+ ED_screen_draw_join_shape(sd->sa1, sd->sa2);
+ }
+}
+
/* validate selection inside screen, set variables OK */
/* return 0: init failed */
/* XXX todo: find edge based on (x,y) and set other area? */
@@ -2561,14 +2676,14 @@ static int area_join_init(bContext *C, wmOperator *op)
}
jd = (sAreaJoinData *)MEM_callocN(sizeof(sAreaJoinData), "op_area_join");
-
+
jd->sa1 = sa1;
- jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
jd->sa2 = sa2;
- jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
-
+
op->customdata = jd;
-
+
+ jd->draw_callback = WM_draw_cb_activate(CTX_wm_window(C), area_join_draw_cb, op);
+
return 1;
}
@@ -2592,8 +2707,13 @@ static int area_join_apply(bContext *C, wmOperator *op)
/* finish operation */
static void area_join_exit(bContext *C, wmOperator *op)
{
- if (op->customdata) {
- MEM_freeN(op->customdata);
+ sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
+
+ if (jd) {
+ if (jd->draw_callback)
+ WM_draw_cb_exit(CTX_wm_window(C), jd->draw_callback);
+
+ MEM_freeN(jd);
op->customdata = NULL;
}
@@ -2652,17 +2772,6 @@ static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void area_join_cancel(bContext *C, wmOperator *op)
{
- sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
-
- if (jd->sa1) {
- jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
- jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
- }
- if (jd->sa2) {
- jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
- jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
- }
-
WM_event_add_notifier(C, NC_WINDOW, NULL);
area_join_exit(C, op);
@@ -2686,9 +2795,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (jd->sa1 != sa) {
dir = area_getorientation(jd->sa1, sa);
if (dir != -1) {
- if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
jd->sa2 = sa;
- jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
}
else {
/* we are not bordering on the previously selected area
@@ -2697,15 +2804,10 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
dir = area_getorientation(sa, jd->sa2);
if (dir != -1) {
- if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
- if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
jd->sa1 = jd->sa2;
jd->sa2 = sa;
- if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
- if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
}
else {
- if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
jd->sa2 = NULL;
}
}
@@ -2715,12 +2817,8 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* we are back in the area previously selected for keeping
* we swap the areas if possible to allow user to choose */
if (jd->sa2 != NULL) {
- if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
- if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
jd->sa1 = jd->sa2;
jd->sa2 = sa;
- if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
- if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
dir = area_getorientation(jd->sa1, jd->sa2);
if (dir == -1) {
printf("oops, didn't expect that!\n");
@@ -2729,9 +2827,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
dir = area_getorientation(jd->sa1, sa);
if (dir != -1) {
- if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
jd->sa2 = sa;
- jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
}
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -2785,7 +2881,11 @@ static void SCREEN_OT_area_join(wmOperatorType *ot)
RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
}
-/* ******************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Screen Area Options Operator
+ * \{ */
static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -2838,9 +2938,11 @@ static void SCREEN_OT_area_options(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
}
+/** \} */
-/* ******************************* */
-
+/* -------------------------------------------------------------------- */
+/** \name Space Data Cleanup Operator
+ * \{ */
static int spacedata_cleanup_exec(bContext *C, wmOperator *op)
{
@@ -2879,7 +2981,11 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
}
-/* ************** repeat last operator ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Repeat Last Operator
+ * \{ */
static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2918,6 +3024,12 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot)
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Repeat History Operator
+ * \{ */
+
static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2975,7 +3087,11 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot)
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
}
-/* ********************** redo operator ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Redo Operator
+ * \{ */
static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
@@ -3000,7 +3116,11 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
}
-/* ************** region four-split operator ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Region Quad-View Operator
+ * \{ */
static void view3d_localview_update_rv3d(struct RegionView3D *rv3d)
{
@@ -3153,8 +3273,11 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
-/* ************** region flip operator ***************************** */
+/* -------------------------------------------------------------------- */
+/** \name Region Flip Operator
+ * \{ */
/* flip a region alignment */
static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
@@ -3205,7 +3328,11 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
ot->flag = 0;
}
-/* ************** header operator ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Header Toggle Operator
+ * \{ */
static int header_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3235,8 +3362,11 @@ static void SCREEN_OT_header(wmOperatorType *ot)
ot->exec = header_exec;
}
+/** \} */
-/* ************** show menus operator ***************************** */
+/* -------------------------------------------------------------------- */
+/** \name Header Toggle Menu Operator
+ * \{ */
/* show/hide header text menus */
static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op))
@@ -3265,8 +3395,11 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
-/* ************** header tools operator ***************************** */
+/* -------------------------------------------------------------------- */
+/** \name Header Tools Operator
+ * \{ */
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
@@ -3318,7 +3451,13 @@ static void SCREEN_OT_header_toolbox(wmOperatorType *ot)
ot->invoke = header_toolbox_invoke;
}
-/* ****************** anim player, with timer ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Step Operator
+ *
+ * Animation Step.
+ * \{ */
static int match_area_with_refresh(int spacetype, int refresh)
{
@@ -3615,7 +3754,13 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
}
-/* ****************** anim player, starts or ends timer ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Playback Operator
+ *
+ * Animation Playback with Timer.
+ * \{ */
/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
@@ -3708,6 +3853,12 @@ static void SCREEN_OT_animation_play(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Cancel Operator
+ * \{ */
+
static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
{
bScreen *screen = ED_screen_animation_playing(CTX_wm_manager(C));
@@ -3747,7 +3898,11 @@ static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "restore_frame", true, "Restore Frame", "Restore the frame when animation was initialized");
}
-/* ************** border select operator (template) ***************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Border Select Operator (Template)
+ * \{ */
/* operator state vars used: (added by default WM callbacks)
* xmin, ymin
@@ -3802,6 +3957,12 @@ static void SCREEN_OT_border_select(wmOperatorType *ot)
}
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Full Screen Back Operator
+ * \{ */
+
/* *********************** generic fullscreen 'back' button *************** */
@@ -3836,7 +3997,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
}
-/* *********** show user pref window ****** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Show User Preferences Operator
+ * \{ */
static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -3866,7 +4031,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
}
-/********************* new screen operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name New Screen Operator
+ * \{ */
static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3893,7 +4062,11 @@ static void SCREEN_OT_new(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
}
-/********************* delete screen operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Screen Operator
+ * \{ */
static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3917,7 +4090,11 @@ static void SCREEN_OT_delete(wmOperatorType *ot)
ot->exec = screen_delete_exec;
}
-/* ***************** region alpha blending ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Region Alpha Blending Operator
+ * \{ */
/* implementation note: a disappearing region needs at least 1 last draw with 100% backbuffer
* texture over it- then triple buffer will clear it entirely.
@@ -4059,7 +4236,11 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot)
/* properties */
}
-/* ******************** space context cycling operator ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Space Context Cycle Operator
+ * \{ */
/* SCREEN_OT_space_context_cycle direction */
enum {
@@ -4142,9 +4323,11 @@ static void SCREEN_OT_space_context_cycle(wmOperatorType *ot)
"Direction to cycle through");
}
+/** \} */
-/* **************** Assigning operatortypes to global list, adding handlers **************** */
-
+/* -------------------------------------------------------------------- */
+/** \name Assigning Operator Types
+ * \{ */
/* called in spacetypes.c */
void ED_operatortypes_screen(void)
@@ -4203,13 +4386,19 @@ void ED_operatortypes_screen(void)
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Key Map
+ * \{ */
+
static void keymap_modal_set(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
{KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
- {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
- {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
+ {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap on", ""},
+ {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap off", ""},
{0, NULL, 0, NULL, NULL}};
wmKeyMap *keymap;
@@ -4221,8 +4410,8 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_SNAP_ON);
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_SNAP_OFF);
WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
@@ -4404,3 +4593,4 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
keymap_modal_set(keyconf);
}
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index e1e90506299..3a43c7a6585 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -151,7 +151,10 @@ typedef struct LoadTexData {
float radius;
} LoadTexData;
-static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), const int j, const int thread_id)
+static void load_tex_task_cb_ex(
+ void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict tls)
{
LoadTexData *data = userdata;
Brush *br = data->br;
@@ -212,7 +215,7 @@ static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), c
if (col) {
float rgba[4];
- paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
+ paint_get_tex_pixel_col(mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
buffer[index * 4] = rgba[0] * 255;
buffer[index * 4 + 1] = rgba[1] * 255;
@@ -220,7 +223,7 @@ static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), c
buffer[index * 4 + 3] = rgba[3] * 255;
}
else {
- float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
+ float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
avg += br->texture_sample_bias;
@@ -318,7 +321,9 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
.pool = pool, .size = size, .rotation = rotation, .radius = radius,
};
- BLI_task_parallel_range_ex(0, size, &data, NULL, 0, load_tex_task_cb_ex, true, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings);
if (mtex->tex && mtex->tex->nodetree)
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
@@ -365,7 +370,10 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
return 1;
}
-static void load_tex_cursor_task_cb(void *userdata, const int j)
+static void load_tex_cursor_task_cb(
+ void *__restrict userdata,
+ const int j,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
LoadTexData *data = userdata;
Brush *br = data->br;
@@ -445,7 +453,9 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
.br = br, .buffer = buffer, .size = size,
};
- BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, true);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings);
if (!cursor_snap.overlay_texture)
glGenTextures(1, &cursor_snap.overlay_texture);
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 2d1f0cb3b0d..aebd0c10e9c 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -50,6 +50,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
@@ -58,7 +59,6 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
@@ -666,17 +666,17 @@ void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_cor
float color_gr[4];
switch (br->gradient_stroke_mode) {
case BRUSH_GRADIENT_PRESSURE:
- do_colorband(br->gradient, pressure, color_gr);
+ BKE_colorband_evaluate(br->gradient, pressure, color_gr);
break;
case BRUSH_GRADIENT_SPACING_REPEAT:
{
float coord = fmod(distance / br->gradient_spacing, 1.0);
- do_colorband(br->gradient, coord, color_gr);
+ BKE_colorband_evaluate(br->gradient, coord, color_gr);
break;
}
case BRUSH_GRADIENT_SPACING_CLAMP:
{
- do_colorband(br->gradient, distance / br->gradient_spacing, color_gr);
+ BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr);
break;
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 30830e4e7bc..2ce7c51b6b4 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -44,12 +44,12 @@
#include "BLI_bitmap.h"
#include "BLI_task.h"
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
@@ -1071,7 +1071,10 @@ typedef struct Paint2DForeachData {
int tilew;
} Paint2DForeachData;
-static void paint_2d_op_foreach_do(void *data_v, const int iter)
+static void paint_2d_op_foreach_do(
+ void *__restrict data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
Paint2DForeachData *data = (Paint2DForeachData *)data_v;
paint_2d_do_making_brush(data->s, data->region, data->curveb,
@@ -1157,9 +1160,12 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
data.blend = blend;
data.tilex = tilex;
data.tilew = tilew;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
BLI_task_parallel_range(tiley, tileh + 1, &data,
paint_2d_op_foreach_do,
- true);
+ &settings);
}
}
@@ -1667,7 +1673,7 @@ void paint_2d_gradient_fill(
break;
}
}
- do_colorband(br->gradient, f, color_f);
+ BKE_colorband_evaluate(br->gradient, f, color_f);
/* convert to premultiplied */
mul_v3_fl(color_f, color_f[3]);
color_f[3] *= br->alpha;
@@ -1697,7 +1703,7 @@ void paint_2d_gradient_fill(
}
}
- do_colorband(br->gradient, f, color_f);
+ BKE_colorband_evaluate(br->gradient, f, color_f);
linearrgb_to_srgb_v3_v3(color_f, color_f);
rgba_float_to_uchar((unsigned char *)&color_b, color_f);
((unsigned char *)&color_b)[3] *= br->alpha;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 900ca844dbf..4a14e985827 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -62,6 +62,7 @@
#include "DNA_object_types.h"
#include "BKE_camera.h"
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
#include "BKE_DerivedMesh.h"
@@ -226,6 +227,7 @@ typedef struct ProjPaintState {
View3D *v3d;
RegionView3D *rv3d;
ARegion *ar;
+ const Depsgraph *depsgraph;
Scene *scene;
int source; /* PROJ_SRC_**** */
@@ -3132,7 +3134,7 @@ static void proj_paint_state_viewport_init(
ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
- ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
+ ps->is_ortho = ED_view3d_clip_range_get(ps->depsgraph, ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
}
else {
/* re-projection */
@@ -4582,7 +4584,7 @@ static void *do_projectpaint_thread(void *ph_v)
break;
}
}
- do_colorband(brush->gradient, f, color_f);
+ BKE_colorband_evaluate(brush->gradient, f, color_f);
color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
if (is_floatbuf) {
@@ -5097,6 +5099,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->rv3d = CTX_wm_region_view3d(C);
ps->ar = CTX_wm_region(C);
+ ps->depsgraph = CTX_data_depsgraph(C);
ps->scene = scene;
ps->ob = ob; /* allow override of active object */
@@ -5507,7 +5510,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
array = (float *)IDP_Array(view_data);
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);
+ is_ortho = ED_view3d_clip_range_get(CTX_data_depsgraph(C), v3d, rv3d, &array[0], &array[1], true);
/* 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;
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 0fec4c4fc80..ff261a808da 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -104,7 +104,10 @@ typedef struct MaskTaskData {
float (*clip_planes_final)[4];
} MaskTaskData;
-static void mask_flood_fill_task_cb(void *userdata, const int i)
+static void mask_flood_fill_task_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
MaskTaskData *data = userdata;
@@ -158,9 +161,12 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
.mode = mode, .value = value,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
0, totnode, &data, mask_flood_fill_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ &settings);
if (multires)
multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
@@ -221,7 +227,10 @@ static void flip_plane(float out[4], const float in[4], const char symm)
out[3] = in[3];
}
-static void mask_box_select_task_cb(void *userdata, const int i)
+static void mask_box_select_task_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
MaskTaskData *data = userdata;
@@ -303,9 +312,12 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
.mode = mode, .value = value, .clip_planes_final = clip_planes_final,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
0, totnode, &data, mask_box_select_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ &settings);
if (nodes)
MEM_freeN(nodes);
@@ -377,7 +389,10 @@ static void mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
} while (++index != index_end);
}
-static void mask_gesture_lasso_task_cb(void *userdata, const int i)
+static void mask_gesture_lasso_task_cb(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
LassoMaskData *lasso_data = userdata;
MaskTaskData *data = &lasso_data->task_data;
@@ -484,9 +499,12 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.mode = mode;
data.task_data.value = value;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT));
BLI_task_parallel_range(
0, totnode, &data, mask_gesture_lasso_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT)));
+ &settings);
if (nodes)
MEM_freeN(nodes);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 40210d63566..004d2757a71 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -68,10 +68,13 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
Main *bmain = CTX_data_main(C);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- if (br)
+ if (br) {
br = BKE_brush_copy(bmain, br);
- else
+ }
+ else {
br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode));
+ id_us_min(&br->id); /* fake user only */
+ }
BKE_paint_brush_set(paint, br);
@@ -376,6 +379,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool,
if (!brush && brush_tool(brush_orig, tool_offset) != tool && create_missing) {
brush = BKE_brush_add(bmain, tool_name, ob_mode);
+ id_us_min(&brush->id); /* fake user only */
brush_tool_set(brush, tool_offset, tool);
brush->toggle_brush = brush_orig;
}
@@ -1273,6 +1277,10 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "PAINT_OT_mask_lasso_gesture", LEFTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ /* Toggle mask visibility */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path", "scene.tool_settings.sculpt.show_mask");
+
/* Toggle dynamic topology */
WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index dacaea6a96e..3982c9a3c30 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -109,6 +109,8 @@ typedef struct PaintStroke {
* e.g. in sculpt mode, stroke doesn't start until cursor
* passes over the mesh */
bool stroke_started;
+ /* Set when enough motion was found for rake rotation */
+ bool rake_started;
/* event that started stroke, for modal() return */
int event_type;
/* check if stroke variables have been initialized */
@@ -233,6 +235,9 @@ static bool paint_brush_update(bContext *C,
UnifiedPaintSettings *ups = stroke->ups;
bool location_sampled = false;
bool location_success = false;
+ /* Use to perform all operations except applying the stroke,
+ * needed for operations that require cursor motion (rake). */
+ bool is_dry_run = false;
bool do_random = false;
bool do_random_mask = false;
/* XXX: Use pressure value from first brush step for brushes which don't
@@ -371,7 +376,15 @@ static bool paint_brush_update(bContext *C,
}
/* curve strokes do their own rake calculation */
else if (!(brush->flag & BRUSH_CURVE)) {
- paint_calculate_rake_rotation(ups, brush, mouse_init);
+ if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) {
+ /* Not enough motion to define an angle. */
+ if (!stroke->rake_started) {
+ is_dry_run = true;
+ }
+ }
+ else {
+ stroke->rake_started = true;
+ }
}
}
@@ -402,7 +415,7 @@ static bool paint_brush_update(bContext *C,
}
}
- return location_success;
+ return location_success && (is_dry_run == false);
}
static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 57a3044cc2b..1ec1e052d43 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -282,7 +282,7 @@ static void imapaint_pick_uv(EvaluationContext *eval_ctx, Scene *scene, Object *
float p[2], w[3], absw, minabsw;
float matrix[4][4], proj[4][4];
GLint view[4];
- const eImageePaintMode mode = scene->toolsettings->imapaint.mode;
+ const eImagePaintMode mode = scene->toolsettings->imapaint.mode;
const MLoopTri *lt = dm->getLoopTriArray(dm);
const MPoly *mpoly = dm->getPolyArray(dm);
const MLoop *mloop = dm->getLoopArray(dm);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index d9df8c78ba9..0c1df71b1aa 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1195,7 +1195,7 @@ static void vwpaint_update_cache_invariants(
cache->invert = mode == BRUSH_STROKE_INVERT;
cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
/* not very nice, but with current events system implementation
- * we can't handle brush appearance inversion hotkey separately (sergey) */
+ * we can't handle brush appearance inversion hotkey separately (sergey) */
if (cache->invert) ups->draw_inverted = true;
else ups->draw_inverted = false;
@@ -1441,7 +1441,9 @@ static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintIn
}
static void do_wpaint_precompute_weight_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
const MDeformVert *dv = &data->me->dvert[n];
@@ -1460,15 +1462,21 @@ static void precompute_weight_values(
.C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me,
};
- BLI_task_parallel_range_ex(
- 0, me->totvert, &data, NULL, 0, do_wpaint_precompute_weight_cb_ex,
- true, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(
+ 0, me->totvert,
+ &data,
+ do_wpaint_precompute_weight_cb_ex,
+ &settings);
wpd->precomputed_weight_ready = true;
}
static void do_wpaint_brush_blur_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1557,7 +1565,9 @@ static void do_wpaint_brush_blur_task_cb_ex(
}
static void do_wpaint_brush_smear_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1664,7 +1674,9 @@ static void do_wpaint_brush_smear_task_cb_ex(
}
static void do_wpaint_brush_draw_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1734,7 +1746,9 @@ static void do_wpaint_brush_draw_task_cb_ex(
}
static void do_wpaint_brush_calc_average_weight_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1785,9 +1799,14 @@ static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UN
struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- BLI_task_parallel_range_ex(
- 0, totnode, data, NULL, 0, do_wpaint_brush_calc_average_weight_cb_ex,
- ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ data,
+ do_wpaint_brush_calc_average_weight_cb_ex,
+ &settings);
uint accum_len = 0;
double accum_weight = 0.0;
@@ -1819,30 +1838,40 @@ static void wpaint_paint_leaves(
/* Use this so average can modify its weight without touching the brush. */
data.strength = BKE_brush_weight_get(scene, brush);
- /* current mirroring code cannot be run in parallel */
- bool use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ /* NOTE: current mirroring code cannot be run in parallel */
+ settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
switch (brush->vertexpaint_tool) {
case PAINT_BLEND_AVERAGE:
calculate_average_weight(&data, nodes, totnode);
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_wpaint_brush_draw_task_cb_ex, use_threading, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_wpaint_brush_draw_task_cb_ex,
+ &settings);
break;
case PAINT_BLEND_SMEAR:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_wpaint_brush_smear_task_cb_ex, use_threading, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_wpaint_brush_smear_task_cb_ex,
+ &settings);
break;
case PAINT_BLEND_BLUR:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_wpaint_brush_blur_task_cb_ex, use_threading, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_wpaint_brush_blur_task_cb_ex,
+ &settings);
break;
default:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_wpaint_brush_draw_task_cb_ex, use_threading, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_wpaint_brush_draw_task_cb_ex,
+ &settings);
break;
}
}
@@ -2398,7 +2427,9 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
}
static void do_vpaint_brush_calc_average_color_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2460,7 +2491,9 @@ static float tex_color_alpha_ubyte(
}
static void do_vpaint_brush_draw_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2552,7 +2585,9 @@ static void do_vpaint_brush_draw_task_cb_ex(
}
static void do_vpaint_brush_blur_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2661,7 +2696,9 @@ static void do_vpaint_brush_blur_task_cb_ex(
}
static void do_vpaint_brush_smear_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2799,9 +2836,13 @@ static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNU
struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- BLI_task_parallel_range_ex(
- 0, totnode, data, NULL, 0, do_vpaint_brush_calc_average_color_cb_ex,
- true, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(
+ 0, totnode,
+ data,
+ do_vpaint_brush_calc_average_color_cb_ex,
+ &settings);
uint accum_len = 0;
uint accum_value[3] = {0};
@@ -2833,27 +2874,37 @@ static void vpaint_paint_leaves(
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd,
.lcol = (uint *)me->mloopcol, .me = me, .C = C,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
switch (brush->vertexpaint_tool) {
case PAINT_BLEND_AVERAGE:
calculate_average_color(&data, nodes, totnode);
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_vpaint_brush_draw_task_cb_ex, true, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_vpaint_brush_draw_task_cb_ex,
+ &settings);
break;
case PAINT_BLEND_BLUR:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_vpaint_brush_blur_task_cb_ex, true, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_vpaint_brush_blur_task_cb_ex,
+ &settings);
break;
case PAINT_BLEND_SMEAR:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_vpaint_brush_smear_task_cb_ex, true, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_vpaint_brush_smear_task_cb_ex,
+ &settings);
break;
default:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0,
- do_vpaint_brush_draw_task_cb_ex, true, false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_vpaint_brush_draw_task_cb_ex,
+ &settings);
break;
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 6e08f47f60d..c9d550aa4bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -377,7 +377,10 @@ static bool sculpt_stroke_is_dynamic_topology(
/*** paint mesh ***/
-static void paint_mesh_restore_co_task_cb(void *userdata, const int n)
+static void paint_mesh_restore_co_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -439,9 +442,14 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, &data, paint_mesh_restore_co_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ &data,
+ paint_mesh_restore_co_task_cb,
+ &settings);
if (nodes)
MEM_freeN(nodes);
@@ -794,7 +802,10 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
-static void calc_area_normal_and_center_task_cb(void *userdata, const int n)
+static void calc_area_normal_and_center_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -946,9 +957,14 @@ static void calc_area_center(
};
BLI_mutex_init(&data.mutex);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, &data, calc_area_normal_and_center_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ &data,
+ calc_area_normal_and_center_task_cb,
+ &settings);
BLI_mutex_end(&data.mutex);
@@ -996,9 +1012,14 @@ void sculpt_pbvh_calc_area_normal(
};
BLI_mutex_init(&data.mutex);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = use_threading;
BLI_task_parallel_range(
- 0, totnode, &data, calc_area_normal_and_center_task_cb,
- use_threading);
+ 0, totnode,
+ &data,
+ calc_area_normal_and_center_task_cb,
+ &settings);
BLI_mutex_end(&data.mutex);
@@ -1036,9 +1057,14 @@ static void calc_area_normal_and_center(
};
BLI_mutex_init(&data.mutex);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, &data, calc_area_normal_and_center_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ &data,
+ calc_area_normal_and_center_task_cb,
+ &settings);
BLI_mutex_end(&data.mutex);
@@ -1626,7 +1652,9 @@ typedef struct {
} SculptFindNearestToRayData;
static void do_smooth_brush_mesh_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1648,7 +1676,7 @@ static void do_smooth_brush_mesh_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), thread_id);
+ vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), tls->thread_id);
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
val *= fade * bstrength;
@@ -1674,7 +1702,9 @@ static void do_smooth_brush_mesh_task_cb_ex(
}
static void do_smooth_brush_bmesh_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1696,7 +1726,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, thread_id);
+ vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, tls->thread_id);
if (smooth_mask) {
float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
@@ -1722,10 +1752,12 @@ static void do_smooth_brush_bmesh_task_cb_ex(
}
static void do_smooth_brush_multires_task_cb_ex(
- void *userdata, void *userdata_chunk, const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
- SculptDoBrushSmoothGridDataChunk *data_chunk = userdata_chunk;
+ SculptDoBrushSmoothGridDataChunk *data_chunk = tls->userdata_chunk;
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
@@ -1837,7 +1869,7 @@ static void do_smooth_brush_multires_task_cb_ex(
const float strength_mask = (smooth_mask ? 0.0f : *mask);
const float fade = bstrength * tex_strength(
ss, brush, co, sqrtf(test.dist),
- NULL, fno, strength_mask, thread_id);
+ NULL, fno, strength_mask, tls->thread_id);
float f = 1.0f / 16.0f;
if (x == 0 || x == gridsize - 1)
@@ -1895,6 +1927,10 @@ static void smooth(
.smooth_mask = smooth_mask, .strength = strength,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+
switch (type) {
case PBVH_GRIDS:
{
@@ -1909,22 +1945,30 @@ static void smooth(
data_chunk->tmpgrid_size = size;
size += sizeof(*data_chunk);
- BLI_task_parallel_range_ex(
- 0, totnode, &data, data_chunk, size, do_smooth_brush_multires_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ settings.userdata_chunk = data_chunk;
+ settings.userdata_chunk_size = size;
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_smooth_brush_multires_task_cb_ex,
+ &settings);
MEM_freeN(data_chunk);
break;
}
case PBVH_FACES:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_smooth_brush_mesh_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_smooth_brush_mesh_task_cb_ex,
+ &settings);
break;
case PBVH_BMESH:
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_smooth_brush_bmesh_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_smooth_brush_bmesh_task_cb_ex,
+ &settings);
break;
}
@@ -1940,7 +1984,9 @@ static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
}
static void do_mask_brush_draw_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -1958,7 +2004,7 @@ static void do_mask_brush_draw_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, 0.0f, thread_id);
+ vd.no, vd.fno, 0.0f, tls->thread_id);
(*vd.mask) += fade * bstrength;
CLAMP(*vd.mask, 0, 1);
@@ -1979,9 +2025,14 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_mask_brush_draw_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_mask_brush_draw_task_cb_ex,
+ &settings);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2000,7 +2051,9 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
static void do_draw_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2022,7 +2075,7 @@ static void do_draw_brush_task_cb_ex(
/* offset vertex */
const float fade = tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2055,16 +2108,23 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.offset = offset,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_draw_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_draw_brush_task_cb_ex,
+ &settings);
}
/**
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
*/
static void do_crease_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2088,7 +2148,7 @@ static void do_crease_brush_task_cb_ex(
/* offset vertex */
const float fade = tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
float val1[3];
float val2[3];
@@ -2152,13 +2212,20 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.spvc = &spvc, .offset = offset, .flippedbstrength = flippedbstrength,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_crease_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_crease_brush_task_cb_ex,
+ &settings);
}
static void do_pinch_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2179,7 +2246,7 @@ static void do_pinch_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
float val[3];
sub_v3_v3v3(val, test.location, vd.co);
@@ -2203,13 +2270,20 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_pinch_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_pinch_brush_task_cb_ex,
+ &settings);
}
static void do_grab_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2236,7 +2310,7 @@ static void do_grab_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(
ss, brush, orig_data.co, sqrtf(test.dist),
- orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id);
+ orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2264,13 +2338,20 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_grab_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_grab_brush_task_cb_ex,
+ &settings);
}
static void do_nudge_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2292,7 +2373,7 @@ static void do_nudge_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -2320,13 +2401,20 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_nudge_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_nudge_brush_task_cb_ex,
+ &settings);
}
static void do_snake_hook_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2353,7 +2441,7 @@ static void do_snake_hook_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2426,13 +2514,20 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.spvc = &spvc, .grab_delta = grab_delta,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_snake_hook_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_snake_hook_brush_task_cb_ex,
+ &settings);
}
static void do_thumb_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2459,7 +2554,7 @@ static void do_thumb_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(
ss, brush, orig_data.co, sqrtf(test.dist),
- orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id);
+ orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -2487,13 +2582,20 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_thumb_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_thumb_brush_task_cb_ex,
+ &settings);
}
static void do_rotate_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2521,7 +2623,7 @@ static void do_rotate_brush_task_cb_ex(
float vec[3], rot[3][3];
const float fade = bstrength * tex_strength(
ss, brush, orig_data.co, sqrtf(test.dist),
- orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id);
+ orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@@ -2549,13 +2651,20 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.angle = angle,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_rotate_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_rotate_brush_task_cb_ex,
+ &settings);
}
static void do_layer_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2589,7 +2698,7 @@ static void do_layer_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
float *disp = &layer_disp[vd.i];
float val[3];
@@ -2634,15 +2743,22 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
BLI_mutex_init(&data.mutex);
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_layer_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_layer_brush_task_cb_ex,
+ &settings);
BLI_mutex_end(&data.mutex);
}
static void do_inflate_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2663,7 +2779,7 @@ static void do_inflate_brush_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
float val[3];
if (vd.fno)
@@ -2689,9 +2805,14 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_inflate_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_inflate_brush_task_cb_ex,
+ &settings);
}
static void calc_sculpt_plane(
@@ -2806,7 +2927,9 @@ static float get_offset(Sculpt *sd, SculptSession *ss)
}
static void do_flatten_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2839,7 +2962,7 @@ static void do_flatten_brush_task_cb_ex(
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2878,13 +3001,20 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.area_no = area_no, .area_co = area_co,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_flatten_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_flatten_brush_task_cb_ex,
+ &settings);
}
static void do_clay_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -2921,7 +3051,7 @@ static void do_clay_brush_task_cb_ex(
* causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2964,13 +3094,20 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_no = area_no, .area_co = area_co,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_clay_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_clay_brush_task_cb_ex,
+ &settings);
}
static void do_clay_strips_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -3006,7 +3143,7 @@ static void do_clay_strips_brush_task_cb_ex(
* causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(
ss, brush, vd.co, ss->cache->radius * test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3074,13 +3211,20 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.area_no_sp = area_no_sp, .area_co = area_co, .mat = mat,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_clay_strips_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_clay_strips_brush_task_cb_ex,
+ &settings);
}
static void do_fill_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -3114,7 +3258,7 @@ static void do_fill_brush_task_cb_ex(
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3155,13 +3299,20 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_no = area_no, .area_co = area_co,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_fill_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_fill_brush_task_cb_ex,
+ &settings);
}
static void do_scrape_brush_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -3194,7 +3345,7 @@ static void do_scrape_brush_task_cb_ex(
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3235,13 +3386,20 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.area_no = area_no, .area_co = area_co,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_scrape_brush_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_scrape_brush_task_cb_ex,
+ &settings);
}
static void do_gravity_task_cb_ex(
- void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -3261,7 +3419,7 @@ static void do_gravity_task_cb_ex(
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = tex_strength(
ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3292,9 +3450,14 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
.offset = offset,
};
- BLI_task_parallel_range_ex(
- 0, totnode, &data, NULL, 0, do_gravity_task_cb_ex,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, totnode,
+ &data,
+ do_gravity_task_cb_ex,
+ &settings);
}
@@ -3396,7 +3559,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
}
}
-static void do_brush_action_task_cb(void *userdata, const int n)
+static void do_brush_action_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
@@ -3423,9 +3589,14 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, &task_data, do_brush_action_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ &task_data,
+ do_brush_action_task_cb,
+ &settings);
if (sculpt_brush_needs_normal(brush, ss->cache->normal_weight))
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -3537,7 +3708,10 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
copy_v3_v3(me->mvert[index].co, newco);
}
-static void sculpt_combine_proxies_task_cb(void *userdata, const int n)
+static void sculpt_combine_proxies_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -3604,9 +3778,14 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, &data, sculpt_combine_proxies_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ &data,
+ sculpt_combine_proxies_task_cb,
+ &settings);
}
if (nodes)
@@ -3632,7 +3811,10 @@ static void sculpt_update_keyblock(Object *ob)
}
}
-static void sculpt_flush_stroke_deform_task_cb(void *userdata, const int n)
+static void sculpt_flush_stroke_deform_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@@ -3685,9 +3867,14 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
.vertCos = vertCos,
};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, &data, sculpt_flush_stroke_deform_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ &data,
+ sculpt_flush_stroke_deform_task_cb,
+ &settings);
if (vertCos) {
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -4505,7 +4692,7 @@ static float sculpt_raycast_init(
RegionView3D *rv3d = vc->ar->regiondata;
/* TODO: what if the segment is totally clipped? (return == 0) */
- ED_view3d_win_to_segment(vc->ar, vc->v3d, mouse, ray_start, ray_end, true);
+ ED_view3d_win_to_segment(vc->depsgraph, vc->ar, vc->v3d, mouse, ray_start, ray_end, true);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index aaea13ce5d0..5fb9eee805f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -119,7 +119,7 @@ typedef struct SculptUndoNode {
} SculptUndoNode;
/* Factor of brush to have rake point following behind
-* (could be configurable but this is reasonable default). */
+ * (could be configurable but this is reasonable default). */
#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
struct SculptRakeData {
@@ -148,7 +148,7 @@ typedef struct SculptThreadedTaskData {
/* Data specific to some callbacks. */
/* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
- * what it is, and memory overhead is ridiculous anyway... */
+ * what it is, and memory overhead is ridiculous anyway... */
float flippedbstrength;
float angle;
float strength;
@@ -239,10 +239,10 @@ void sculpt_pbvh_calc_area_normal(
float r_area_no[3]);
/* Cache stroke properties. Used because
-* RNA property lookup isn't particularly fast.
-*
-* For descriptions of these settings, check the operator properties.
-*/
+ * RNA property lookup isn't particularly fast.
+ *
+ * For descriptions of these settings, check the operator properties.
+ */
typedef struct StrokeCache {
/* Invariants */
@@ -296,13 +296,13 @@ typedef struct StrokeCache {
float view_normal[3];
/* sculpt_normal gets calculated by calc_sculpt_normal(), then the
- * sculpt_normal_symm gets updated quickly with the usual symmetry
- * transforms */
+ * sculpt_normal_symm gets updated quickly with the usual symmetry
+ * transforms */
float sculpt_normal[3];
float sculpt_normal_symm[3];
/* Used for area texture mode, local_mat gets calculated by
- * calc_brush_local_mat() and used in tex_strength(). */
+ * calc_brush_local_mat() and used in tex_strength(). */
float brush_local_mat[4][4];
float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index a10c7477dc6..63017a0e576 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -319,7 +319,10 @@ static bool sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNod
return 1;
}
-static void sculpt_undo_bmesh_restore_generic_task_cb(void *userdata, const int n)
+static void sculpt_undo_bmesh_restore_generic_task_cb(
+ void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
PBVHNode **nodes = userdata;
@@ -347,9 +350,14 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(
- 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb,
- ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+ 0, totnode,
+ nodes,
+ sculpt_undo_bmesh_restore_generic_task_cb,
+ &settings);
if (nodes)
MEM_freeN(nodes);
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index fdf2dfe8371..29b3c6f2f6c 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -125,7 +125,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact)
}
else {
/* just make a new (empty) action */
- action = add_empty_action(CTX_data_main(C), "Action");
+ action = BKE_action_add(CTX_data_main(C), "Action");
}
/* when creating new ID blocks, there is already 1 user (as for all new datablocks),
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 1c55a0d76cf..110c4d1789d 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1127,7 +1127,8 @@ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op)
actkeys_select_leftright(&ac, leftright, selectmode);
/* set notifier that keyframe selection (and channels too) have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1577,7 +1578,8 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent
mouse_action_keys(&ac, event->mval, selectmode, column, channel);
/* set notifier that keyframe selection (and channels too) have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
/* for tweak grab to work */
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 7850a57f534..e47841ab574 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -128,6 +128,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_ui();
/* manipulator types */
+ ED_manipulatortypes_button_2d();
ED_manipulatortypes_dial_3d();
ED_manipulatortypes_grab_3d();
ED_manipulatortypes_arrow_2d();
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index d2f407bfa8c..179780bf517 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -225,6 +225,28 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
+static void buttons_header_region_message_subscribe(
+ const bContext *UNUSED(C),
+ WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
+ bScreen *UNUSED(screen), ScrArea *sa, ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ SpaceButs *sbuts = sa->spacedata.first;
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Don't check for SpaceButs.mainb here, we may toggle between view-layers
+ * where one has no active object, so that available contexts changes. */
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+
+ if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_WORLD)) {
+ WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
+ }
+}
+
/* draw a certain button set only if properties area is currently
* showing that button set, to reduce unnecessary drawing. */
static void buttons_area_redraw(ScrArea *sa, short buttons)
@@ -503,6 +525,7 @@ void ED_spacetype_buttons(void)
art->init = buttons_header_region_init;
art->draw = buttons_header_region_draw;
+ art->message_subscribe = buttons_header_region_message_subscribe;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index eb9aadd2e72..469d94fed3a 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -107,7 +107,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr);
if (!compact)
- uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (clip) {
uiLayout *col;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 60736cfb885..7e37ae1238c 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -138,6 +138,8 @@ void clip_graph_tracking_iterate(struct SpaceClip *sc, bool selected_only, bool
void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track);
void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker);
+void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track);
+
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene);
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 40661937bae..7f9d9bf577c 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -184,37 +184,37 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
bool has_bundle = false;
- char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
- const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT));
-
- if (track == act_track)
+ const bool used_for_stabilization =
+ (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) != 0;
+ if (track == act_track) {
tracking->act_track = NULL;
-
- /* handle reconstruction display in 3d viewport */
- if (track->flag & TRACK_HAS_BUNDLE)
+ }
+ /* Handle reconstruction display in 3d viewport. */
+ if (track->flag & TRACK_HAS_BUNDLE) {
has_bundle = true;
-
+ }
/* Make sure no plane will use freed track */
BKE_tracking_plane_tracks_remove_point_track(tracking, track);
-
/* Delete f-curves associated with the track (such as weight, i.e.) */
- BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
- BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped);
- BKE_animdata_fix_paths_remove(&clip->id, prefix);
-
+ /* Escaped object name, escaped track name, rest of the path. */
+ char rna_path[MAX_NAME * 4 + 64];
+ BKE_tracking_get_rna_path_for_track(tracking,
+ track,
+ rna_path, sizeof(rna_path));
+ BKE_animdata_fix_paths_remove(&clip->id, rna_path);
+ /* Delete track itself. */
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
-
+ /* Send notifiers. */
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
-
if (used_for_stabilization) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
-
+ /* Inform dependency graph. */
DEG_id_tag_update(&clip->id, 0);
-
- if (has_bundle)
+ if (has_bundle) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ }
}
void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track,
@@ -230,6 +230,28 @@ void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track,
}
}
+void clip_delete_plane_track(bContext *C,
+ MovieClip *clip,
+ MovieTrackingPlaneTrack *plane_track)
+{
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ /* Delete f-curves associated with the track (such as weight, i.e.) */
+ /* Escaped object name, escaped track name, rest of the path. */
+ char rna_path[MAX_NAME * 4 + 64];
+ BKE_tracking_get_rna_path_for_plane_track(tracking,
+ plane_track,
+ rna_path, sizeof(rna_path));
+ BKE_animdata_fix_paths_remove(&clip->id, rna_path);
+ /* Delete the plane track itself. */
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ /* TODO(sergey): Any notifiers to be sent here? */
+ (void) C;
+ /* Inform dependency graph. */
+ DEG_id_tag_update(&clip->id, 0);
+}
+
void clip_view_center_to_point(SpaceClip *sc, float x, float y)
{
int width, height;
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 2439ac06d9c..4ca2b54eaaf 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -227,7 +227,6 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
bool changed = false;
-
/* Delete selected plane tracks. */
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first,
@@ -236,14 +235,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
plane_track = next_plane_track)
{
next_plane_track = plane_track->next;
-
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- BKE_tracking_plane_track_free(plane_track);
- BLI_freelinkN(plane_tracks_base, plane_track);
+ clip_delete_plane_track(C, clip, plane_track);
changed = true;
}
}
-
/* Remove selected point tracks (they'll also be removed from planes which
* uses them).
*/
@@ -258,14 +254,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
changed = true;
}
}
-
/* Nothing selected now, unlock view so it can be scrolled nice again. */
sc->flag &= ~SC_LOCK_SELECTION;
-
if (changed) {
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
}
-
return OPERATOR_FINISHED;
}
@@ -1866,6 +1859,10 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
}
}
+ if (count == 0) {
+ ok = 0;
+ }
+
if (del) {
MEM_freeN(track->markers);
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index eddd65475a2..4ee85ace271 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -906,7 +906,7 @@ void CLIP_OT_select_all(wmOperatorType *ot)
/********************** select grouped operator *********************/
-static int select_groped_exec(bContext *C, wmOperator *op)
+static int select_grouped_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -989,7 +989,7 @@ void CLIP_OT_select_grouped(wmOperatorType *ot)
ot->idname = "CLIP_OT_select_grouped";
/* api callbacks */
- ot->exec = select_groped_exec;
+ ot->exec = select_grouped_exec;
ot->poll = ED_space_clip_tracking_poll;
/* flags */
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 3f26604c23a..3c90f2957df 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -289,8 +289,9 @@ static void file_refresh(const bContext *C, ScrArea *sa)
file_tools_region(sa);
ED_area_initialize(wm, CTX_wm_window(C), sa);
- ED_area_tag_redraw(sa);
}
+
+ ED_area_tag_redraw(sa);
}
static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene),
@@ -304,16 +305,13 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Sce
switch (wmn->data) {
case ND_SPACE_FILE_LIST:
ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
break;
case ND_SPACE_FILE_PARAMS:
ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
break;
case ND_SPACE_FILE_PREVIEW:
if (sfile->files && filelist_cache_previews_update(sfile->files)) {
ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
}
break;
}
@@ -372,6 +370,15 @@ static void file_main_region_message_subscribe(
.notify = ED_area_do_msg_notify_tag_refresh,
};
+ /* SpaceFile itself. */
+ {
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr);
+
+ /* All properties for this space type. */
+ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
+ }
+
/* FileSelectParams */
{
PointerRNA ptr;
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 2876fccaa51..29e3f99e1d4 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2747,3 +2747,89 @@ void GRAPH_OT_driver_variables_paste(wmOperatorType *ot)
}
/* ************************************************************************** */
+
+static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ bool ok = false;
+ unsigned int deleted = 0;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* NOTE: we might need a scene update to evaluate the driver flags */
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* find invalid drivers */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->data;
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ continue;
+ }
+ if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) {
+ continue;
+ }
+
+ ok |= ANIM_remove_driver(op->reports, ale->id, fcu->rna_path, fcu->array_index, 0);
+ if (!ok) {
+ break;
+ }
+ deleted += 1;
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+
+ if (deleted > 0) {
+ /* notify the world of any changes */
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
+ WM_reportf(RPT_INFO, "Deleted %u drivers", deleted);
+ }
+ else {
+ WM_report(RPT_INFO, "No drivers deleted");
+ }
+
+ /* successful or not? */
+ if (!ok) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int graph_driver_delete_invalid_poll(bContext *C)
+{
+ bAnimContext ac;
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* firstly, check if in Graph Editor */
+ if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
+ return 0;
+
+ /* try to init Anim-Context stuff ourselves and check */
+ return ANIM_animdata_get_context(C, &ac) != 0;
+}
+
+
+void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Invalid Drivers";
+ ot->idname = "GRAPH_OT_driver_delete_invalid";
+ ot->description = "Delete all visible drivers considered invalid";
+
+ /* api callbacks */
+ ot->exec = graph_driver_delete_invalid_exec;
+ ot->poll = graph_driver_delete_invalid_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 534b712fd5e..6c375b23352 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -152,6 +152,7 @@ void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot);
void GRAPH_OT_driver_variables_copy(struct wmOperatorType *ot);
void GRAPH_OT_driver_variables_paste(struct wmOperatorType *ot);
+void GRAPH_OT_driver_delete_invalid(struct wmOperatorType *ot);
/* ----------- */
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 62275abcd02..57d8f45905d 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -468,6 +468,7 @@ void graphedit_operatortypes(void)
/* Drivers */
WM_operatortype_append(GRAPH_OT_driver_variables_copy);
WM_operatortype_append(GRAPH_OT_driver_variables_paste);
+ WM_operatortype_append(GRAPH_OT_driver_delete_invalid);
}
void ED_operatormacros_graph(void)
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 1683fbdbdb9..392db4ef4b5 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -1003,7 +1003,8 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op)
graphkeys_select_leftright(&ac, leftright, selectmode);
/* set notifier that keyframe selection (and channels too) have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1517,7 +1518,8 @@ static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEve
}
/* set notifier that keyframe selection (and also channel selection in some cases) has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
/* for tweak grab to work */
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 51ccaf6800a..20f9658020d 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -871,8 +871,11 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiLayoutSetContextPointer(layout, "edit_image", &imaptr);
uiLayoutSetContextPointer(layout, "edit_image_user", userptr);
- if (!compact)
- uiTemplateID(layout, C, ptr, propname, ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+ if (!compact) {
+ uiTemplateID(
+ layout, C, ptr, propname,
+ ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ }
if (ima) {
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index a95f7ccd69e..de158f84a4d 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1152,9 +1152,10 @@ static int image_cmp_frame(const void *a, const void *b)
}
/**
- * \brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames
- * \param frames [in] the list of frame numbers, as a side-effect the list is sorted
- * \param ofs [out] offest, the first frame number in the sequence
+ * Return the start (offset) and the length of the sequence of continuous frames in the list of frames
+ *
+ * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted.
+ * \param ofs: [out] offset the first frame number in the sequence.
* \return the number of contiguous frames in the sequence
*/
static int image_sequence_get_len(ListBase *frames, int *ofs)
@@ -1857,7 +1858,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
scene = CTX_data_scene(C);
rr = BKE_image_acquire_renderresult(scene, ima);
bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2;
- bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER);
+ bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr);
/* error handling */
if (!rr) {
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 4f595ad98c6..a89ae2b869a 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -95,6 +95,18 @@ static void image_scopes_tag_refresh(ScrArea *sa)
sima->scopes.ok = 0;
}
+static void image_user_refresh_scene(const bContext *C, SpaceImage *sima)
+{
+ if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
+ /* for render result, try to use the currently rendering scene */
+ Scene *render_scene = ED_render_job_get_current_scene(C);
+ if (render_scene) {
+ sima->iuser.scene = render_scene;
+ return;
+ }
+ }
+ sima->iuser.scene = CTX_data_scene(C);
+}
/* ******************** manage regions ********************* */
@@ -734,17 +746,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
- /* put scene context variable in iuser */
- if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
- /* for render result, try to use the currently rendering scene */
- Scene *render_scene = ED_render_job_get_current_scene(C);
- if (render_scene)
- sima->iuser.scene = render_scene;
- else
- sima->iuser.scene = scene;
- }
- else
- sima->iuser.scene = scene;
+ image_user_refresh_scene(C, sima);
/* we set view2d from own zoom and offset each time */
image_main_region_set_view2d(sima, ar);
@@ -1014,6 +1016,11 @@ static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
static void image_header_region_draw(const bContext *C, ARegion *ar)
{
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceImage *sima = sa->spacedata.first;
+
+ image_user_refresh_scene(C, sima);
+
ED_region_header(C, ar);
}
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 4f042364c63..b13152883c3 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -50,6 +50,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
#include "UI_resources.h"
#include "UI_interface.h"
@@ -284,6 +287,22 @@ static void info_header_listener(
}
+static void info_header_region_message_subscribe(
+ const bContext *UNUSED(C),
+ WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
+ bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
+}
+
static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu)
{
struct RecentFile *recent;
@@ -347,6 +366,7 @@ void ED_spacetype_info(void)
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
art->listener = info_header_listener;
+ art->message_subscribe = info_header_region_message_subscribe;
art->init = info_header_region_init;
art->draw = info_header_region_draw;
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 69bf51ade3a..c6fd70a60dd 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -2011,7 +2011,7 @@ static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C)
{
uiLayout *row, *col;
- uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!RNA_pointer_get(ptr, "sound").data) {
uiItemL(layout, IFACE_("Select a sound from the list or load a new one"), ICON_NONE);
return;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index c774b99629c..3080ac2de84 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -285,7 +285,9 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
/* Active Action Properties ------------------------------------- */
/* action */
row = uiLayoutRow(layout, true);
- uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, "NLA_OT_action_unlink");
+ uiTemplateID(
+ row, (bContext *)C, &adt_ptr, "action",
+ "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL);
/* extrapolation */
row = uiLayoutRow(layout, true);
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 1179401f346..e09e4417d5d 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -444,7 +444,8 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op)
nlaedit_select_leftright(C, &ac, leftright, selectmode);
/* set notifier that keyframe selection (and channels too) have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index c591433f7b1..1bee2716e65 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -284,7 +284,7 @@ static int node_resize_area_default(bNode *node, int x, int y)
static void node_draw_buttons_group(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL);
+ uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
}
/* XXX Does a bounding box update by iterating over all children.
@@ -633,7 +633,8 @@ static void node_common_set_butfunc(bNodeType *ntype)
/* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */
static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
- PointerRNA *imaptr, PointerRNA *iuserptr)
+ PointerRNA *imaptr, PointerRNA *iuserptr,
+ bool compositor)
{
uiLayout *col;
int source;
@@ -668,7 +669,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
}
- if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ if (compositor &&
+ RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers"))
{
col = uiLayoutColumn(layout, false);
@@ -681,7 +683,7 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA
bNode *node = ptr->data;
uiLayout *col;
- uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL);
+ uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!node->id) return;
@@ -778,7 +780,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
@@ -792,7 +794,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
*/
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
}
static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -807,9 +809,11 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiTemplateID(
+ layout, C, ptr, "image",
+ NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
@@ -823,7 +827,9 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
Image *ima = imaptr.data;
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout, C, ptr, "image", ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+ uiTemplateID(
+ layout, C, ptr, "image",
+ ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!ima)
return;
@@ -1250,12 +1256,14 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiTemplateID(
+ layout, C, ptr, "image",
+ NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!node->id) return;
imaptr = RNA_pointer_get(ptr, "image");
- node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr);
+ node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true);
node_buts_image_views(layout, C, ptr, &imaptr);
}
@@ -1280,7 +1288,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
const char *layer_name;
char scene_name[MAX_ID_NAME - 2];
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!node->id) return;
@@ -1394,7 +1402,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
@@ -1961,7 +1969,7 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
}
static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1969,7 +1977,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point
bNode *node = ptr->data;
PointerRNA clipptr;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!node->id)
return;
@@ -1983,7 +1991,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!node->id)
return;
@@ -2007,7 +2015,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!node->id)
return;
@@ -2315,7 +2323,7 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL);
+ uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE);
@@ -2337,7 +2345,7 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2373,7 +2381,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2413,7 +2421,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
bNode *node = ptr->data;
NodePlaneTrackDeformData *data = node->storage;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2791,7 +2799,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
}
static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 64c019d12a3..70f7553cf41 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -31,12 +31,14 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_node_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_easing.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -63,6 +65,15 @@
/* ****************** Relations helpers *********************** */
+static bool ntree_has_drivers(bNodeTree *ntree)
+{
+ AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ if (adt == NULL) {
+ return false;
+ }
+ return !BLI_listbase_is_empty(&adt->drivers);
+}
+
static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree,
bNode *from,
bNode *to)
@@ -134,6 +145,14 @@ static bool node_group_has_output(bNode *node)
bool node_connected_to_output(bNodeTree *ntree, bNode *node)
{
+ /* Special case for drivers: if node tree has any drivers we assume it is
+ * always to be tagged for update when node changes. Otherwise we will be
+ * doomed to do some deep and nasty deep search of indirect dependencies,
+ * which will be too complicated without real benefit.
+ */
+ if (ntree_has_drivers(ntree)) {
+ return true;
+ }
for (bNode *current_node = ntree->nodes.first;
current_node != NULL;
current_node = current_node->next)
@@ -144,11 +163,17 @@ bool node_connected_to_output(bNodeTree *ntree, bNode *node)
* We could make check more grained here by taking which socket the node
* is connected to and so eventually.
*/
- if (current_node->type == NODE_GROUP &&
- ntree_check_nodes_connected(ntree, node, current_node) &&
- node_group_has_output(current_node))
- {
- return true;
+ if (current_node->type == NODE_GROUP) {
+ if (current_node->id != NULL &&
+ ntree_has_drivers((bNodeTree *)current_node->id))
+ {
+ return true;
+ }
+ if (ntree_check_nodes_connected(ntree, node, current_node) &&
+ node_group_has_output(current_node))
+ {
+ return true;
+ }
}
if (current_node->flag & NODE_DO_OUTPUT) {
if (ntree_check_nodes_connected(ntree, node, current_node)) {
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index d5c833a7b5f..8999555521a 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -51,13 +51,13 @@
#include "outliner_intern.h" /* own include */
+/* Prototypes. */
+static int collection_delete_exec(struct bContext *C, struct wmOperator *op);
+
/* -------------------------------------------------------------------- */
static LayerCollection *outliner_collection_active(bContext *C)
{
- TODO_LAYER_OPERATORS;
- /* consider that we may have overrides or objects active
- * leading to no active collections */
return CTX_data_layer_collection(C);
}
@@ -76,14 +76,20 @@ SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te)
return NULL;
}
-#if 0
-static CollectionOverride *outliner_override_active(bContext *UNUSED(C))
+/* -------------------------------------------------------------------- */
+/* Poll functions. */
+
+static int collections_editor_poll(bContext *C)
{
- TODO_LAYER_OPERATORS;
- TODO_LAYER_OVERRIDE;
- return NULL;
+ SpaceOops *so = CTX_wm_space_outliner(C);
+ return (so != NULL) && (so->outlinevis == SO_COLLECTIONS);
+}
+
+static int view_layer_editor_poll(bContext *C)
+{
+ SpaceOops *so = CTX_wm_space_outliner(C);
+ return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER);
}
-#endif
/* -------------------------------------------------------------------- */
/* collection manager operators */
@@ -108,6 +114,44 @@ static SceneCollection *scene_collection_from_index(ListBase *lb, const int numb
return NULL;
}
+typedef struct TreeElementFindData {
+ SceneCollection *collection;
+ TreeElement *r_result_te;
+} TreeElementFindData;
+
+static TreeTraversalAction tree_element_find_by_scene_collection_cb(TreeElement *te, void *customdata)
+{
+ TreeElementFindData *data = customdata;
+ const SceneCollection *current_element_sc = outliner_scene_collection_from_tree_element(te);
+
+ if (current_element_sc == data->collection) {
+ data->r_result_te = te;
+ return TRAVERSE_BREAK;
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+static TreeElement *outliner_tree_element_from_layer_collection_index(
+ SpaceOops *soops, ViewLayer *view_layer,
+ const int index)
+{
+ LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index);
+
+ if (lc == NULL) {
+ return NULL;
+ }
+
+ /* Find the tree element containing the LayerCollection's scene_collection. */
+ TreeElementFindData data = {
+ .collection = lc->scene_collection,
+ .r_result_te = NULL,
+ };
+ outliner_tree_traverse(soops, &soops->tree, 0, 0, tree_element_find_by_scene_collection_cb, &data);
+
+ return data.r_result_te;
+}
+
static int collection_link_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -187,7 +231,7 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Collection";
+ ot->name = "Link Collection";
ot->idname = "OUTLINER_OT_collection_link";
ot->description = "Link a new collection to the active layer";
@@ -210,6 +254,10 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot)
*/
static int collection_unlink_poll(bContext *C)
{
+ if (view_layer_editor_poll(C) == 0) {
+ return 0;
+ }
+
LayerCollection *lc = outliner_collection_active(C);
if (lc == NULL) {
@@ -249,7 +297,7 @@ static int collection_unlink_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Collection";
+ ot->name = "Unlink Collection";
ot->idname = "OUTLINER_OT_collection_unlink";
ot->description = "Unlink collection from the active layer";
@@ -292,40 +340,218 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot)
}
/**********************************************************************************/
+/* Add new nested collection. */
-/**
- * Returns true is selected element is a collection
- */
-static int collection_override_new_poll(bContext *(C))
+struct CollectionNewData
+{
+ bool error;
+ SceneCollection *scene_collection;
+};
+
+static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
+{
+ struct CollectionNewData *data = customdata;
+ SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
+
+ if (!scene_collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ if (data->scene_collection != NULL) {
+ data->error = true;
+ return TRAVERSE_BREAK;
+ }
+
+ data->scene_collection = scene_collection;
+ return TRAVERSE_CONTINUE;
+}
+
+static int collection_nested_new_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ struct CollectionNewData data = {
+ .error = false,
+ .scene_collection = NULL,
+ };
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
+
+ if (data.error) {
+ BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_collection_add(
+ &scene->id,
+ data.scene_collection,
+ COLLECTION_TYPE_NONE,
+ NULL);
+
+ outliner_cleanup_tree(soops);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_nested_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Nested Collection";
+ ot->idname = "OUTLINER_OT_collection_nested_new";
+ ot->description = "Add a new collection inside selected collection";
+
+ /* api callbacks */
+ ot->exec = collection_nested_new_exec;
+ ot->poll = collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/**********************************************************************************/
+/* Delete selected collection. */
+
+void OUTLINER_OT_collection_delete_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Selected Collections";
+ ot->idname = "OUTLINER_OT_collection_delete_selected";
+ ot->description = "Delete all the selected collections";
+
+ /* api callbacks */
+ ot->exec = collection_delete_exec;
+ ot->poll = collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/**********************************************************************************/
+/* Add new selected objects. */
+
+struct SceneCollectionSelectedData {
+ ListBase scene_collections_array;
+};
+
+static TreeTraversalAction collection_find_selected_scene_collections(TreeElement *te, void *customdata)
+{
+ struct SceneCollectionSelectedData *data = customdata;
+ SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
+
+ if (!scene_collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ BLI_addtail(&data->scene_collections_array, BLI_genericNodeN(scene_collection));
+ return TRAVERSE_CONTINUE;
+}
+
+static int collection_objects_add_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ struct SceneCollectionSelectedData data = {
+ .scene_collections_array = {NULL, NULL},
+ };
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data);
+
+ if (BLI_listbase_is_empty(&data.scene_collections_array)) {
+ BKE_report(op->reports, RPT_ERROR, "No collection is selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects)
+ {
+ BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) {
+ SceneCollection *scene_collection = link->data;
+ BKE_collection_object_add(
+ &scene->id,
+ scene_collection,
+ ob);
+ }
+ }
+ CTX_DATA_END;
+ BLI_freelistN(&data.scene_collections_array);
+
+ outliner_cleanup_tree(soops);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
{
-#ifdef TODO_LAYER_OVERRIDE
- /* disable for now, since it's not implemented */
- (void) C;
- return 0;
-#else
- return outliner_collection_active(C) ? 1 : 0;
-#endif
+ /* identifiers */
+ ot->name = "Add Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_add";
+ ot->description = "Add selected objects to collection";
+
+ /* api callbacks */
+ ot->exec = collection_objects_add_exec;
+ ot->poll = collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
+/**********************************************************************************/
+/* Remove selected objects. */
+
+
+static int collection_objects_remove_exec(bContext *C, wmOperator *op)
{
- TODO_LAYER_OPERATORS;
- TODO_LAYER_OVERRIDE;
- BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet");
- return OPERATOR_CANCELLED;
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ struct SceneCollectionSelectedData data = {
+ .scene_collections_array = {NULL, NULL},
+ };
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data);
+
+ if (BLI_listbase_is_empty(&data.scene_collections_array)) {
+ BKE_report(op->reports, RPT_ERROR, "No collection is selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects)
+ {
+ BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) {
+ SceneCollection *scene_collection = link->data;
+ BKE_collection_object_remove(
+ bmain,
+ &scene->id,
+ scene_collection,
+ ob,
+ true);
+ }
+ }
+ CTX_DATA_END;
+ BLI_freelistN(&data.scene_collections_array);
+
+ outliner_cleanup_tree(soops);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
}
-/* in the middle of renames remove s */
-void OUTLINER_OT_collection_override_new(wmOperatorType *ot)
+void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "New Override";
- ot->idname = "OUTLINER_OT_collection_override_new";
- ot->description = "Add a new override to the active collection";
+ ot->name = "Remove Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_remove";
+ ot->description = "Remove selected objects from collection";
/* api callbacks */
- ot->invoke = collection_override_new_invoke;
- ot->poll = collection_override_new_poll;
+ ot->exec = collection_objects_remove_exec;
+ ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -352,6 +578,26 @@ static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void
}
else {
BLI_gset_add(data->collections_to_delete, scene_collection);
+ return TRAVERSE_SKIP_CHILDS; /* Childs will be gone anyway, no need to recurse deeper. */
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+static TreeTraversalAction collection_delete_elements_from_collection(TreeElement *te, void *customdata)
+{
+ struct CollectionDeleteData *data = customdata;
+ SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
+
+ if (!scene_collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ const bool will_be_deleted = BLI_gset_haskey(data->collections_to_delete, scene_collection);
+ if (will_be_deleted) {
+ outliner_free_tree_element(te, te->parent ? &te->parent->subtree : &data->soops->tree);
+ /* Childs are freed now, so don't recurse into them. */
+ return TRAVERSE_SKIP_CHILDS;
}
return TRAVERSE_CONTINUE;
@@ -365,26 +611,33 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
data.collections_to_delete = BLI_gset_ptr_new(__func__);
- TODO_LAYER_OVERRIDE; /* handle overrides */
-
/* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */
outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data);
+ /* Now, delete all tree elements representing a collection that will be deleted. We'll look for a
+ * new element to select in a few lines, so we can't wait until the tree is recreated on redraw. */
+ outliner_tree_traverse(soops, &soops->tree, 0, 0, collection_delete_elements_from_collection, &data);
+
/* Effectively delete the collections. */
GSetIterator collections_to_delete_iter;
GSET_ITER(collections_to_delete_iter, data.collections_to_delete) {
-
SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter);
BKE_collection_remove(&data.scene->id, sc);
}
BLI_gset_free(data.collections_to_delete, NULL);
+ TreeElement *select_te = outliner_tree_element_from_layer_collection_index(soops, CTX_data_view_layer(C), 0);
+ if (select_te) {
+ outliner_item_select(soops, select_te, false, false);
+ }
+
DEG_relations_tag_update(CTX_data_main(C));
/* TODO(sergey): Use proper flag for tagging here. */
DEG_id_tag_update(&scene->id, 0);
+ soops->storeflag |= SO_TREESTORE_REDRAW;
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;
@@ -438,13 +691,12 @@ static int collection_toggle_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
int action = RNA_enum_get(op->ptr, "action");
LayerCollection *layer_collection = CTX_data_layer_collection(C);
if (layer_collection->flag & COLLECTION_DISABLED) {
if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) {
- BKE_collection_enable(view_layer, layer_collection);
+ layer_collection->flag &= ~COLLECTION_DISABLED;
}
else { /* ACTION_DISABLE */
BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled",
@@ -454,7 +706,7 @@ static int collection_toggle_exec(bContext *C, wmOperator *op)
}
else {
if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) {
- BKE_collection_disable(view_layer, layer_collection);
+ layer_collection->flag |= COLLECTION_DISABLED;
}
else { /* ACTION_ENABLE */
BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled",
@@ -505,68 +757,3 @@ void OUTLINER_OT_collection_toggle(wmOperatorType *ot)
#undef ACTION_TOGGLE
#undef ACTION_ENABLE
#undef ACTION_DISABLE
-
-/* -------------------------------------------------------------------- */
-
-static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
-{
- TODO_LAYER_OPERATORS;
- BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet");
- return OPERATOR_CANCELLED;
-}
-
-void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Objects";
- ot->idname = "OUTLINER_OT_collection_objects_add";
- ot->description = "Add selected objects to collection";
-
- /* api callbacks */
- ot->invoke = stubs_invoke;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Object";
- ot->idname = "OUTLINER_OT_collection_objects_remove";
- ot->description = "Remove objects from collection";
-
- /* api callbacks */
- ot->invoke = stubs_invoke;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Objects";
- ot->idname = "OUTLINER_OT_collection_objects_select";
- ot->description = "Select collection objects";
-
- /* api callbacks */
- ot->invoke = stubs_invoke;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Deselect Objects";
- ot->idname = "OUTLINER_OT_collection_objects_deselect";
- ot->description = "Deselect collection objects";
-
- /* api callbacks */
- ot->invoke = stubs_invoke;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 670fc4e6627..1478792b38b 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -247,49 +247,16 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ID *id = poin;
- LayerCollection *layer_collection = poin2;
- ViewLayer *view_layer = BKE_view_layer_find_from_collection(id, layer_collection);
-
- /* TODO: This breaks when you see the collections of a group. (dfelinto) */
- if (view_layer == NULL) {
- WM_reportf(RPT_INFO, "Enable/disable of group collections disabled for now");
- return;
- }
-
- /* We need to toggle the flag since this is called after the flag is already set. */
- layer_collection->flag ^= COLLECTION_DISABLED;
-
- if (layer_collection->flag & COLLECTION_DISABLED) {
- BKE_collection_enable(view_layer, layer_collection);
- }
- else {
- BKE_collection_disable(view_layer, layer_collection);
- }
-
- DEG_relations_tag_update(bmain);
- /* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
-}
-
static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2))
{
ID *id = (ID *)poin;
- /* hide and deselect bases that are directly influenced by this LayerCollection */
/* TODO(sergey): Use proper flag for tagging here. */
DEG_id_tag_update(id, 0);
if (GS(id->name) == ID_SCE) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id);
}
-
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
}
@@ -602,21 +569,6 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0,
- is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
- TIP_("Enable/Disable collection from depsgraph"));
- UI_but_func_set(bt, enablebutton_collection_flag_cb, tselem->id, collection);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
- TIP_("Restrict/Allow 3D View visibility of objects in the collection"));
- UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
if (collection->scene_collection->type == COLLECTION_TYPE_NONE) {
bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
@@ -625,6 +577,31 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
+ else if ((soops->outlinevis == SO_GROUPS) &&
+ (collection->scene_collection->type == COLLECTION_TYPE_GROUP_INTERNAL))
+ {
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VIEWPORT, 0, ICON_RESTRICT_VIEW_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow 3D View selection of objects in the collection"));
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_RENDER, 0, ICON_RESTRICT_RENDER_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow 3D View selection of objects in the collection"));
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ }
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0,
+ is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
+ TIP_("Enable/Disable collection"));
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_block_emboss_set(block, UI_EMBOSS);
}
@@ -694,7 +671,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
}
}
-static void outliner_draw_rnacols(ARegion *ar, int sizex)
+static void UNUSED_FUNCTION(outliner_draw_rnacols)(ARegion *ar, int sizex)
{
View2D *v2d = &ar->v2d;
@@ -720,6 +697,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex)
immUnbindProgram();
}
+#if 0
static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
{
TreeElement *te;
@@ -764,6 +742,7 @@ static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops,
UI_block_emboss_set(block, UI_EMBOSS);
}
+#endif
static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te)
{
@@ -1131,6 +1110,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
ICON_DRAW(icon);
}
break;
+ case TSE_LAYER_COLLECTION:
+ case TSE_SCENE_COLLECTION:
+ ICON_DRAW(ICON_COLLAPSEMENU);
+ break;
/* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
#if 0
case TSE_GP_LAYER:
@@ -1378,22 +1361,24 @@ static void outliner_draw_tree_element(
}
else if (te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
-
- if (ob == OBACT(view_layer) || (ob->flag & SELECT)) {
+ Base *base = (Base *)te->directdata;
+ const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+
+ if (ob == OBACT(view_layer) || is_selected) {
char col[4] = {0, 0, 0, 0};
/* outliner active ob: always white text, circle color now similar to view3d */
active = OL_DRAWSEL_ACTIVE;
if (ob == OBACT(view_layer)) {
- if (ob->flag & SELECT) {
+ if (is_selected) {
UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
col[3] = alpha;
}
active = OL_DRAWSEL_NORMAL;
}
- else if (ob->flag & SELECT) {
+ else if (is_selected) {
UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
col[3] = alpha;
}
@@ -1432,13 +1417,12 @@ static void outliner_draw_tree_element(
te->flag |= TE_ACTIVE; // for lookup in display hierarchies
}
+ if ((soops->outlinevis == SO_COLLECTIONS) && (tselem->type == TSE_SCENE_COLLECTION) && (te->parent == NULL)) {
+ /* Master collection can't expand/collapse. */
+ }
+ else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
/* open/close icon, only when sublevels, except for scene */
- if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
- int icon_x;
- if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE))
- icon_x = startx;
- else
- icon_x = startx + 5 * ufac;
+ int icon_x = startx;
// icons a bit higher
if (TSELEM_OPEN(tselem, soops))
@@ -1474,6 +1458,11 @@ static void outliner_draw_tree_element(
}
offsx += UI_UNIT_X + 2 * ufac;
}
+ else if (tselem->type == 0 && ID_IS_STATIC_OVERRIDE(tselem->id)) {
+ UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE,
+ alpha_fac);
+ offsx += UI_UNIT_X + 2 * ufac;
+ }
glDisable(GL_BLEND);
/* name */
@@ -1612,7 +1601,7 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo
const unsigned char col[4], bool draw_grayed_out,
int *starty)
{
- TreeElement *te;
+ TreeElement *te, *te_vertical_line_last = NULL;
TreeStoreElem *tselem;
int y1, y2;
@@ -1622,10 +1611,10 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo
const unsigned char grayed_alpha = col[3] / 2;
- y1 = y2 = *starty; /* for vertical lines between objects */
+ /* For vertical lines between objects. */
+ y1 = *starty;
for (te = lb->first; te; te = te->next) {
bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL);
- y2 = *starty;
tselem = TREESTORE(te);
if (draw_childs_grayed_out) {
@@ -1635,10 +1624,17 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo
immUniformColor4ubv(col);
}
- /* horizontal line? */
- if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE))
+ /* Horizontal Line? */
+ if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) {
immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1);
-
+
+ /* Vertical Line? */
+ if (te->idcode == ID_OB) {
+ te_vertical_line_last = te;
+ y2 = *starty;
+ }
+ }
+
*starty -= UI_UNIT_Y;
if (TSELEM_OPEN(tselem, soops))
@@ -1653,12 +1649,10 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo
immUniformColor4ubv(col);
}
- /* vertical line */
- te = lb->last;
- if (te->parent || lb->first != lb->last) {
- tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB)
- immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2);
+ /* Vertical line. */
+ te = te_vertical_line_last;
+ if ((te != NULL) && (te->parent || lb->first != lb->last)) {
+ immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2);
}
}
@@ -1724,7 +1718,9 @@ static void outliner_draw_highlights_recursive(
int start_x, int *io_start_y)
{
const bool is_searching = SEARCHING_OUTLINER(soops) ||
- (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0);
+ (soops->outlinevis == SO_DATABLOCKS &&
+ (soops->filter & SO_FILTER_SEARCH) &&
+ soops->search_string[0] != 0);
for (TreeElement *te = lb->first; te; te = te->next) {
const TreeStoreElem *tselem = TREESTORE(te);
@@ -1790,7 +1786,7 @@ static void outliner_draw_tree(
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once
- if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
+ if (soops->outlinevis == SO_DATABLOCKS) {
/* struct marks */
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
outliner_draw_struct_marks(ar, soops, &soops->tree, &starty);
@@ -1814,7 +1810,7 @@ static void outliner_draw_tree(
// gray hierarchy lines
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
- startx = 6;
+ startx = UI_UNIT_X / 2 - 1.0f;
outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty);
// items themselves
@@ -1879,15 +1875,12 @@ static void outliner_draw_restrictcols(ARegion *ar)
immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
immBegin(GWN_PRIM_LINES, 6);
- /* view */
immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax);
immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin);
- /* render */
immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax);
immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin);
- /* render */
immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax);
immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin);
@@ -1911,12 +1904,12 @@ void draw_outliner(const bContext *C)
TreeElement *te_edit = NULL;
bool has_restrict_icons;
- outliner_build_tree(mainvar, scene, view_layer, soops); // always
+ outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
/* get extents of data */
outliner_height(soops, &soops->tree, &sizey);
- if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
+ if (soops->outlinevis == SO_DATABLOCKS) {
/* RNA has two columns:
* - column 1 is (max_width + OL_RNA_COL_SPACEX) or
* (OL_RNA_COL_X), whichever is wider...
@@ -1941,8 +1934,9 @@ void draw_outliner(const bContext *C)
/* constant offset for restriction columns */
// XXX this isn't that great yet...
- if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
+ if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) {
sizex += OL_TOGW * 3;
+ }
has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS);
}
@@ -1962,13 +1956,8 @@ void draw_outliner(const bContext *C)
outliner_back(ar);
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
outliner_draw_tree((bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit);
-
- if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
- /* draw rna buttons */
- outliner_draw_rnacols(ar, sizex_rna);
- outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree);
- }
- else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) {
+
+ if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) {
/* draw user toggle columns */
outliner_draw_restrictcols(ar);
outliner_draw_userbuts(block, ar, soops, &soops->tree);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 8cd76179f23..fc0e30c78ce 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -949,7 +949,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeEle
}
/* to retrieve coordinates with redrawing the entire tree */
-static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
+void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
{
TreeElement *te;
int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
@@ -2085,7 +2085,7 @@ static int outliner_parenting_poll(bContext *C)
SpaceOops *soops = CTX_wm_space_outliner(C);
if (soops) {
- return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
+ return ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS);
}
return false;
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index f69eb9af1bf..b06c9b85eb8 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -36,6 +36,7 @@
/* internal exports only */
+struct ARegion;
struct wmOperatorType;
struct TreeElement;
struct TreeStoreElem;
@@ -47,6 +48,7 @@ struct ID;
struct Object;
struct bPoseChannel;
struct EditBone;
+struct wmEvent;
struct wmKeyConfig;
@@ -69,8 +71,11 @@ typedef enum TreeTraversalAction {
* Callback type for reinserting elements at a different position, used to allow user customizable element order.
*/
typedef void (*TreeElementReinsertFunc)(struct Main *bmain,
+ struct SpaceOops *soops,
struct TreeElement *insert_element,
- struct TreeElement *insert_handle, TreeElementInsertType action);
+ struct TreeElement *insert_handle,
+ TreeElementInsertType action,
+ const struct wmEvent *event);
/**
* Executed on (almost) each mouse move while dragging. It's supposed to give info
* if reinserting insert_element before/after/into insert_handle would be allowed.
@@ -102,6 +107,7 @@ typedef struct TreeElement {
TreeElementInsertType insert_type;
/* the element before/after/into which we may insert the dragged one (NULL to insert at top) */
struct TreeElement *insert_handle;
+ void *tooltip_draw_handle;
} *drag_data;
} TreeElement;
@@ -143,17 +149,19 @@ typedef enum {
/* size constants */
#define OL_Y_OFFSET 2
-#define OL_TOG_RESTRICT_ENABLEX (UI_UNIT_X * 3.0f)
-#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f)
-#define OL_TOG_RESTRICT_SELECTX UI_UNIT_X
+#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f)
+#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f)
#define OL_TOG_RESTRICT_RENDERX UI_UNIT_X
-#define OL_TOGW OL_TOG_RESTRICT_ENABLEX
+#define OL_TOGW OL_TOG_RESTRICT_VIEWX
#define OL_RNA_COLX (UI_UNIT_X * 15)
#define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f)
#define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f)
+/* The outliner display modes that support the filter system.
+ * Note: keep it synced with space_outliner.py */
+#define SUPPORT_FILTER_OUTLINER(soops_) ELEM((soops_)->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)
/* Outliner Searching --
*
@@ -171,18 +179,20 @@ typedef enum {
* - not searching into RNA items helps but isn't the complete solution
*/
-#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE)
+#define SEARCHING_OUTLINER(sov) ((sov->search_flags & SO_SEARCH_RECURSIVE) && (sov->filter & SO_FILTER_SEARCH))
/* is the currrent element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) ( (telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)) )
/* outliner_tree.c ----------------------------------------------- */
-void outliner_free_tree(ListBase *lb);
+void outliner_free_tree(ListBase *tree);
void outliner_cleanup_tree(struct SpaceOops *soops);
+void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree);
void outliner_remove_treestore_element(struct SpaceOops *soops, TreeStoreElem *tselem);
-void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOops *soops);
+void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer,
+ struct SpaceOops *soops, struct ARegion *ar);
/* outliner_draw.c ---------------------------------------------- */
@@ -203,6 +213,10 @@ int outliner_item_do_activate_from_cursor(
struct bContext *C, const int mval[2],
bool extend, bool recursive);
+void outliner_item_select(
+ struct SpaceOops *soops, const struct TreeElement *te,
+ const bool extend, const bool toggle);
+
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(
struct bContext *C, struct ReportList *, struct Scene *scene,
@@ -260,6 +274,8 @@ void id_remap_cb(
TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
+void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops);
+
/* ...................................................... */
void OUTLINER_OT_highlight_update(struct wmOperatorType *ot);
@@ -328,11 +344,11 @@ void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot);
void OUTLINER_OT_collection_link(struct wmOperatorType *ot);
void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot);
void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_override_new(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot);
+
+void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_delete_selected(struct wmOperatorType *ot);
/* outliner_utils.c ---------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 856dd022c14..52f27b9708e 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -33,9 +33,13 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_main.h"
+#include "GPU_immediate.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -48,6 +52,11 @@
#include "outliner_intern.h"
+typedef struct OutlinerDragDropTooltip {
+ TreeElement *te;
+ void *handle;
+} OutlinerDragDropTooltip;
+
enum {
OUTLINER_ITEM_DRAG_CANCEL,
OUTLINER_ITEM_DRAG_CONFIRM,
@@ -58,7 +67,7 @@ static int outliner_item_drag_drop_poll(bContext *C)
SpaceOops *soops = CTX_wm_space_outliner(C);
return ED_operator_outliner_active(C) &&
/* Only collection display modes supported for now. Others need more design work */
- ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS, SO_GROUPS);
+ ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS);
}
static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
@@ -69,9 +78,15 @@ static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *a
return outliner_find_item_at_y(soops, &soops->tree, my);
}
-static void outliner_item_drag_end(TreeElement *dragged_te)
+static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data)
{
- MEM_SAFE_FREE(dragged_te->drag_data);
+ MEM_SAFE_FREE(data->te->drag_data);
+
+ if (data->handle) {
+ WM_draw_cb_exit(win, data->handle);
+ }
+
+ MEM_SAFE_FREE(data);
}
static void outliner_item_drag_get_insert_data(
@@ -164,8 +179,35 @@ static void outliner_item_drag_handle(
te_dragged->drag_data->insert_handle = te_insert_handle;
}
-static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te)
+/**
+ * Returns true if it is a collection and empty.
+ */
+static bool is_empty_collection(TreeElement *te)
+{
+ if (!ELEM(TREESTORE(te)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) {
+ return false;
+ }
+
+ SceneCollection *scene_collection;
+ if (TREESTORE(te)->type == TSE_SCENE_COLLECTION) {
+ scene_collection = (SceneCollection *)te->directdata;
+ }
+ else {
+ BLI_assert(TREESTORE(te)->type == TSE_LAYER_COLLECTION);
+ scene_collection = ((LayerCollection *)te->directdata)->scene_collection;
+ }
+
+ return BLI_listbase_is_empty(&scene_collection->objects) &&
+ BLI_listbase_is_empty(&scene_collection->scene_collections);
+}
+
+static bool outliner_item_drag_drop_apply(
+ Main *bmain,
+ SpaceOops *soops,
+ OutlinerDragDropTooltip *data,
+ const wmEvent *event)
{
+ TreeElement *dragged_te = data->te;
TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
@@ -178,7 +220,16 @@ static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te)
/* call of assert above should not have changed insert_handle and insert_type at this point */
BLI_assert(dragged_te->drag_data->insert_handle == insert_handle &&
dragged_te->drag_data->insert_type == insert_type);
- dragged_te->reinsert(bmain, dragged_te, insert_handle, insert_type);
+
+ /* If the collection was just created and you moved objects/collections inside it,
+ * it is strange to have it closed and we not see the newly dragged elements. */
+ const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle);
+
+ dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type, event);
+
+ if (should_open_collection && !is_empty_collection(insert_handle)) {
+ TREESTORE(insert_handle)->flag &= ~TSE_CLOSED;
+ }
return true;
}
@@ -190,7 +241,8 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
Main *bmain = CTX_data_main(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
- TreeElement *te_dragged = op->customdata;
+ OutlinerDragDropTooltip *data = op->customdata;
+ TreeElement *te_dragged = data->te;
int retval = OPERATOR_RUNNING_MODAL;
bool redraw = false;
bool skip_rebuild = true;
@@ -198,7 +250,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
switch (event->type) {
case EVT_MODAL_MAP:
if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
- if (outliner_item_drag_drop_apply(bmain, te_dragged)) {
+ if (outliner_item_drag_drop_apply(bmain, soops, data, event)) {
skip_rebuild = false;
}
retval = OPERATOR_FINISHED;
@@ -210,7 +262,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
BLI_assert(0);
}
WM_event_add_mousemove(C); /* update highlight */
- outliner_item_drag_end(te_dragged);
+ outliner_item_drag_end(CTX_wm_window(C), data);
redraw = true;
break;
case MOUSEMOVE:
@@ -229,6 +281,93 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
return retval;
}
+/**
+ * Check if the given TreeElement is a collection
+ *
+ * This test is mainly used to see if next/prev TreeElement is a collection.
+ * It will fail when there is no next/prev TreeElement, or when the
+ * element is an Override or something else in the future.
+ */
+static bool tree_element_is_collection_get(const TreeElement *te) {
+ if (te == NULL) {
+ return false;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION);
+}
+
+static const char *outliner_drag_drop_tooltip_get(
+ const TreeElement *te_float)
+{
+ const char *name = NULL;
+
+ const TreeElement *te_insert = te_float->drag_data->insert_handle;
+ if (tree_element_is_collection_get(te_float)) {
+ if (te_insert == NULL) {
+ name = TIP_("Move collection");
+ }
+ else {
+ switch (te_float->drag_data->insert_type) {
+ case TE_INSERT_BEFORE:
+ if (tree_element_is_collection_get(te_insert->prev)) {
+ name = TIP_("Move between collections");
+ }
+ else {
+ name = TIP_("Move before collection");
+ }
+ break;
+ case TE_INSERT_AFTER:
+ if (tree_element_is_collection_get(te_insert->next)) {
+ name = TIP_("Move between collections");
+ }
+ else {
+ name = TIP_("Move after collection");
+ }
+ break;
+ case TE_INSERT_INTO:
+ name = TIP_("Move inside collection");
+ break;
+ }
+ }
+ }
+ else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) {
+ name = TIP_("Move to collection (Ctrl to add)");
+ }
+
+ return name;
+}
+
+static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata)
+{
+ OutlinerDragDropTooltip *data = vdata;
+ const char *tooltip;
+
+ int cursorx, cursory;
+ int x, y;
+
+ tooltip = outliner_drag_drop_tooltip_get(data->te);
+ if (tooltip == NULL) {
+ return;
+ }
+
+ cursorx = win->eventstate->x;
+ cursory = win->eventstate->y;
+
+ x = cursorx + U.widget_unit;
+ y = cursory - U.widget_unit;
+
+ /* Drawing. */
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+
+ const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
+
+ glEnable(GL_BLEND);
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg);
+ glDisable(GL_BLEND);
+}
+
static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
@@ -239,7 +378,10 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
- op->customdata = te_dragged;
+ OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__);
+ data->te = te_dragged;
+
+ op->customdata = data;
te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__);
/* by default we don't change the item position */
te_dragged->drag_data->insert_handle = te_dragged;
@@ -251,6 +393,8 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE
WM_event_add_modal_handler(C, op);
+ data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data);
+
return OPERATOR_RUNNING_MODAL;
}
@@ -330,11 +474,11 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_collection_link);
WM_operatortype_append(OUTLINER_OT_collection_unlink);
WM_operatortype_append(OUTLINER_OT_collection_new);
- WM_operatortype_append(OUTLINER_OT_collection_override_new);
+
+ WM_operatortype_append(OUTLINER_OT_collection_nested_new);
+ WM_operatortype_append(OUTLINER_OT_collection_delete_selected);
WM_operatortype_append(OUTLINER_OT_collection_objects_add);
WM_operatortype_append(OUTLINER_OT_collection_objects_remove);
- WM_operatortype_append(OUTLINER_OT_collection_objects_select);
- WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
}
static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf)
@@ -432,6 +576,9 @@ void outliner_keymap(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_nested_new", CKEY, KM_PRESS, 0, 0);
+ WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete_selected", XKEY, KM_PRESS, 0, 0);
+
outliner_item_drag_drop_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 08b5f337936..b9222e62bb0 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -97,8 +97,8 @@ static eOLDrawState tree_element_active_renderlayer(
/**
* Select object tree:
- * CTRL+LMB: Select/Deselect object and all cildren
- * CTRL+SHIFT+LMB: Add/Remove object and all children
+ * CTRL+LMB: Select/Deselect object and all children.
+ * CTRL+SHIFT+LMB: Add/Remove object and all children.
*/
static void do_outliner_object_select_recursive(ViewLayer *view_layer, Object *ob_parent, bool select)
{
@@ -185,7 +185,7 @@ static eOLDrawState tree_element_set_active_object(
if (recursive) {
/* Recursive select/deselect for Object hierarchies */
- do_outliner_object_select_recursive(view_layer, ob, (ob->flag & SELECT) != 0);
+ do_outliner_object_select_recursive(view_layer, ob, (base->flag & BASE_SELECTED) != 0);
}
if (set != OL_SETSEL_NONE) {
@@ -973,7 +973,7 @@ static void do_outliner_item_activate_tree_element(
* \param extend: Don't deselect other items, only modify \a te.
* \param toggle: Select \a te when not selected, deselect when selected.
*/
-static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle)
+void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle)
{
TreeStoreElem *tselem = TREESTORE(te);
const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
@@ -1005,7 +1005,7 @@ static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_
static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x)
{
- return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) &&
+ return ((soops->outlinevis != SO_DATABLOCKS) &&
!(soops->flag & SO_HIDE_RESTRICTCOLS) &&
(view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX));
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 99fd539293f..9f0165d1272 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -57,6 +57,7 @@
#include "BKE_group.h"
#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
@@ -454,6 +455,19 @@ static void id_local_cb(
}
}
+static void id_static_override_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ Main *bmain = CTX_data_main(C);
+ ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
+ }
+ }
+}
+
static void id_fake_user_set_cb(
bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
@@ -1002,9 +1016,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_REMAP, "REMAP", 0, "Remap Users",
"Make all users of selected data-blocks to use instead a new chosen one"},
- {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
- {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
- {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1117,6 +1128,7 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
typedef enum eOutliner_PropGroupOps {
OL_GROUPOP_UNLINK = 1,
OL_GROUPOP_LOCAL,
+ OL_GROUPOP_STATIC_OVERRIDE,
OL_GROUPOP_LINK,
OL_GROUPOP_DELETE,
OL_GROUPOP_REMAP,
@@ -1130,6 +1142,8 @@ typedef enum eOutliner_PropGroupOps {
static const EnumPropertyItem prop_group_op_types[] = {
{OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
{OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
+ {OL_GROUPOP_STATIC_OVERRIDE, "STATIC_OVERRIDE",
+ 0, "Add Static Override", "Add a local static override of that group"},
{OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
{OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""},
{OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
@@ -1161,6 +1175,9 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
case OL_GROUPOP_LOCAL:
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
break;
+ case OL_GROUPOP_STATIC_OVERRIDE:
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL);
+ break;
case OL_GROUPOP_LINK:
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
break;
@@ -1213,6 +1230,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
+ OUTLINER_IDOP_STATIC_OVERRIDE,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
OUTLINER_IDOP_REMAP,
@@ -1228,6 +1246,8 @@ typedef enum eOutlinerIdOpTypes {
static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
+ {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE",
+ 0, "Add Static Override", "Add a local static override of this data-block"},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
{OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
@@ -1297,6 +1317,13 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Localized Data");
break;
}
+ case OUTLINER_IDOP_STATIC_OVERRIDE:
+ {
+ /* make local */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL);
+ ED_undo_push(C, "Overrided Data");
+ break;
+ }
case OUTLINER_IDOP_SINGLE:
{
/* make single user */
@@ -1841,7 +1868,7 @@ static const EnumPropertyItem *outliner_collection_operation_type_itemf(
switch (soops->outlinevis) {
case SO_GROUPS:
return prop_collection_op_group_internal_types;
- case SO_ACT_LAYER:
+ case SO_VIEW_LAYER:
return prop_collection_op_none_types;
}
return NULL;
@@ -2021,7 +2048,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
}
}
else if (objectlevel) {
- WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN);
}
else if (idlevel) {
if (idlevel == -1 || datalevel) {
@@ -2066,6 +2093,9 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
else if (datalevel == TSE_LAYER_COLLECTION) {
WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
+ else if (datalevel == TSE_SCENE_COLLECTION) {
+ WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN);
+ }
else {
WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index a9c9ab74970..06b3319935d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -71,6 +71,7 @@
#include "BKE_idcode.h"
#include "BKE_outliner_treehash.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
@@ -81,6 +82,8 @@
#include "RNA_access.h"
+#include "UI_interface.h"
+
#include "outliner_intern.h"
#ifdef WIN32
@@ -89,7 +92,11 @@
/* prototypes */
static void outliner_add_layer_collections_recursive(
- SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten);
+ SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten,
+ const bool show_objects);
+static void outliner_add_view_layer(
+ SpaceOops *soops, ListBase *tree, TreeElement *parent,
+ Scene *scene, ViewLayer *layer, const bool show_objects);
static void outliner_make_hierarchy(ListBase *lb);
/* ********************************************************* */
@@ -189,16 +196,11 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
/* ********************************************************* */
/* Tree Management */
-void outliner_free_tree(ListBase *lb)
+void outliner_free_tree(ListBase *tree)
{
- while (lb->first) {
- TreeElement *te = lb->first;
-
- outliner_free_tree(&te->subtree);
- BLI_remlink(lb, te);
-
- if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
- MEM_freeN(te);
+ for (TreeElement *element = tree->first, *element_next; element; element = element_next) {
+ element_next = element->next;
+ outliner_free_tree_element(element, tree);
}
}
@@ -208,6 +210,25 @@ void outliner_cleanup_tree(SpaceOops *soops)
outliner_storage_cleanup(soops);
}
+/**
+ * Free \a element and its sub-tree and remove its link in \a parent_subtree.
+ *
+ * \note Does not remove the TreeStoreElem of \a element!
+ * \param parent_subtree Subtree of the parent element, so the list containing \a element.
+ */
+void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
+{
+ BLI_assert(BLI_findindex(parent_subtree, element) > -1);
+ BLI_remlink(parent_subtree, element);
+
+ outliner_free_tree(&element->subtree);
+
+ if (element->flag & TE_FREE_NAME) {
+ MEM_freeN((void *)element->name);
+ }
+ MEM_freeN(element);
+}
+
/* ********************************************************* */
@@ -365,12 +386,21 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
int a;
- tenla->name = IFACE_("RenderLayers");
+ tenla->name = IFACE_("View Layers");
for (a = 0, view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next, a++) {
TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
tenlay->name = view_layer->name;
tenlay->directdata = &view_layer->flag;
- outliner_add_passes(soops, tenlay, &sce->id, view_layer);
+
+ TreeElement *te_view_layers;
+ te_view_layers = outliner_add_element(soops, &tenlay->subtree, sce, tenlay, TSE_LAYER_COLLECTION_BASE, 0);
+ te_view_layers->name = IFACE_("Collections");
+ outliner_add_view_layer(soops, &te_view_layers->subtree, te_view_layers, sce, view_layer, false);
+
+ TreeElement *te_passes;
+ te_passes = outliner_add_element(soops, &tenlay->subtree, sce, tenlay, TSE_LAYER_COLLECTION_BASE, 0);
+ te_passes->name = IFACE_("Passes");
+ outliner_add_passes(soops, te_passes, &sce->id, view_layer);
}
// TODO: move this to the front?
@@ -379,20 +409,45 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
- outliner_add_element(soops, lb, sce->world, te, 0, 0);
-
#ifdef WITH_FREESTYLE
if (STREQ(sce->view_render->engine_id, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS))
outliner_add_line_styles(soops, lb, sce, te);
#endif
}
+struct ObjectsSelectedData {
+ ListBase objects_selected_array;
+};
+
+static TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
+{
+ struct ObjectsSelectedData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
+ return TRAVERSE_CONTINUE;
+ }
+
+ if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te));
+
+ return TRAVERSE_CONTINUE;
+}
+
+/**
+ * Move objects from a collection to another.
+ * We ignore the original object being inserted, we used it for polling only.
+ * Instead we move all the selected objects around.
+ */
static void outliner_object_reorder(
- Main *UNUSED(bmain),
- TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
+ Main *bmain, SpaceOops *soops,
+ TreeElement *insert_element,
+ TreeElement *insert_handle, TreeElementInsertType action,
+ const wmEvent *event)
{
- TreeStoreElem *tselem_insert = TREESTORE(insert_element);
- Object *ob = (Object *)tselem_insert->id;
SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle);
SceneCollection *sc_ob_parent = NULL;
ID *id = insert_handle->store_elem->id;
@@ -400,19 +455,49 @@ static void outliner_object_reorder(
BLI_assert(action == TE_INSERT_INTO);
UNUSED_VARS_NDEBUG(action);
- /* find parent scene-collection of object */
- if (insert_element->parent) {
- for (TreeElement *te_ob_parent = insert_element->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) {
- if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) {
- sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent);
- break;
+ struct ObjectsSelectedData data = {
+ .objects_selected_array = {NULL, NULL},
+ };
+
+ const bool is_append = event->ctrl;
+
+ /* Make sure we include the originally inserted element as well. */
+ TREESTORE(insert_element)->flag |= TSE_SELECTED;
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
+ BLI_LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
+ TreeElement *ten_selected = (TreeElement *)link->data;
+ Object *ob = (Object *)TREESTORE(ten_selected)->id;
+
+ if (is_append) {
+ BKE_collection_object_add(id, sc, ob);
+ continue;
+ }
+
+ /* Find parent scene-collection of object. */
+ if (ten_selected->parent) {
+ for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) {
+ if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) {
+ sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent);
+ break;
+ }
}
}
+ else {
+ sc_ob_parent = BKE_collection_master(id);
+ }
+
+ BKE_collection_object_move(id, sc, sc_ob_parent, ob);
}
- else {
- sc_ob_parent = BKE_collection_master(id);
- }
- BKE_collection_object_move(id, sc, sc_ob_parent, ob);
+
+ BLI_freelistN(&data.objects_selected_array);
+
+ DEG_relations_tag_update(bmain);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
}
static bool outliner_object_reorder_poll(
@@ -1202,9 +1287,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->flag |= TE_LAZY_CLOSED;
}
- if ((type != TSE_LAYER_COLLECTION) && GS(id->name) == ID_GR) {
+ if ((type != TSE_LAYER_COLLECTION) && (te->idcode == ID_GR)) {
Group *group = (Group *)id;
- outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL);
+ outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL, true);
}
return te;
@@ -1358,7 +1443,9 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
static void outliner_layer_collections_reorder(
Main *bmain,
- TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
+ SpaceOops *UNUSED(soops),
+ TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action,
+ const wmEvent *UNUSED(event))
{
LayerCollection *lc_insert = insert_element->directdata;
LayerCollection *lc_handle = insert_handle->directdata;
@@ -1393,7 +1480,8 @@ static bool outliner_layer_collections_reorder_poll(
}
static void outliner_add_layer_collections_recursive(
- SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten)
+ SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten,
+ const bool show_objects)
{
for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) {
TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0);
@@ -1403,23 +1491,29 @@ static void outliner_add_layer_collections_recursive(
ten->reinsert = outliner_layer_collections_reorder;
ten->reinsert_poll = outliner_layer_collections_reorder_poll;
- outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten);
- for (LinkData *link = collection->object_bases.first; link; link = link->next) {
- Base *base = (Base *)link->data;
- TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0);
- te_object->directdata = base;
+ outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten, show_objects);
+ if (show_objects) {
+ for (LinkData *link = collection->object_bases.first; link; link = link->next) {
+ Base *base = (Base *)link->data;
+ TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0);
+ te_object->directdata = base;
+ }
}
outliner_make_hierarchy(&ten->subtree);
}
}
-static void outliner_add_collections_act_layer(SpaceOops *soops, Scene *scene, ViewLayer *layer)
+
+static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent,
+ Scene *scene, ViewLayer *layer, const bool show_objects)
{
- outliner_add_layer_collections_recursive(soops, &soops->tree, &scene->id, &layer->layer_collections, NULL);
+ outliner_add_layer_collections_recursive(soops, tree, &scene->id, &layer->layer_collections, parent, show_objects);
}
static void outliner_scene_collections_reorder(
Main *bmain,
- TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
+ SpaceOops *UNUSED(soops),
+ TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action,
+ const wmEvent *UNUSED(event))
{
SceneCollection *sc_insert = insert_element->directdata;
SceneCollection *sc_handle = insert_handle->directdata;
@@ -1474,35 +1568,46 @@ static bool outliner_scene_collections_reorder_poll(
return true;
}
-static void outliner_add_scene_collection_objects(
+BLI_INLINE void outliner_add_scene_collection_init(TreeElement *te, SceneCollection *collection)
+{
+ te->name = collection->name;
+ te->directdata = collection;
+ te->reinsert = outliner_scene_collections_reorder;
+ te->reinsert_poll = outliner_scene_collections_reorder_poll;
+}
+
+BLI_INLINE void outliner_add_scene_collection_objects(
SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent)
{
for (LinkData *link = collection->objects.first; link; link = link->next) {
outliner_add_element(soops, tree, link->data, parent, 0, 0);
}
- outliner_make_hierarchy(tree);
}
-static void outliner_add_scene_collections_recursive(
- SpaceOops *soops, ListBase *tree, ListBase *scene_collections, TreeElement *parent_ten)
+static TreeElement *outliner_add_scene_collection_recursive(
+ SpaceOops *soops, ListBase *tree, ID *id, SceneCollection *scene_collection, TreeElement *parent_ten)
{
- for (SceneCollection *collection = scene_collections->first; collection; collection = collection->next) {
- TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_SCENE_COLLECTION, 0);
+ TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_SCENE_COLLECTION, 0);
+ outliner_add_scene_collection_init(ten, scene_collection);
+ outliner_add_scene_collection_objects(soops, &ten->subtree, scene_collection, ten);
- ten->name = collection->name;
- ten->directdata = collection;
- ten->reinsert = outliner_scene_collections_reorder;
- ten->reinsert_poll = outliner_scene_collections_reorder_poll;
-
- outliner_add_scene_collections_recursive(soops, &ten->subtree, &collection->scene_collections, ten);
- outliner_add_scene_collection_objects(soops, &ten->subtree, collection, ten);
+ for (SceneCollection *scene_collection_nested = scene_collection->scene_collections.first;
+ scene_collection_nested != NULL;
+ scene_collection_nested = scene_collection_nested->next)
+ {
+ outliner_add_scene_collection_recursive(soops, &ten->subtree, id, scene_collection_nested, ten);
}
+
+ outliner_make_hierarchy(&ten->subtree);
+ return ten;
}
-static void outliner_add_collections_master(SpaceOops *soops, Scene *scene)
+
+static void outliner_add_collections(SpaceOops *soops, Scene *scene)
{
- SceneCollection *master = BKE_collection_master(&scene->id);
- outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL);
- outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL);
+ SceneCollection *master_collection = BKE_collection_master(&scene->id);
+ TreeElement *ten = outliner_add_scene_collection_recursive(soops, &soops->tree, &scene->id, master_collection, NULL);
+ /* Master Collection should always be expanded. */
+ TREESTORE(ten)->flag &= ~TSE_CLOSED;
}
/* ======================================================= */
@@ -1676,6 +1781,305 @@ static void outliner_sort(ListBase *lb)
/* Filtering ----------------------------------------------- */
+typedef struct OutlinerTreeElementFocus {
+ TreeStoreElem *tselem;
+ int ys;
+} OutlinerTreeElementFocus;
+
+/**
+ * Bring the outliner scrolling back to where it was in relation to the original focus element
+ * Caller is expected to handle redrawing of ARegion.
+ */
+static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
+{
+ View2D *v2d = &ar->v2d;
+ int ytop;
+
+ if (focus->tselem != NULL) {
+ outliner_set_coordinates(ar, soops);
+
+ TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem);
+
+ if (te_new != NULL) {
+ int ys_new, ys_old;
+
+ ys_new = te_new->ys;
+ ys_old = focus->ys;
+
+ ytop = v2d->cur.ymax + (ys_new - ys_old) -1;
+ if (ytop > 0) ytop = 0;
+
+ v2d->cur.ymax = (float)ytop;
+ v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
+ }
+ else {
+ return;
+ }
+
+ soops->storeflag |= SO_TREESTORE_REDRAW;
+ }
+}
+
+static bool test_collection_callback(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+ return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION);
+}
+
+static bool test_object_callback(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+ return ((tselem->type == 0) && (te->idcode == ID_OB));
+}
+
+/**
+ * See if TreeElement or any of its children pass the callback_test.
+ */
+static TreeElement *outliner_find_first_desired_element_at_y_recursive(
+ const SpaceOops *soops,
+ TreeElement *te,
+ const float limit,
+ bool (*callback_test)(TreeElement *))
+{
+ if (callback_test(te)) {
+ return te;
+ }
+
+ if (TSELEM_OPEN(te->store_elem, soops)) {
+ TreeElement *te_iter, *te_sub;
+ for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
+ te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test);
+ if (te_sub != NULL) {
+ return te_sub;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Find the first element that passes a test starting from a reference vertical coordinate
+ *
+ * If the element that is in the position is not what we are looking for, keep looking for its
+ * children, siblings, and eventually, aunts, cousins, disntant families, ...
+ *
+ * Basically we keep going up and down the outliner tree from that point forward, until we find
+ * what we are looking for. If we are past the visible range and we can't find a valid element
+ * we return NULL.
+ */
+static TreeElement *outliner_find_first_desired_element_at_y(
+ const SpaceOops *soops,
+ const float view_co,
+ const float view_co_limit)
+{
+ TreeElement *te, *te_sub;
+ te = outliner_find_item_at_y(soops, &soops->tree, view_co);
+
+ bool (*callback_test)(TreeElement *);
+ if (soops->filter & SO_FILTER_NO_COLLECTION) {
+ callback_test = test_object_callback;
+ }
+ else {
+ callback_test = test_collection_callback;
+ }
+
+ while (te != NULL) {
+ te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test);
+ if (te_sub != NULL) {
+ /* Skip the element if it was not visible to start with. */
+ if (te->ys + UI_UNIT_Y > view_co_limit) {
+ return te_sub;
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ if (te->next) {
+ te = te->next;
+ continue;
+ }
+
+ if (te->parent == NULL) {
+ break;
+ }
+
+ while (te->parent) {
+ if (te->parent->next) {
+ te = te->parent->next;
+ break;
+ }
+ te = te->parent;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Store information of current outliner scrolling status to be restored later
+ *
+ * Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus
+ * struct to retrieve this element later to make sure it is in the same original position as before filtering
+ */
+static void outliner_store_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
+{
+ TreeElement *te;
+ float limit = ar->v2d.cur.ymin;
+
+ outliner_set_coordinates(ar, soops);
+
+ te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit);
+
+ if (te != NULL) {
+ focus->tselem = TREESTORE(te);
+ focus->ys = te->ys;
+ }
+ else {
+ focus->tselem = NULL;
+ }
+}
+
+static int outliner_exclude_filter_get(SpaceOops *soops)
+{
+ int exclude_filter = soops->filter & ~(SO_FILTER_OB_STATE_VISIBLE |
+ SO_FILTER_OB_STATE_SELECTED |
+ SO_FILTER_OB_STATE_ACTIVE);
+
+ if (soops->filter & SO_FILTER_SEARCH) {
+ if (soops->search_string[0] == 0) {
+ exclude_filter &= ~SO_FILTER_SEARCH;
+ }
+ }
+
+ /* Let's have this for the collection options at first. */
+ if (!SUPPORT_FILTER_OUTLINER(soops)) {
+ return (exclude_filter & SO_FILTER_SEARCH);
+ }
+
+ if ((exclude_filter & SO_FILTER_NO_OB_ALL) == 0) {
+ exclude_filter &= ~SO_FILTER_OB_TYPE;
+ }
+
+ if (exclude_filter & SO_FILTER_OB_STATE) {
+ switch (soops->filter_state) {
+ case SO_FILTER_OB_VISIBLE:
+ exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
+ break;
+ case SO_FILTER_OB_SELECTED:
+ exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
+ break;
+ case SO_FILTER_OB_ACTIVE:
+ exclude_filter |= SO_FILTER_OB_STATE_ACTIVE;
+ break;
+ }
+ }
+
+ if ((exclude_filter & SO_FILTER_ANY) == 0) {
+ exclude_filter &= ~(SO_FILTER_OB_STATE);
+ }
+
+ return exclude_filter;
+}
+
+static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter)
+{
+ if ((exclude_filter & SO_FILTER_ENABLE) == 0) {
+ return true;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((exclude_filter & SO_FILTER_NO_OBJECT)) {
+ return false;
+ }
+
+ Object *ob = (Object *)tselem->id;
+ Base *base = (Base *)te->directdata;
+ BLI_assert((base == NULL) || (base->object == ob));
+
+ if (exclude_filter & SO_FILTER_OB_TYPE) {
+ switch (ob->type) {
+ case OB_MESH:
+ if (exclude_filter & SO_FILTER_NO_OB_MESH) {
+ return false;
+ }
+ break;
+ case OB_ARMATURE:
+ if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) {
+ return false;
+ }
+ break;
+ case OB_EMPTY:
+ if (exclude_filter & SO_FILTER_NO_OB_EMPTY) {
+ return false;
+ }
+ break;
+ case OB_LAMP:
+ if (exclude_filter & SO_FILTER_NO_OB_LAMP) {
+ return false;
+ }
+ break;
+ case OB_CAMERA:
+ if (exclude_filter & SO_FILTER_NO_OB_CAMERA) {
+ return false;
+ }
+ break;
+ default:
+ if (exclude_filter & SO_FILTER_NO_OB_OTHERS) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (exclude_filter & SO_FILTER_OB_STATE) {
+ if (base == NULL) {
+ base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (base == NULL) {
+ return false;
+ }
+ }
+
+ if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
+ if ((base->flag & BASE_VISIBLED) == 0) {
+ return false;
+ }
+ }
+ else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
+ if ((base->flag & BASE_SELECTED) == 0) {
+ return false;
+ }
+ }
+ else {
+ BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
+ if (base != BASACT(view_layer)) {
+ return false;
+ }
+ }
+ }
+
+ if ((te->parent != NULL) &&
+ (TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB))
+ {
+ if (exclude_filter & SO_FILTER_NO_CHILDREN) {
+ return false;
+ }
+ }
+ }
+ else if (te->parent != NULL &&
+ TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB)
+ {
+ if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
{
int fn_flag = 0;
@@ -1686,31 +2090,25 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag
return fnmatch(name, te->name, fn_flag) == 0;
}
-static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
+static int outliner_filter_subtree(
+ SpaceOops *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter)
{
- TreeElement *te, *ten;
+ TreeElement *te, *te_next;
TreeStoreElem *tselem;
- char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
- char *search_string;
- /* although we don't have any search string, we return true
- * since the entire tree is ok then...
- */
- if (soops->search_string[0] == 0)
- return 1;
+ for (te = lb->first; te; te = te_next) {
+ te_next = te->next;
- if (soops->search_flags & SO_FIND_COMPLETE) {
- search_string = soops->search_string;
- }
- else {
- /* Implicitly add heading/trailing wildcards if needed. */
- BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
- search_string = search_buff;
- }
+ if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
+ outliner_free_tree_element(te, lb);
+ continue;
+ }
+ else if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
+ /* Filter subtree too. */
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
+ continue;
+ }
- for (te = lb->first; te; te = ten) {
- ten = te->next;
-
if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
/* item isn't something we're looking for, but...
* - if the subtree is expanded, check if there are any matches that can be easily found
@@ -1719,39 +2117,60 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
* so these can be safely ignored (i.e. the subtree can get freed)
*/
tselem = TREESTORE(te);
-
+
/* flag as not a found item */
tselem->flag &= ~TSE_SEARCHMATCH;
- if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) {
- outliner_free_tree(&te->subtree);
- BLI_remlink(lb, te);
-
- if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
- MEM_freeN(te);
+ if ((!TSELEM_OPEN(tselem, soops)) ||
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0)
+ {
+ outliner_free_tree_element(te, lb);
}
}
else {
tselem = TREESTORE(te);
-
+
/* flag as a found item - we can then highlight it */
tselem->flag |= TSE_SEARCHMATCH;
-
+
/* filter subtree too */
- outliner_filter_tree(soops, &te->subtree);
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
}
}
-
+
/* if there are still items in the list, that means that there were still some matches */
return (BLI_listbase_is_empty(lb) == false);
}
+static void outliner_filter_tree(SpaceOops *soops, ViewLayer *view_layer)
+{
+ char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
+ char *search_string;
+
+ const int exclude_filter = outliner_exclude_filter_get(soops);
+
+ if (exclude_filter == 0) {
+ return;
+ }
+
+ if (soops->search_flags & SO_FIND_COMPLETE) {
+ search_string = soops->search_string;
+ }
+ else {
+ /* Implicitly add heading/trailing wildcards if needed. */
+ BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
+ search_string = search_buff;
+ }
+
+ outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter);
+}
+
/* ======================================================= */
/* Main Tree Building API */
/* Main entry point for building the tree data-structure that the outliner represents */
// TODO: split each mode into its own function?
-void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops)
+void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, ARegion *ar)
{
TreeElement *te = NULL, *ten;
TreeStoreElem *tselem;
@@ -1773,6 +2192,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
return;
+ OutlinerTreeElementFocus focus;
+ outliner_store_scrolling_position(soops, ar, &focus);
+
outliner_free_tree(&soops->tree);
outliner_storage_cleanup(soops);
@@ -1826,51 +2248,19 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
lib->id.newid = NULL;
}
- else if (soops->outlinevis == SO_ALL_SCENES) {
+ else if (soops->outlinevis == SO_SCENES) {
Scene *sce;
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
tselem = TREESTORE(te);
- if (sce == scene && show_opened)
- tselem->flag &= ~TSE_CLOSED;
- FOREACH_SCENE_OBJECT(scene, ob)
- {
- outliner_add_element(soops, &te->subtree, ob, te, 0, 0);
+ if (sce == scene && show_opened) {
+ tselem->flag &= ~TSE_CLOSED;
}
- FOREACH_SCENE_OBJECT_END
outliner_make_hierarchy(&te->subtree);
-
- /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
- FOREACH_SCENE_OBJECT(scene, ob)
- {
- ob->id.newid = NULL;
- }
- FOREACH_SCENE_OBJECT_END
}
}
- else if (soops->outlinevis == SO_CUR_SCENE) {
-
- outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
-
- FOREACH_SCENE_OBJECT(scene, ob)
- {
- outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
- }
- FOREACH_SCENE_OBJECT_END
- outliner_make_hierarchy(&soops->tree);
- }
- else if (soops->outlinevis == SO_VISIBLE) {
- FOREACH_VISIBLE_BASE(view_layer, base)
- {
- ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
- ten->directdata = base;
-
- }
- FOREACH_VISIBLE_BASE_END
- outliner_make_hierarchy(&soops->tree);
- }
else if (soops->outlinevis == SO_GROUPS) {
Group *group;
for (group = mainvar->group.first; group; group = group->id.next) {
@@ -1878,28 +2268,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
outliner_make_hierarchy(&te->subtree);
}
}
- else if (soops->outlinevis == SO_SAME_TYPE) {
- Object *ob_active = OBACT(view_layer);
- if (ob_active) {
- FOREACH_SCENE_OBJECT(scene, ob)
- {
- if (ob->type == ob_active->type) {
- outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
- }
- }
- FOREACH_SCENE_OBJECT_END
- outliner_make_hierarchy(&soops->tree);
- }
- }
- else if (soops->outlinevis == SO_SELECTED) {
- FOREACH_SELECTED_BASE(view_layer, base)
- {
- ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
- ten->directdata = base;
- }
- FOREACH_SELECTED_BASE_END
- outliner_make_hierarchy(&soops->tree);
- }
else if (soops->outlinevis == SO_SEQUENCE) {
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -1936,36 +2304,47 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
tselem->flag &= ~TSE_CLOSED;
}
}
- else if (soops->outlinevis == SO_USERDEF) {
- PointerRNA userdefptr;
-
- RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr);
-
- ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
-
- if (show_opened) {
- tselem = TREESTORE(ten);
- tselem->flag &= ~TSE_CLOSED;
- }
- }
else if (soops->outlinevis == SO_ID_ORPHANS) {
outliner_add_orphaned_datablocks(mainvar, soops);
}
- else if (soops->outlinevis == SO_ACT_LAYER) {
- outliner_add_collections_act_layer(soops, scene, view_layer);
+ else if (soops->outlinevis == SO_VIEW_LAYER) {
+ if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ te_object->directdata = base;
+ }
+ outliner_make_hierarchy(&soops->tree);
+ }
+ else {
+ outliner_add_view_layer(soops, &soops->tree, NULL, scene, view_layer, true);
+ }
}
else if (soops->outlinevis == SO_COLLECTIONS) {
- outliner_add_collections_master(soops, scene);
+ if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) {
+ FOREACH_SCENE_OBJECT(scene, ob)
+ {
+ outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
+ }
+ FOREACH_SCENE_OBJECT_END
+ outliner_make_hierarchy(&soops->tree);
+ }
+ else {
+ outliner_add_collections(soops, scene);
+ }
}
else {
- ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0);
- ten->directdata = BASACT(view_layer);
+ if (BASACT(view_layer)) {
+ ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0);
+ ten->directdata = BASACT(view_layer);
+ }
}
if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
outliner_sort(&soops->tree);
}
- outliner_filter_tree(soops, &soops->tree);
+
+ outliner_filter_tree(soops, view_layer);
+ outliner_restore_scrolling_position(soops, ar, &focus);
BKE_main_id_clear_newpoins(mainvar);
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 1bc1a227a03..1529e6143c3 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -48,6 +48,7 @@
#include "ED_screen.h"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_types.h"
#include "BIF_gl.h"
@@ -162,7 +163,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
- if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) {
+ if (!ELEM(soops->outlinevis, SO_SCENES, SO_GROUPS, SO_VIEW_LAYER, SO_COLLECTIONS)) {
return false;
}
@@ -423,6 +424,24 @@ static void outliner_main_region_listener(
}
+static void outliner_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ SpaceOops *soops = sa->spacedata.first;
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)) {
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+ }
+}
+
/* ************************ header outliner area region *********************** */
@@ -576,6 +595,7 @@ void ED_spacetype_outliner(void)
art->draw = outliner_main_region_draw;
art->free = outliner_main_region_free;
art->listener = outliner_main_region_listener;
+ art->message_subscribe = outliner_main_region_message_subscribe;
BLI_addhead(&st->regiontypes, art);
/* regions: header */
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 8f6eb064b0d..cb0c5bd3717 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -2190,23 +2190,24 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq;
MetaStack *ms;
- bool nothingSelected = true;
+ bool nothing_selected = true;
seq = BKE_sequencer_active_get(scene);
if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */
- nothingSelected = false;
+ nothing_selected = false;
}
else {
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
- nothingSelected = false;
+ nothing_selected = false;
break;
}
}
}
- if (nothingSelected)
+ if (nothing_selected) {
return OPERATOR_FINISHED;
+ }
/* for effects and modifiers, try to find a replacement input */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 80cb42c0b3d..c5d6edadb53 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -459,13 +459,15 @@ typedef struct MakeHistogramViewData {
} MakeHistogramViewData;
static void make_histogram_view_from_ibuf_byte_cb_ex(
- void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict tls)
{
MakeHistogramViewData *data = userdata;
const ImBuf *ibuf = data->ibuf;
const unsigned char *src = (unsigned char *)ibuf->rect;
- uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
+ uint32_t (*cur_bins)[HIS_STEPS] = tls->userdata_chunk;
for (int x = 0; x < ibuf->x; x++) {
const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
@@ -476,7 +478,8 @@ static void make_histogram_view_from_ibuf_byte_cb_ex(
}
}
-static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk)
+static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata,
+ void *__restrict userdata_chunk)
{
MakeHistogramViewData *data = userdata;
uint32_t (*bins)[HIS_STEPS] = data->bins;
@@ -501,9 +504,17 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
memset(bins, 0, sizeof(bins));
MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
- BLI_task_parallel_range_finalize(
- 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex,
- make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (ibuf->y >= 256);
+ settings.userdata_chunk = bins;
+ settings.userdata_chunk_size = sizeof(bins);
+ settings.func_finalize = make_histogram_view_from_ibuf_finalize;
+ BLI_task_parallel_range(
+ 0, ibuf->y,
+ &data,
+ make_histogram_view_from_ibuf_byte_cb_ex,
+ &settings);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -548,13 +559,15 @@ BLI_INLINE int get_bin_float(float f)
}
static void make_histogram_view_from_ibuf_float_cb_ex(
- void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+ void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict tls)
{
const MakeHistogramViewData *data = userdata;
const ImBuf *ibuf = data->ibuf;
const float *src = ibuf->rect_float;
- uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
+ uint32_t (*cur_bins)[HIS_STEPS] = tls->userdata_chunk;
for (int x = 0; x < ibuf->x; x++) {
const float *pixel = src + (y * ibuf->x + x) * 4;
@@ -576,9 +589,17 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
memset(bins, 0, sizeof(bins));
MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
- BLI_task_parallel_range_finalize(
- 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex,
- make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (ibuf->y >= 256);
+ settings.userdata_chunk = bins;
+ settings.userdata_chunk_size = sizeof(bins);
+ settings.func_finalize = make_histogram_view_from_ibuf_finalize;
+ BLI_task_parallel_range(
+ 0, ibuf->y,
+ &data,
+ make_histogram_view_from_ibuf_float_cb_ex,
+ &settings);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index fcb675abcf2..62fde49cade 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -596,7 +596,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
drawcache->total_lines = 0;
if (st->showlinenrs)
- st->linenrs_tot = (int)floor(log10((float)nlines)) + 1;
+ st->linenrs_tot = integer_digits_i(nlines);
while (line) {
if (drawcache->valid_head) { /* we're inside valid head lines */
@@ -630,7 +630,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
nlines = BLI_listbase_count(&txt->lines);
if (st->showlinenrs)
- st->linenrs_tot = (int)floor(log10((float)nlines)) + 1;
+ st->linenrs_tot = integer_digits_i(nlines);
}
drawcache->total_lines = nlines;
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index de8380aa8bb..d148ef3c6fe 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -64,6 +64,8 @@ set(SRC
view3d_manipulator_empty.c
view3d_manipulator_forcefield.c
view3d_manipulator_lamp.c
+ view3d_manipulator_navigate.c
+ view3d_manipulator_navigate_type.c
view3d_manipulator_ruler.c
view3d_ops.c
view3d_project.c
@@ -71,6 +73,7 @@ set(SRC
view3d_select.c
view3d_snap.c
view3d_toolbar.c
+ view3d_utils.c
view3d_view.c
view3d_intern.h
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index 66355a50478..9fa85b55362 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -77,15 +77,15 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar)
}
/* set color
-* - more intense for active/selected bones, less intense for unselected bones
-* - black for before current frame, green for current frame, blue for after current frame
-* - intensity decreases as distance from current frame increases
-*
-* If the user select custom color, the color is replaced for the color selected in UI panel
-* - 75% Darker color is used for previous frames
-* - 50% Darker color for current frame
-* - User selected color for next frames
-*/
+ * - more intense for active/selected bones, less intense for unselected bones
+ * - black for before current frame, green for current frame, blue for after current frame
+ * - intensity decreases as distance from current frame increases
+ *
+ * If the user select custom color, the color is replaced for the color selected in UI panel
+ * - 75% Darker color is used for previous frames
+ * - 50% Darker color for current frame
+ * - User selected color for next frames
+ */
static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra,
float prev_color[3], float frame_color[3], float next_color[3], unsigned color)
{
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 08ef9cc21cb..51dc56bafaf 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -980,14 +980,12 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
col_pack_prev = vos->col.pack;
}
- ((vos->flag & V3D_CACHE_TEXT_ASCII) ?
- BLF_draw_default_ascii :
- BLF_draw_default
- )((float)(vos->sco[0] + vos->xoffs),
- (float)(vos->sco[1]),
- (depth_write) ? 0.0f : 2.0f,
- vos->str,
- vos->str_len);
+ ((vos->flag & V3D_CACHE_TEXT_ASCII) ? BLF_draw_default_ascii : BLF_draw_default)(
+ (float)(vos->sco[0] + vos->xoffs),
+ (float)(vos->sco[1]),
+ (depth_write) ? 0.0f : 2.0f,
+ vos->str,
+ vos->str_len);
}
}
@@ -1036,7 +1034,7 @@ static void drawcube_size(float size, unsigned pos)
{ size, size, size}
};
- const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6};
+ const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6};
#if 0
glEnableClientState(GL_VERTEX_ARRAY);
@@ -6098,46 +6096,46 @@ static void draw_new_particle_system(
/* 4. */
if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) {
- int tot_vec_size = (totpart + totchild) * 3 * sizeof(float);
+ int partsize = 3 * sizeof(float);
int create_ndata = 0;
if (!pdd)
pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData");
if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
- tot_vec_size *= part->trail_count;
+ partsize *= part->trail_count;
psys_make_temp_pointcache(ob, psys);
}
switch (draw_as) {
case PART_DRAW_AXIS:
case PART_DRAW_CROSS:
- tot_vec_size *= 6;
+ partsize *= 6;
if (draw_as != PART_DRAW_CROSS)
create_cdata = 1;
break;
case PART_DRAW_LINE:
- tot_vec_size *= 2;
+ partsize *= 2;
break;
case PART_DRAW_BB:
- tot_vec_size *= 6; /* New OGL only understands tris, no choice here. */
+ partsize *= 6; /* New OGL only understands tris, no choice here. */
create_ndata = 1;
break;
}
- if (pdd->tot_vec_size != tot_vec_size)
+ if (pdd->totpart != totpart + totchild || pdd->partsize != partsize)
psys_free_pdd(psys);
if (!pdd->vdata)
- pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata");
+ pdd->vdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_vdata");
if (create_cdata && !pdd->cdata)
- pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata");
+ pdd->cdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_cdata");
if (create_ndata && !pdd->ndata)
- pdd->ndata = MEM_callocN(tot_vec_size, "particle_ndata");
+ pdd->ndata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_ndata");
if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) {
if (!pdd->vedata)
- pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata");
+ pdd->vedata = MEM_calloc_arrayN(totpart + totchild, 2 * 3 * sizeof(float), "particle_vedata");
need_v = 1;
}
@@ -6151,7 +6149,8 @@ static void draw_new_particle_system(
pdd->ved = pdd->vedata;
pdd->cd = pdd->cdata;
pdd->nd = pdd->ndata;
- pdd->tot_vec_size = tot_vec_size;
+ pdd->totpart = totpart + totchild;
+ pdd->partsize = partsize;
}
else if (psys->pdd) {
psys_free_pdd(psys);
@@ -6630,7 +6629,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
const int totkeys = (*edit->pathcache)->segments + 1;
glEnable(GL_BLEND);
- float *pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
+ float *pathcol = MEM_calloc_arrayN(totkeys, 4 * sizeof(float), "particle path color data");
if (pset->brushtype == PE_BRUSH_WEIGHT)
glLineWidth(2.0f);
@@ -6707,8 +6706,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
if (totkeys_visible) {
if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO))
- pd = pdata = MEM_callocN(totkeys_visible * 3 * sizeof(float), "particle edit point data");
- cd = cdata = MEM_callocN(totkeys_visible * (timed ? 4 : 3) * sizeof(float), "particle edit color data");
+ pd = pdata = MEM_calloc_arrayN(totkeys_visible, 3 * sizeof(float), "particle edit point data");
+ cd = cdata = MEM_calloc_arrayN(totkeys_visible, (timed ? 4 : 3) * sizeof(float), "particle edit color data");
}
for (i = 0, point = edit->points; i < totpoint; i++, point++) {
@@ -7405,7 +7404,7 @@ static void draw_editnurb(
}
#else
/* Same as loop above */
- count += 4 * max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0);
+ count += 4 * ((nr / (skip + 1)) + ((nr % (skip + 1)) != 0));
#endif
}
@@ -8066,7 +8065,7 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos)
if (solid) {
/* Adpated from "Optimizing Triangle Strips for Fast Rendering" by F. Evans, S. Skiena and A. Varshney
* (http://www.cs.umd.edu/gvil/papers/av_ts.pdf). */
- static const GLubyte tris_strip_indices[14] = {0,1,3,2,6,1,5,0,4,3,7,6,4,5};
+ static const GLubyte tris_strip_indices[14] = {0, 1, 3, 2, 6, 1, 5, 0, 4, 3, 7, 6, 4, 5};
immBegin(GWN_PRIM_TRI_STRIP, 14);
for (int i = 0; i < 14; ++i) {
immVertex3fv(pos, vec[tris_strip_indices[i]]);
@@ -8074,7 +8073,8 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos)
immEnd();
}
else {
- static const GLubyte line_indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7};
+ static const GLubyte line_indices[24] =
+ {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7};
immBegin(GWN_PRIM_LINES, 24);
for (int i = 0; i < 24; ++i) {
immVertex3fv(pos, vec[line_indices[i]]);
@@ -9217,7 +9217,10 @@ afterdraw:
/* help lines and so */
if (ob != scene->obedit && ob->parent) {
- if (BKE_object_is_visible(ob->parent)) {
+ const eObjectVisibilityCheck mode = eval_ctx->mode != DAG_EVAL_VIEWPORT ?
+ OB_VISIBILITY_CHECK_FOR_RENDER :
+ OB_VISIBILITY_CHECK_FOR_VIEWPORT;
+ if (BKE_object_is_visible(ob->parent, mode)) {
setlinestyle(3);
immBegin(GWN_PRIM_LINES, 2);
immVertex3fv(pos, ob->obmat[3]);
@@ -9769,8 +9772,9 @@ void draw_object_backbufsel(
bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (ts->selectmode & SCE_SELECT_FACE) != 0);
if (ts->selectmode & SCE_SELECT_FACE)
bm_solidoffs = 1 + em->bm->totface;
- else
+ else {
bm_solidoffs = 1;
+ }
ED_view3d_polygon_offset(rv3d, 1.0);
@@ -9779,6 +9783,10 @@ void draw_object_backbufsel(
bbs_mesh_wire(em, dm, bm_solidoffs);
bm_wireoffs = bm_solidoffs + em->bm->totedge;
}
+ else {
+ /* `bm_vertoffs` is calculated from `bm_wireoffs`. (otherwise see T53512) */
+ bm_wireoffs = bm_solidoffs;
+ }
/* we draw verts if vert select mode. */
if (ts->selectmode & SCE_SELECT_VERTEX) {
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 3a80624acd9..d39f3937a9d 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -41,7 +41,7 @@
#include "BLI_math.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_texture.h"
+#include "BKE_colorband.h"
#include "BKE_particle.h"
#include "smoke_API.h"
@@ -111,7 +111,7 @@ static void create_flame_spectrum_texture(float *data)
static void create_color_ramp(const ColorBand *coba, float *data)
{
for (int i = 0; i < TFUNC_WIDTH; i++) {
- do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
+ BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
}
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 7cf1573de43..6540a1fb234 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -711,6 +711,9 @@ static void view3d_widgets(void)
WM_manipulatorgrouptype_append(VIEW3D_WGT_ruler);
WM_manipulatortype_append(VIEW3D_WT_ruler_item);
+
+ WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_navigate);
+ WM_manipulatortype_append(VIEW3D_WT_navigate_rotate);
}
@@ -1055,6 +1058,8 @@ static void view3d_main_region_message_subscribe(
/* Only subscribe to types. */
StructRNA *type_array[] = {
+ &RNA_Window,
+
/* These object have properties that impact drawing. */
&RNA_AreaLamp,
&RNA_Camera,
@@ -1102,10 +1107,12 @@ static void view3d_main_region_message_subscribe(
extern StructRNA RNA_ViewLayerEngineSettingsEevee;
WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw);
}
+#ifdef WITH_CLAY_ENGINE
else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) {
extern StructRNA RNA_ViewLayerEngineSettingsClay;
WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw);
}
+#endif
}
/* concept is to retrieve cursor type context-less */
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 9b07593e576..c39057431c2 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -138,13 +138,10 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
* the view for first-person style navigation.
*/
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
- const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d,
+ const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root)
{
View3DCameraControl *vctrl;
- EvaluationContext eval_ctx;
-
- CTX_data_eval_ctx(C, &eval_ctx);
vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__);
@@ -181,7 +178,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
/* store the original camera loc and rot */
vctrl->obtfm = BKE_object_tfm_backup(ob_back);
- BKE_object_where_is_calc(&eval_ctx, scene, v3d->camera);
+ BKE_object_where_is_calc(eval_ctx, scene, v3d->camera);
negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
rv3d->dist = 0.0;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 6ea2ff10af2..f734bb085d0 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -123,21 +123,28 @@ void ED_view3d_update_viewmat(
const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar,
float viewmat[4][4], float winmat[4][4], const rcti *rect)
{
+ const Depsgraph *depsgraph = eval_ctx->depsgraph;
RegionView3D *rv3d = ar->regiondata;
-
/* setup window matrices */
if (winmat)
copy_m4_m4(rv3d->winmat, winmat);
else
- view3d_winmatrix_set(ar, v3d, rect);
+ view3d_winmatrix_set(depsgraph, ar, v3d, rect);
/* setup view matrix */
- if (viewmat)
+ if (viewmat) {
copy_m4_m4(rv3d->viewmat, viewmat);
- else
- view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
-
+ }
+ else {
+ float rect_scale[2];
+ if (rect) {
+ rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx;
+ rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy;
+ }
+ /* note: calls BKE_object_where_is_calc for camera... */
+ view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d, rect ? rect_scale : NULL);
+ }
/* update utility matrices */
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
invert_m4_m4(rv3d->persinv, rv3d->persmat);
@@ -148,7 +155,7 @@ void ED_view3d_update_viewmat(
/* store window coordinates scaling/offset */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
rctf cameraborder;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
+ ED_view3d_calc_camera_border(scene, eval_ctx->depsgraph, 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);
@@ -307,7 +314,8 @@ void ED_view3d_draw_setup_view(
/* ******************** view border ***************** */
static void view3d_camera_border(
- const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ const Scene *scene, const struct Depsgraph *depsgraph,
+ const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
rctf *r_viewborder, const bool no_shift, const bool no_zoom)
{
CameraParams params;
@@ -315,7 +323,7 @@ static void view3d_camera_border(
/* get viewport viewplane */
BKE_camera_params_init(&params);
- BKE_camera_params_from_view3d(&params, v3d, rv3d);
+ BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
if (no_zoom)
params.zoom = 1.0f;
BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
@@ -342,21 +350,23 @@ static void view3d_camera_border(
}
void ED_view3d_calc_camera_border_size(
- const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ const Scene *scene, const Depsgraph *depsgraph,
+ const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
float r_size[2])
{
rctf viewborder;
- view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true);
+ view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, true, true);
r_size[0] = BLI_rctf_size_x(&viewborder);
r_size[1] = BLI_rctf_size_y(&viewborder);
}
void ED_view3d_calc_camera_border(
- const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ const Scene *scene, const Depsgraph *depsgraph,
+ const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
rctf *r_viewborder, const bool no_shift)
{
- view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
+ view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, r_viewborder, no_shift, false);
}
static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac)
@@ -435,7 +445,7 @@ static void drawviewborder_triangle(
immEnd();
}
-static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
+static void drawviewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d)
{
float x1, x2, y1, y2;
float x1i, x2i, y1i, y2i;
@@ -449,7 +459,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
if (v3d->camera->type == OB_CAMERA)
ca = v3d->camera->data;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
/* the offsets */
x1 = viewborder.xmin;
y1 = viewborder.ymin;
@@ -1318,6 +1328,10 @@ float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
static bool is_cursor_visible(Scene *scene, ViewLayer *view_layer)
{
+ if (U.app_flag & USER_APP_VIEW3D_HIDE_CURSOR) {
+ return false;
+ }
+
Object *ob = OBACT(view_layer);
/* don't draw cursor in paint modes, but with a few exceptions */
@@ -1594,11 +1608,12 @@ static void UNUSED_FUNCTION(draw_rotation_guide)(RegionView3D *rv3d)
static void view3d_draw_border(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
RegionView3D *rv3d = ar->regiondata;
View3D *v3d = CTX_wm_view3d(C);
if (rv3d->persp == RV3D_CAMOB) {
- drawviewborder(scene, ar, v3d);
+ drawviewborder(scene, depsgraph, ar, v3d);
}
else if (v3d->flag2 & V3D_RENDER_BORDER) {
drawrenderborder(ar, v3d);
@@ -1966,7 +1981,7 @@ void ED_view3d_draw_offscreen(
float viewmat[4][4], float winmat[4][4],
bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
GPUFX *fx, GPUFXSettings *fx_settings,
- GPUOffScreen *ofs)
+ GPUOffScreen *ofs, GPUViewport *viewport)
{
bool do_compositing = false;
RegionView3D *rv3d = ar->regiondata;
@@ -2015,6 +2030,10 @@ void ED_view3d_draw_offscreen(
else
view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL);
+ /* XXX, should take depsgraph as arg */
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ BLI_assert(depsgraph != NULL);
+
/* main drawing call */
RenderEngineType *engine_type = eval_ctx->engine_type;
if (engine_type->flag & RE_USE_LEGACY_PIPELINE) {
@@ -2049,7 +2068,7 @@ void ED_view3d_draw_offscreen(
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- ED_gpencil_draw_view3d(NULL, scene, view_layer, v3d, ar, false);
+ ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, false);
}
/* freeing the images again here could be done after the operator runs, leaving for now */
@@ -2057,10 +2076,7 @@ void ED_view3d_draw_offscreen(
}
}
else {
- /* XXX, should take depsgraph as arg */
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
- BLI_assert(depsgraph != NULL);
- DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs);
+ DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, do_sky, ofs, viewport);
}
/* restore size */
@@ -2090,6 +2106,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
/* output vars */
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
{
+ const Depsgraph *depsgraph = eval_ctx->depsgraph;
RegionView3D *rv3d = ar->regiondata;
const bool draw_sky = (alpha_mode == R_ADDSKY);
const bool draw_background = (draw_flags & V3D_OFSDRAW_USE_BACKGROUND);
@@ -2109,7 +2126,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
if (own_ofs) {
/* bind */
- ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, err_out);
+ ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, false, err_out);
if (ofs == NULL) {
return NULL;
}
@@ -2145,7 +2162,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
rctf viewplane;
float clipsta, clipend;
- is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
+ is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
if (is_ortho) {
orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
}
@@ -2159,7 +2176,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
ED_view3d_draw_offscreen(
eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat,
draw_background, draw_sky, !is_ortho, viewname,
- fx, &fx_settings, ofs);
+ fx, &fx_settings, ofs, NULL);
if (ibuf->rect_float) {
GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
@@ -2173,9 +2190,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
* Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */
static float jit_ofs[32][2];
float winmat_jitter[4][4];
- /* use imbuf as temp storage, before writing into it from accumulation buffer */
- unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float;
- unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1");
+ float *rect_temp = (ibuf->rect_float) ? ibuf->rect_float : MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp");
+ float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer");
+ GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs);
BLI_jitter_init(jit_ofs, samples);
@@ -2183,13 +2200,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
ED_view3d_draw_offscreen(
eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat,
draw_background, draw_sky, !is_ortho, viewname,
- fx, &fx_settings, ofs);
- GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
-
- unsigned i = sizex * sizey * 4;
- while (i--) {
- accum_buffer[i] = rect_temp[i];
- }
+ fx, &fx_settings, ofs, viewport);
+ GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer);
/* skip the first sample */
for (int j = 1; j < samples; j++) {
@@ -2202,27 +2214,38 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
ED_view3d_draw_offscreen(
eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat_jitter,
draw_background, draw_sky, !is_ortho, viewname,
- fx, &fx_settings, ofs);
- GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
+ fx, &fx_settings, ofs, viewport);
+ GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp);
- i = sizex * sizey * 4;
+ unsigned int i = sizex * sizey * 4;
while (i--) {
accum_buffer[i] += rect_temp[i];
}
}
+ {
+ /* don't free data owned by 'ofs' */
+ GPU_viewport_clear_from_offscreen(viewport);
+ GPU_viewport_free(viewport);
+ MEM_freeN(viewport);
+ }
+
+ if (ibuf->rect_float == NULL) {
+ MEM_freeN(rect_temp);
+ }
+
if (ibuf->rect_float) {
float *rect_float = ibuf->rect_float;
- i = sizex * sizey * 4;
+ unsigned int i = sizex * sizey * 4;
while (i--) {
- rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f);
+ rect_float[i] = accum_buffer[i] / samples;
}
}
else {
unsigned char *rect_ub = (unsigned char *)ibuf->rect;
- i = sizex * sizey * 4;
+ unsigned int i = sizex * sizey * 4;
while (i--) {
- rect_ub[i] = accum_buffer[i] / samples;
+ rect_ub[i] = (unsigned char)(255.0f * accum_buffer[i] / samples);
}
}
@@ -2383,9 +2406,9 @@ bool VP_legacy_use_depth(Scene *scene, View3D *v3d)
return use_depth_doit(scene, v3d);
}
-void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
+void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d)
{
- drawviewborder(scene, ar, v3d);
+ drawviewborder(scene, depsgraph, ar, v3d);
}
void VP_drawrenderborder(ARegion *ar, View3D *v3d)
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index 84f0f96fe0b..7cb362ffb92 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -284,7 +284,7 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen
}
if (!rv3d->gpuoffscreen) {
- rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error);
+ rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, false, error);
if (!rv3d->gpuoffscreen)
fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
@@ -530,7 +530,8 @@ static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, Ima
}
}
-static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
+static void view3d_draw_bgpic(Scene *scene, const Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d,
const bool do_foreground, const bool do_camera_frame)
{
RegionView3D *rv3d = ar->regiondata;
@@ -629,7 +630,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
{
if (do_camera_frame) {
rctf vb;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
x1 = vb.xmin;
y1 = vb.ymin;
x2 = vb.xmax;
@@ -773,8 +774,10 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
}
}
-void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame)
+void ED_view3d_draw_bgpic_test(
+ Scene *scene, const Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d,
+ const bool do_foreground, const bool do_camera_frame)
{
RegionView3D *rv3d = ar->regiondata;
@@ -797,11 +800,11 @@ void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
if (rv3d->persp == RV3D_CAMOB) {
- view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
+ view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
}
}
else {
- view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
+ view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
}
}
@@ -1182,7 +1185,7 @@ void ED_view3d_draw_depth_gpencil(
glEnable(GL_DEPTH_TEST);
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- ED_gpencil_draw_view3d(NULL, scene, eval_ctx->view_layer, v3d, ar, true);
+ ED_gpencil_draw_view3d(NULL, scene, eval_ctx->view_layer, eval_ctx->depsgraph, v3d, ar, true);
}
v3d->zbuf = zbuf;
@@ -1423,7 +1426,7 @@ static void gpu_update_lamps_shadows_world(const EvaluationContext *eval_ctx, Sc
ED_view3d_draw_offscreen(
eval_ctx, scene, eval_ctx->view_layer, v3d, &ar, winsize, winsize, viewmat, winmat,
false, false, true,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL);
GPU_lamp_shadow_buffer_unbind(shadow->lamp);
v3d->drawtype = drawtype;
@@ -1500,6 +1503,7 @@ static void view3d_draw_objects(
const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
{
ViewLayer *view_layer = C ? CTX_data_view_layer(C) : BKE_view_layer_from_scene_get(scene);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
RegionView3D *rv3d = ar->regiondata;
Base *base;
const bool do_camera_frame = !draw_offscreen;
@@ -1544,7 +1548,7 @@ static void view3d_draw_objects(
/* important to do before clipping */
if (do_bgpic) {
- view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, do_camera_frame);
}
if (rv3d->rflag & RV3D_CLIPPING) {
@@ -1625,7 +1629,7 @@ static void view3d_draw_objects(
/* must be before xray draw which clears the depth buffer */
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- ED_gpencil_draw_view3d(wm, scene, view_layer, v3d, ar, true);
+ ED_gpencil_draw_view3d(wm, scene, view_layer, depsgraph, v3d, ar, true);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -1654,7 +1658,7 @@ static void view3d_draw_objects(
/* important to do after clipping */
if (do_bgpic) {
- view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, do_camera_frame);
}
/* cleanup */
@@ -1773,7 +1777,7 @@ static bool view3d_main_region_do_render_draw(const Scene *scene)
return (type && type->view_update && type->render_to_view);
}
-bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, rcti *rect)
+bool ED_view3d_calc_render_border(const Scene *scene, const Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
bool use_border;
@@ -1794,7 +1798,7 @@ bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar,
/* compute border */
if (rv3d->persp == RV3D_CAMOB) {
rctf viewborder;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
@@ -1823,11 +1827,11 @@ static bool view3d_main_region_draw_engine(
ARegion *ar, View3D *v3d,
bool clip_border, const rcti *border_rect)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
RegionView3D *rv3d = ar->regiondata;
RenderEngineType *type;
GLint scissor[4];
-
/* create render engine */
if (!rv3d->render_engine) {
RenderEngine *engine;
@@ -1872,7 +1876,7 @@ static bool view3d_main_region_draw_engine(
Camera *cam = ED_view3d_camera_data_get(v3d, rv3d);
if (cam->flag & CAM_SHOW_BG_IMAGE) {
show_image = true;
- view3d_draw_bgpic_test(scene, ar, v3d, false, true);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true);
}
else {
imm_draw_box_checker_2d(0, 0, ar->winx, ar->winy);
@@ -1880,7 +1884,7 @@ static bool view3d_main_region_draw_engine(
}
if (show_image) {
- view3d_draw_bgpic_test(scene, ar, v3d, false, true);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true);
}
else {
imm_draw_box_checker_2d(0, 0, ar->winx, ar->winy);
@@ -1891,7 +1895,7 @@ static bool view3d_main_region_draw_engine(
type->render_to_view(rv3d->render_engine, C);
if (show_image) {
- view3d_draw_bgpic_test(scene, ar, v3d, true, true);
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, true);
}
if (clip_border) {
@@ -2007,11 +2011,6 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie
/* main drawing call */
view3d_draw_objects(C, &eval_ctx, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL);
- /* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */
- /* TODO depth culling manipulators is not yet supported, just drawing _3D here, should
- * later become _IN_SCENE (and draw _3D separate) */
- WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D);
-
/* post process */
if (do_compositing) {
GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL);
@@ -2038,6 +2037,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
ARegion *ar, View3D *v3d,
const char *grid_unit, bool render_border)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
wmWindowManager *wm = CTX_wm_manager(C);
RegionView3D *rv3d = ar->regiondata;
@@ -2047,7 +2047,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
ED_region_visible_rect(ar, &rect);
if (rv3d->persp == RV3D_CAMOB) {
- VP_drawviewborder(scene, ar, v3d);
+ VP_drawviewborder(scene, CTX_data_depsgraph(C), ar, v3d);
}
else if (v3d->flag2 & V3D_RENDER_BORDER) {
VP_drawrenderborder(ar, v3d);
@@ -2055,7 +2055,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- ED_gpencil_draw_view3d(wm, scene, view_layer, v3d, ar, false);
+ ED_gpencil_draw_view3d(wm, scene, view_layer, depsgraph, v3d, ar, false);
}
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
@@ -2102,6 +2102,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
EvaluationContext eval_ctx;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2111,7 +2112,7 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar)
/* if we only redraw render border area, skip opengl draw and also
* don't do scissor because it's already set */
- bool render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect);
+ bool render_border = ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect);
bool clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect));
gpuPushProjectionMatrix();
@@ -2141,12 +2142,14 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar)
VP_legacy_view3d_main_region_setup_view(&eval_ctx, scene, v3d, ar, NULL, NULL);
glClear(GL_DEPTH_BUFFER_BIT);
- ED_region_pixelspace(ar);
+ WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D);
- WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D);
+ ED_region_pixelspace(ar);
view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
+ WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D);
+
gpuPopProjectionMatrix();
gpuPopMatrix();
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 0dba87bef25..2457a890f71 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -26,6 +26,8 @@
/** \file blender/editors/space_view3d/view3d_edit.c
* \ingroup spview3d
+ *
+ * 3D view manipulation/operators.
*/
#include <string.h>
@@ -42,9 +44,7 @@
#include "MEM_guardedalloc.h"
-#include "BLI_bitmap_draw_2d.h"
#include "BLI_blenlib.h"
-#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -63,7 +63,6 @@
#include "DEG_depsgraph.h"
-#include "BIF_gl.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -73,499 +72,129 @@
#include "ED_armature.h"
#include "ED_particle.h"
-#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_mesh.h"
#include "ED_gpencil.h"
#include "ED_view3d.h"
-#include "DEG_depsgraph_query.h"
-
#include "UI_resources.h"
-#include "PIL_time.h" /* smoothview */
+#include "PIL_time.h"
#include "view3d_intern.h" /* own include */
-static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar);
-
-bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
-{
- return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
-}
-
-/* ********************** view3d_edit: view manipulations ********************* */
-
-/**
- * \return true when the view-port is locked to its camera.
- */
-bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
-{
- return ((v3d->camera) &&
- (!ID_IS_LINKED(v3d->camera)) &&
- (v3d->flag2 & V3D_LOCK_CAMERA) &&
- (rv3d->persp == RV3D_CAMOB));
-}
-
-/**
- * Apply the camera object transformation to the view-port.
- * (needed so we can use regular view-port manipulation operators, that sync back to the camera).
- */
-void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
-{
- if (ED_view3d_camera_lock_check(v3d, rv3d)) {
- if (calc_dist) {
- /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
- rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
- }
- ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
- }
-}
-
-void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
-{
- ED_view3d_camera_lock_init_ex(v3d, rv3d, true);
-}
-
-/**
- * Apply the view-port transformation back to the camera object.
- *
- * \return true if the camera is moved.
- */
-bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
-{
- if (ED_view3d_camera_lock_check(v3d, rv3d)) {
- ObjectTfmProtectedChannels obtfm;
- Object *root_parent;
-
- if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
- Object *ob_update;
- float tmat[4][4];
- float imat[4][4];
- float view_mat[4][4];
- float diff_mat[4][4];
- float parent_mat[4][4];
-
- while (root_parent->parent) {
- root_parent = root_parent->parent;
- }
-
- ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
-
- normalize_m4_m4(tmat, v3d->camera->obmat);
-
- invert_m4_m4(imat, tmat);
- mul_m4_m4m4(diff_mat, view_mat, imat);
-
- mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
-
- BKE_object_tfm_protected_backup(root_parent, &obtfm);
- BKE_object_apply_mat4(root_parent, parent_mat, true, false);
- BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
-
- ob_update = v3d->camera;
- while (ob_update) {
- DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
- WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
- ob_update = ob_update->parent;
- }
- }
- else {
- /* always maintain the same scale */
- const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
- BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
- ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
- BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
-
- DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
- WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
- }
-
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ED_view3d_camera_autokey(
- Scene *scene, ID *id_key,
- struct bContext *C, const bool do_rotate, const bool do_translate)
-{
- if (autokeyframe_cfra_can_key(scene, id_key)) {
- const float cfra = (float)CFRA;
- ListBase dsources = {NULL, NULL};
-
- /* add data-source override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
-
- /* insert keyframes
- * 1) on the first frame
- * 2) on each subsequent frame
- * TODO: need to check in future that frame changed before doing this
- */
- if (do_rotate) {
- struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_translate) {
- struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
-
- /* free temp data */
- BLI_freelistN(&dsources);
-
- return true;
- }
- else {
- return false;
- }
-}
-
-/**
- * Call after modifying a locked view.
- *
- * \note Not every view edit currently auto-keys (numpad for eg),
- * this is complicated because of smoothview.
- */
-bool ED_view3d_camera_lock_autokey(
- View3D *v3d, RegionView3D *rv3d,
- struct bContext *C, const bool do_rotate, const bool do_translate)
-{
- /* similar to ED_view3d_cameracontrol_update */
- if (ED_view3d_camera_lock_check(v3d, rv3d)) {
- Scene *scene = CTX_data_scene(C);
- ID *id_key;
- Object *root_parent;
- if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
- while (root_parent->parent) {
- root_parent = root_parent->parent;
- }
- id_key = &root_parent->id;
- }
- else {
- id_key = &v3d->camera->id;
- }
-
- return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
- }
- else {
- return false;
- }
-}
-
-/**
- * For viewport operators that exit camera persp.
- *
- * \note This differs from simply setting ``rv3d->persp = persp`` because it
- * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
- * otherwise switching out of camera view may jump to a different part of the scene.
- */
-static void view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp)
-{
- BLI_assert(rv3d->persp == RV3D_CAMOB);
- BLI_assert(persp != RV3D_CAMOB);
-
- if (v3d->camera) {
- rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
- ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
- }
-
- if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
- rv3d->persp = persp;
- }
-}
-
-/* ********************* box view support ***************** */
-
-static void view3d_boxview_clip(ScrArea *sa)
-{
- ARegion *ar;
- BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
- float clip[6][4];
- float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
- int val;
-
- /* create bounding box */
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = ar->regiondata;
-
- if (rv3d->viewlock & RV3D_BOXCLIP) {
- if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
- if (ar->winx > ar->winy) x1 = rv3d->dist;
- else x1 = ar->winx * rv3d->dist / ar->winy;
-
- if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx;
- else y1 = rv3d->dist;
- copy_v2_v2(ofs, rv3d->ofs);
- }
- else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
- ofs[2] = rv3d->ofs[2];
-
- if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx;
- else z1 = rv3d->dist;
- }
- }
- }
- }
-
- for (val = 0; val < 8; val++) {
- if (ELEM(val, 0, 3, 4, 7))
- bb->vec[val][0] = -x1 - ofs[0];
- else
- bb->vec[val][0] = x1 - ofs[0];
-
- if (ELEM(val, 0, 1, 4, 5))
- bb->vec[val][1] = -y1 - ofs[1];
- else
- bb->vec[val][1] = y1 - ofs[1];
-
- if (val > 3)
- bb->vec[val][2] = -z1 - ofs[2];
- else
- bb->vec[val][2] = z1 - ofs[2];
- }
-
- /* normals for plane equations */
- normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
- normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
- normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
- normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
- normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
- normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
-
- /* then plane equations */
- for (val = 0; val < 6; val++) {
- clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
- }
-
- /* create bounding box */
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = ar->regiondata;
-
- if (rv3d->viewlock & RV3D_BOXCLIP) {
- rv3d->rflag |= RV3D_CLIPPING;
- memcpy(rv3d->clip, clip, sizeof(clip));
- if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
- rv3d->clipbb = MEM_dupallocN(bb);
- }
- }
- }
- MEM_freeN(bb);
-}
-
-/**
- * Find which axis values are shared between both views and copy to \a rv3d_dst
- * taking axis flipping into account.
- */
-static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
-{
- /* absolute axis values above this are considered to be set (will be ~1.0f) */
- const float axis_eps = 0.5f;
- float viewinv[4];
-
- /* use the view rotation to identify which axis to sync on */
- float view_axis_all[4][3] = {
- {1.0f, 0.0f, 0.0f},
- {0.0f, 1.0f, 0.0f},
- {1.0f, 0.0f, 0.0f},
- {0.0f, 1.0f, 0.0f}};
-
- float *view_src_x = &view_axis_all[0][0];
- float *view_src_y = &view_axis_all[1][0];
-
- float *view_dst_x = &view_axis_all[2][0];
- float *view_dst_y = &view_axis_all[3][0];
- int i;
-
-
- /* we could use rv3d->viewinv, but better not depend on view matrix being updated */
- if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) {
- return;
- }
- invert_qt_normalized(viewinv);
- mul_qt_v3(viewinv, view_src_x);
- mul_qt_v3(viewinv, view_src_y);
-
- if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) {
- return;
- }
- invert_qt_normalized(viewinv);
- mul_qt_v3(viewinv, view_dst_x);
- mul_qt_v3(viewinv, view_dst_y);
+/* -------------------------------------------------------------------- */
+/** \name Generic View Operator Properties
+ * \{ */
- /* check source and dest have a matching axis */
- for (i = 0; i < 3; i++) {
- if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
- ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
- {
- rv3d_dst->ofs[i] = rv3d_src->ofs[i];
- }
- }
-}
+enum eV3D_OpPropFlag {
+ V3D_OP_PROP_MOUSE_CO = (1 << 0),
+ V3D_OP_PROP_DELTA = (1 << 1),
+ V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2),
+ V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3),
+};
-/* sync center/zoom view of region to others, for view transforms */
-static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
+static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag)
{
- ARegion *artest;
- RegionView3D *rv3d = ar->regiondata;
- short clip = 0;
-
- for (artest = sa->regionbase.first; artest; artest = artest->next) {
- if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3dtest = artest->regiondata;
-
- if (rv3dtest->viewlock & RV3D_LOCKED) {
- rv3dtest->dist = rv3d->dist;
- view3d_boxview_sync_axis(rv3dtest, rv3d);
- clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
-
- ED_region_tag_redraw(artest);
- }
- }
+ if (flag & V3D_OP_PROP_MOUSE_CO) {
+ PropertyRNA *prop;
+ prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
-
- if (clip) {
- view3d_boxview_clip(sa);
+ if (flag & V3D_OP_PROP_DELTA) {
+ RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
}
-}
-
-/* for home, center etc */
-void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
-{
- ARegion *artest;
- RegionView3D *rv3d = ar->regiondata;
- bool clip = false;
-
- for (artest = sa->regionbase.first; artest; artest = artest->next) {
- if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3dtest = artest->regiondata;
-
- if (rv3dtest->viewlock) {
- rv3dtest->dist = rv3d->dist;
- copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
- ED_region_tag_redraw(artest);
-
- clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0);
- }
- }
+ if (flag & V3D_OP_PROP_USE_ALL_REGIONS) {
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-
- if (clip) {
- view3d_boxview_clip(sa);
+ if (flag & V3D_OP_PROP_USE_MOUSE_INIT) {
+ /* Disable when view operators are initialized from buttons. */
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna, "use_mouse_init", true, "Mouse Init", "Use initial mouse position");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
}
-/* 'clip' is used to know if our clip setting has changed */
-void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
-{
- ARegion *ar_sync = NULL;
- RegionView3D *rv3d = ar->regiondata;
- short viewlock;
- /* this function copies flags from the first of the 3 other quadview
- * regions to the 2 other, so it assumes this is the region whose
- * properties are always being edited, weak */
- viewlock = rv3d->viewlock;
-
- if ((viewlock & RV3D_LOCKED) == 0) {
- do_clip = (viewlock & RV3D_BOXCLIP) != 0;
- viewlock = 0;
- }
- else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
- do_clip = true;
- viewlock &= ~RV3D_BOXCLIP;
- }
-
- for (; ar; ar = ar->prev) {
- if (ar->alignment == RGN_ALIGN_QSPLIT) {
- rv3d = ar->regiondata;
- rv3d->viewlock = viewlock;
-
- if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
- rv3d->rflag &= ~RV3D_BOXCLIP;
- }
-
- /* use ar_sync so we sync with one of the aligned views below
- * else the view jumps on changing view settings like 'clip'
- * since it copies from the perspective view */
- ar_sync = ar;
- }
- }
-
- if (rv3d->viewlock & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
- }
-
- /* ensure locked regions have an axis, locked user views don't make much sense */
- if (viewlock & RV3D_LOCKED) {
- int index_qsplit = 0;
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->alignment == RGN_ALIGN_QSPLIT) {
- rv3d = ar->regiondata;
- if (rv3d->viewlock) {
- if (!RV3D_VIEW_IS_AXIS(rv3d->view)) {
- rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
- rv3d->persp = RV3D_ORTHO;
- ED_view3d_lock(rv3d);
- }
- }
- index_qsplit++;
- }
- }
- }
-
- ED_area_tag_redraw(sa);
-}
+/** \} */
-/* ************************** init for view ops **********************************/
+/* -------------------------------------------------------------------- */
+/** \name Generic View Operator Custom-Data
+ * \{ */
typedef struct ViewOpsData {
- /* context pointers (assigned by viewops_data_alloc) */
+ /** Context pointers (assigned by #viewops_data_alloc). */
Scene *scene;
ScrArea *sa;
ARegion *ar;
View3D *v3d;
RegionView3D *rv3d;
+ Depsgraph *depsgraph;
- /* needed for continuous zoom */
+ /** Needed for continuous zoom. */
wmTimer *timer;
- double timer_lastdraw;
- float oldquat[4];
- float viewquat[4]; /* working copy of rv3d->viewquat */
- float trackvec[3];
- float mousevec[3]; /* dolly only */
+ /** Viewport state on initialization, don't change afterwards. */
+ struct {
+ float dist;
+ float camzoom;
+ float quat[4];
+ /** #wmEvent.x, y. */
+ int event_xy[2];
+ /** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set.
+ * so we can simulate pressing in the middle of the screen. */
+ int event_xy_offset[2];
+ /** #wmEvent.type that triggered the operator. */
+ int event_type;
+ float ofs[3];
+ /** Initial distance to 'ofs'. */
+ float zfac;
+
+ /** Trackball rotation only. */
+ float trackvec[3];
+ /** Dolly only. */
+ float mousevec[3];
+ } init;
+
+ /** Previous state (previous modal event handled). */
+ struct {
+ int event_xy[2];
+ /** For operators that use time-steps (continuous zoom). */
+ double time;
+ } prev;
+
+ /** Current state. */
+ struct {
+ /** Working copy of #RegionView3D.viewquat, needed for rotation calculation
+ * so we can apply snap to the view-port while keeping the unsnapped rotation
+ * here to use when snap is disabled and for continued calculation. */
+ float viewquat[4];
+ } curr;
+
float reverse;
- float dist_prev, camzoom_prev;
- float grid, far;
bool axis_snap; /* view rotate only */
- float zfac;
- /* use for orbit selection and auto-dist */
- float ofs[3], dyn_ofs[3];
+ /** Use for orbit selection and auto-dist. */
+ float dyn_ofs[3];
bool use_dyn_ofs;
-
- int origx, origy, oldx, oldy;
- int origkey; /* the key that triggered the operator */
-
} ViewOpsData;
#define TRACKBALLSIZE (1.1f)
-static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
+static void calctrackballvec(const rcti *rect, const int event_xy[2], float vec[3])
{
const float radius = TRACKBALLSIZE;
const float t = radius / (float)M_SQRT2;
float x, y, z, d;
/* normalize x and y */
- x = BLI_rcti_cent_x(rect) - mx;
+ x = BLI_rcti_cent_x(rect) - event_xy[0];
x /= (float)(BLI_rcti_size_x(rect) / 4);
- y = BLI_rcti_cent_y(rect) - my;
+ y = BLI_rcti_cent_y(rect) - event_xy[1];
y /= (float)(BLI_rcti_size_y(rect) / 2);
d = sqrtf(x * x + y * y);
if (d < t) { /* Inside sphere */
@@ -580,13 +209,6 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
vec[2] = -z; /* yah yah! */
}
-
-/* -------------------------------------------------------------------- */
-/* ViewOpsData */
-
-/** \name Generic View Operator Custom-Data.
- * \{ */
-
/**
* Allocate and fill in context pointers for #ViewOpsData
*/
@@ -596,6 +218,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
/* store data */
op->customdata = vod;
+ vod->depsgraph = CTX_data_depsgraph(C);
vod->scene = CTX_data_scene(C);
vod->sa = CTX_wm_area(C);
vod->ar = CTX_wm_region(C);
@@ -604,7 +227,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
}
void view3d_orbit_apply_dyn_ofs(
- float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
+ float r_ofs[3], const float ofs_init[3], const float viewquat_old[4],
const float viewquat_new[4], const float dyn_ofs[3])
{
float q[4];
@@ -613,7 +236,7 @@ void view3d_orbit_apply_dyn_ofs(
invert_qt_normalized(q);
- sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs);
+ sub_v3_v3v3(r_ofs, ofs_init, dyn_ofs);
mul_qt_v3(q, r_ofs);
add_v3_v3(r_ofs, dyn_ofs);
}
@@ -702,48 +325,58 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
return is_set;
}
-enum eViewOpsOrbit {
- VIEWOPS_ORBIT_SELECT = (1 << 0),
- VIEWOPS_ORBIT_DEPTH = (1 << 1),
+enum eViewOpsFlag {
+ /** When enabled, rotate around the selection. */
+ VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0),
+ /** When enabled, use the depth under the cursor for navigation. */
+ VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1),
+ /**
+ * When enabled run #ED_view3d_persp_ensure this may switch out of
+ * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled.
+ * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common
+ * so we don't want it to trigger auto-perspective). */
+ VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2),
+ /** When set, ignore any options that depend on initial cursor location. */
+ VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3),
};
-static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth)
+static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth)
{
- enum eViewOpsOrbit flag = 0;
+ enum eViewOpsFlag flag = 0;
if (use_select) {
- flag |= VIEWOPS_ORBIT_SELECT;
+ flag |= VIEWOPS_FLAG_ORBIT_SELECT;
}
if (use_depth) {
- flag |= VIEWOPS_ORBIT_DEPTH;
+ flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE;
}
return flag;
}
-static enum eViewOpsOrbit viewops_orbit_mode(void)
+static enum eViewOpsFlag viewops_flag_from_prefs(void)
{
- return viewops_orbit_mode_ex(
+ return viewops_flag_from_args(
(U.uiflag & USER_ORBIT_SELECTION) != 0,
- (U.uiflag & USER_ZBUF_ORBIT) != 0);
+ (U.uiflag & USER_DEPTH_NAVIGATE) != 0);
}
/**
* Calculate the values for #ViewOpsData
- *
- * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of
- * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled.
- * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common
- * so we don't want it to trigger auto-perspective).
*/
-static void viewops_data_create_ex(
+static void viewops_data_create(
bContext *C, wmOperator *op, const wmEvent *event,
- bool use_ensure_persp, enum eViewOpsOrbit orbit_mode)
+ enum eViewOpsFlag viewops_flag)
{
ViewOpsData *vod = op->customdata;
RegionView3D *rv3d = vod->rv3d;
+ /* Could do this more nicely. */
+ if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) {
+ viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
+ }
+
/* we need the depth info before changing any viewport options */
- if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+ if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) {
EvaluationContext eval_ctx;
struct Depsgraph *graph = CTX_data_depsgraph(C);
float fallback_depth_pt[3];
@@ -762,8 +395,8 @@ static void viewops_data_create_ex(
vod->use_dyn_ofs = false;
}
- if (use_ensure_persp) {
- if (view3d_ensure_persp(vod->v3d, vod->ar)) {
+ if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
+ if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) {
/* If we're switching from camera view to the perspective one,
* need to tag viewport update, so camera vuew and borders
* are properly updated.
@@ -776,25 +409,37 @@ static void viewops_data_create_ex(
* we may want to make this optional but for now its needed always */
ED_view3d_camera_lock_init(vod->v3d, vod->rv3d);
- vod->dist_prev = rv3d->dist;
- vod->camzoom_prev = rv3d->camzoom;
- copy_qt_qt(vod->viewquat, rv3d->viewquat);
- copy_qt_qt(vod->oldquat, rv3d->viewquat);
- vod->origx = vod->oldx = event->x;
- vod->origy = vod->oldy = event->y;
- vod->origkey = event->type; /* the key that triggered the operator. */
- copy_v3_v3(vod->ofs, rv3d->ofs);
+ vod->init.dist = rv3d->dist;
+ vod->init.camzoom = rv3d->camzoom;
+ copy_qt_qt(vod->init.quat, rv3d->viewquat);
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
+ vod->init.event_xy[1] = vod->prev.event_xy[1] = event->y;
+
+ if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) {
+ vod->init.event_xy_offset[0] = 0;
+ vod->init.event_xy_offset[1] = 0;
+ }
+ else {
+ /* Simulate the event starting in the middle of the region. */
+ vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->ar->winrct) - event->x;
+ vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->ar->winrct) - event->y;
+ }
- if (orbit_mode & VIEWOPS_ORBIT_SELECT) {
+ vod->init.event_type = event->type;
+ copy_v3_v3(vod->init.ofs, rv3d->ofs);
+
+ copy_qt_qt(vod->curr.viewquat, rv3d->viewquat);
+
+ if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) {
float ofs[3];
if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) {
vod->use_dyn_ofs = true;
negate_v3_v3(vod->dyn_ofs, ofs);
- orbit_mode &= ~VIEWOPS_ORBIT_DEPTH;
+ viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
}
}
- if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+ if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) {
if (vod->use_dyn_ofs) {
if (rv3d->is_persp) {
float my_origin[3]; /* original G.vd->ofs */
@@ -821,7 +466,7 @@ static void viewops_data_create_ex(
/* find a new ofs value that is along the view axis (rather than the mouse location) */
closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
- vod->dist_prev = rv3d->dist = len_v3v3(my_pivot, dvec);
+ vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec);
negate_v3_v3(rv3d->ofs, dvec);
}
@@ -834,27 +479,26 @@ static void viewops_data_create_ex(
negate_v3(rv3d->ofs);
}
negate_v3(vod->dyn_ofs);
- copy_v3_v3(vod->ofs, rv3d->ofs);
+ copy_v3_v3(vod->init.ofs, rv3d->ofs);
}
}
+ /* For dolly */
+ ED_view3d_win_to_vector(vod->ar, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec);
+
{
- /* for dolly */
- const float mval_f[2] = {(float)event->mval[0],
- (float)event->mval[1]};
- ED_view3d_win_to_vector(vod->ar, mval_f, vod->mousevec);
+ const int event_xy_offset[2] = {
+ event->x + vod->init.event_xy_offset[0],
+ event->y + vod->init.event_xy_offset[1],
+ };
+ /* For rotation with trackball rotation. */
+ calctrackballvec(&vod->ar->winrct, event_xy_offset, vod->init.trackvec);
}
- /* lookup, we don't pass on v3d to prevent confusement */
- vod->grid = vod->v3d->grid;
- vod->far = vod->v3d->far;
-
- calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
-
{
float tvec[3];
negate_v3_v3(tvec, rv3d->ofs);
- vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
+ vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
}
vod->reverse = 1.0f;
@@ -864,12 +508,6 @@ static void viewops_data_create_ex(
rv3d->rflag |= RV3D_NAVIGATING;
}
-static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp)
-{
- enum eViewOpsOrbit orbit_mode = viewops_orbit_mode();
- viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode);
-}
-
static void viewops_data_free(bContext *C, wmOperator *op)
{
ARegion *ar;
@@ -896,10 +534,12 @@ static void viewops_data_free(bContext *C, wmOperator *op)
#endif
ED_region_tag_redraw(ar);
}
-/** \} */
+/** \} */
-/* ************************** viewrotate **********************************/
+/* -------------------------------------------------------------------- */
+/** \name View Rotate Operator
+ * \{ */
enum {
VIEW_PASS = 0,
@@ -908,12 +548,14 @@ enum {
};
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-#define VIEW_MODAL_CONFIRM 1 /* used for all view operations */
-#define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2
-#define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3
-#define VIEWROT_MODAL_SWITCH_ZOOM 4
-#define VIEWROT_MODAL_SWITCH_MOVE 5
-#define VIEWROT_MODAL_SWITCH_ROTATE 6
+enum {
+ VIEW_MODAL_CONFIRM = 1, /* used for all view operations */
+ VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2,
+ VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3,
+ VIEWROT_MODAL_SWITCH_ZOOM = 4,
+ VIEWROT_MODAL_SWITCH_MOVE = 5,
+ VIEWROT_MODAL_SWITCH_ROTATE = 6,
+};
/* called in transform_ops.c, on each regeneration of keymaps */
void viewrotate_modal_keymap(wmKeyConfig *keyconf)
@@ -923,7 +565,7 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
{VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""},
{VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""},
-
+
{VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
@@ -950,17 +592,16 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
#endif
-
+
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
-
}
static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
{
if (vod->use_dyn_ofs) {
RegionView3D *rv3d = vod->rv3d;
- view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->ofs, vod->oldquat, viewquat_new, vod->dyn_ofs);
+ view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs);
}
}
@@ -976,7 +617,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
int x, y, z;
bool found = false;
- invert_qt_qt_normalized(viewquat_inv, vod->viewquat);
+ invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat);
mul_qt_v3(viewquat_inv, zaxis);
normalize_v3(zaxis);
@@ -1012,7 +653,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
* for testing roll */
rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis);
normalize_qt(viewquat_align);
- mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align);
+ mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align);
normalize_qt(viewquat_align);
invert_qt_qt_normalized(viewquat_align_inv, viewquat_align);
@@ -1066,7 +707,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
}
}
-static void viewrotate_apply(ViewOpsData *vod, int x, int y)
+static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
{
RegionView3D *rv3d = vod->rv3d;
@@ -1076,9 +717,15 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
float axis[3], q1[4], dvec[3], newvec[3];
float angle;
- calctrackballvec(&vod->ar->winrct, x, y, newvec);
+ {
+ const int event_xy_offset[2] = {
+ event_xy[0] + vod->init.event_xy_offset[0],
+ event_xy[1] + vod->init.event_xy_offset[1],
+ };
+ calctrackballvec(&vod->ar->winrct, event_xy_offset, newvec);
+ }
- sub_v3_v3v3(dvec, newvec, vod->trackvec);
+ sub_v3_v3v3(dvec, newvec, vod->init.trackvec);
angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI;
@@ -1089,12 +736,12 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
* so that the angle of rotation is linearly proportional to
* the distance that the mouse is dragged. */
- cross_v3_v3v3(axis, vod->trackvec, newvec);
+ cross_v3_v3v3(axis, vod->init.trackvec, newvec);
axis_angle_to_quat(q1, axis, angle);
- mul_qt_qtqt(vod->viewquat, q1, vod->oldquat);
+ mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat);
- viewrotate_apply_dyn_ofs(vod, vod->viewquat);
+ viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat);
}
else {
/* New turntable view code by John Aughey */
@@ -1111,7 +758,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
const float sensitivity = 0.007f;
/* Get the 3x3 matrix and its inverse from the quaternion */
- quat_to_mat3(m, vod->viewquat);
+ quat_to_mat3(m, vod->curr.viewquat);
invert_m3_m3(m_inv, m);
/* avoid gimble lock */
@@ -1138,30 +785,30 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
/* This can likely be computed directly from the quaternion. */
/* Perform the up/down rotation */
- axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(y - vod->oldy));
- mul_qt_qtqt(quat_local_x, vod->viewquat, quat_local_x);
+ axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1]));
+ mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x);
/* Perform the orbital rotation */
- axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (x - vod->oldx));
- mul_qt_qtqt(vod->viewquat, quat_local_x, quat_global_z);
+ axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0]));
+ mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z);
- viewrotate_apply_dyn_ofs(vod, vod->viewquat);
+ viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat);
}
/* avoid precision loss over time */
- normalize_qt(vod->viewquat);
+ normalize_qt(vod->curr.viewquat);
/* use a working copy so view rotation locking doesnt overwrite the locked
* rotation back into the view we calculate with */
- copy_qt_qt(rv3d->viewquat, vod->viewquat);
+ copy_qt_qt(rv3d->viewquat, vod->curr.viewquat);
/* check for view snap,
* note: don't apply snap to vod->viewquat so the view wont jam up */
if (vod->axis_snap) {
viewrotate_apply_snap(vod);
}
- vod->oldx = x;
- vod->oldy = y;
+ vod->prev.event_xy[0] = event_xy[0];
+ vod->prev.event_xy[1] = event_xy[1];
ED_view3d_camera_lock_sync(vod->v3d, rv3d);
@@ -1202,12 +849,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- else if (event->type == vod->origkey && event->val == KM_RELEASE) {
+ else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
if (event_code == VIEW_APPLY) {
- viewrotate_apply(vod, event->x, event->y);
+ viewrotate_apply(vod, &event->x);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -1229,41 +876,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
return ret;
}
-/**
- * Action to take when rotating the view,
- * handle auto-persp and logic for switching out of views.
- *
- * shared with NDOF.
- */
-static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar)
-{
- RegionView3D *rv3d = ar->regiondata;
- const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
-
- BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
-
- if (ED_view3d_camera_lock_check(v3d, rv3d))
- return false;
-
- if (rv3d->persp != RV3D_PERSP) {
- if (rv3d->persp == RV3D_CAMOB) {
- /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */
- char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp;
- view3d_persp_switch_from_camera(v3d, rv3d, persp);
- }
- else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
- rv3d->persp = RV3D_PERSP;
- }
- return true;
- }
-
- return false;
-}
-
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
+
/* makes op->customdata */
viewops_data_alloc(C, op);
vod = op->customdata;
@@ -1276,29 +894,33 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
- viewops_data_create(C, op, event, true);
+ viewops_data_create(
+ C, op, event,
+ viewops_flag_from_prefs() |
+ VIEWOPS_FLAG_PERSP_ENSURE |
+ (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
/* Rotate direction we keep always same */
- int x, y;
+ int event_xy[2];
if (event->type == MOUSEPAN) {
if (U.uiflag2 & USER_TRACKPAD_NATURAL) {
- x = 2 * event->x - event->prevx;
- y = 2 * event->y - event->prevy;
+ event_xy[0] = 2 * event->x - event->prevx;
+ event_xy[1] = 2 * event->y - event->prevy;
}
else {
- x = event->prevx;
- y = event->prevy;
+ event_xy[0] = event->prevx;
+ event_xy[1] = event->prevy;
}
}
else {
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
- x = event->prevx;
- y = event->y;
+ event_xy[0] = event->prevx;
+ event_xy[1] = event->y;
}
- viewrotate_apply(vod, x, y);
+ viewrotate_apply(vod, event_xy);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -1361,13 +983,17 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
+
+ view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT);
}
-#ifdef WITH_INPUT_NDOF
+/** \} */
+/* -------------------------------------------------------------------- */
/** \name NDOF Utility Functions
* \{ */
+#ifdef WITH_INPUT_NDOF
#define NDOF_HAS_TRANSLATE ((!ED_view3d_offset_lock_check(v3d, rv3d)) && !is_zero_v3(ndof->tvec))
#define NDOF_HAS_ROTATE (((rv3d->viewlock & RV3D_LOCKED) == 0) && !is_zero_v3(ndof->rvec))
@@ -1417,8 +1043,9 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d)
*
* \param has_zoom zoom, otherwise dolly, often `!rv3d->is_persp` since it doesnt make sense to dolly in ortho.
*/
-static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar,
- const bool has_translate, const bool has_zoom)
+static void view3d_ndof_pan_zoom(
+ const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar,
+ const bool has_translate, const bool has_zoom)
{
RegionView3D *rv3d = ar->regiondata;
float view_inv[4];
@@ -1479,9 +1106,10 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *s
}
-static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar,
- /* optional, can be NULL*/
- ViewOpsData *vod)
+static void view3d_ndof_orbit(
+ const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar,
+ /* optional, can be NULL*/
+ ViewOpsData *vod)
{
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
@@ -1490,7 +1118,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa,
BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
- view3d_ensure_persp(v3d, ar);
+ ED_view3d_persp_ensure(v3d, ar);
rv3d->view = RV3D_VIEW_USER;
@@ -1525,7 +1153,6 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa,
axis_angle_to_quat_single(quat, 'Z', angle);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
-
}
else {
float quat[4];
@@ -1666,14 +1293,16 @@ void view3d_ndof_fly(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operators
+ *
+ * - "orbit" navigation (trackball/turntable)
+ * - zooming
+ * - panning in rotationally-locked views
+ * \{ */
-/* -- "orbit" navigation (trackball/turntable)
- * -- zooming
- * -- panning in rotationally-locked views
- */
static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
-
if (event->type != NDOF_MOTION) {
return OPERATOR_CANCELLED;
}
@@ -1685,9 +1314,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const wmNDOFMotionData *ndof = event->customdata;
viewops_data_alloc(C, op);
- viewops_data_create_ex(
+ viewops_data_create(
C, op, event,
- false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
+ viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -1742,7 +1371,6 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot)
static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
-
if (event->type != NDOF_MOTION) {
return OPERATOR_CANCELLED;
}
@@ -1754,9 +1382,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const wmNDOFMotionData *ndof = event->customdata;
viewops_data_alloc(C, op);
- viewops_data_create_ex(
+ viewops_data_create(
C, op, event,
- false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
+ viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
vod = op->customdata;
@@ -1934,8 +1562,11 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
#endif /* WITH_INPUT_NDOF */
-/* ************************ viewmove ******************************** */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name View Move (Pan) Operator
+ * \{ */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
@@ -1944,7 +1575,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
-
+
{VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
@@ -1968,7 +1599,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
#endif
-
+
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
}
@@ -1977,13 +1608,13 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
static void viewmove_apply(ViewOpsData *vod, int x, int y)
{
if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) {
- vod->rv3d->ofs_lock[0] -= ((vod->oldx - x) * 2.0f) / (float)vod->ar->winx;
- vod->rv3d->ofs_lock[1] -= ((vod->oldy - y) * 2.0f) / (float)vod->ar->winy;
+ vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->ar->winx;
+ vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->ar->winy;
}
else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
- vod->rv3d->camdx += (vod->oldx - x) / (vod->ar->winx * zoomfac);
- vod->rv3d->camdy += (vod->oldy - y) / (vod->ar->winy * zoomfac);
+ vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->ar->winx * zoomfac);
+ vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->ar->winy * zoomfac);
CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
}
@@ -1991,18 +1622,19 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
float dvec[3];
float mval_f[2];
- mval_f[0] = x - vod->oldx;
- mval_f[1] = y - vod->oldy;
- ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->zfac);
+ mval_f[0] = x - vod->prev.event_xy[0];
+ mval_f[1] = y - vod->prev.event_xy[1];
+ ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->init.zfac);
add_v3_v3(vod->rv3d->ofs, dvec);
- if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+ if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->sa, vod->ar);
+ }
}
- vod->oldx = x;
- vod->oldy = y;
+ vod->prev.event_xy[0] = x;
+ vod->prev.event_xy[1] = y;
ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
@@ -2037,7 +1669,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- else if (event->type == vod->origkey && event->val == KM_RELEASE) {
+ else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
@@ -2068,9 +1700,14 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
+
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event, false);
+ viewops_data_create(
+ C, op, event,
+ viewops_flag_from_prefs() |
+ (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2079,9 +1716,9 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* invert it, trackpad scroll follows same principle as 2d windows this way */
viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
ED_view3d_depth_tag_update(vod->rv3d);
-
+
viewops_data_free(C, op);
-
+
return OPERATOR_FINISHED;
}
else {
@@ -2113,9 +1750,16 @@ void VIEW3D_OT_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
+
+ /* properties */
+ view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT);
}
-/* ************************ viewzoom ******************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
/* viewdolly_modal_keymap has an exact copy of this, apply fixes to both */
/* called in transform_ops.c, on each regeneration of keymaps */
@@ -2123,7 +1767,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
-
+
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
@@ -2147,14 +1791,17 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
#endif
-
+
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
}
-static void view_zoom_mouseloc_camera(
- Scene *scene, View3D *v3d,
- ARegion *ar, float dfac, int mx, int my)
+/**
+ * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL.
+ */
+static void view_zoom_to_window_xy_camera(
+ Scene *scene, const Depsgraph *depsgraph, View3D *v3d,
+ ARegion *ar, float dfac, const int zoom_xy[2])
{
RegionView3D *rv3d = ar->regiondata;
const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
@@ -2162,22 +1809,22 @@ static void view_zoom_mouseloc_camera(
const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new);
- if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
+ if (zoom_xy != NULL) {
float zoomfac_px;
rctf camera_frame_old;
rctf camera_frame_new;
- const float pt_src[2] = {mx, my};
+ const float pt_src[2] = {zoom_xy[0], zoom_xy[1]};
float pt_dst[2];
float delta_px[2];
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_old, false);
BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin);
rv3d->camzoom = camzoom_new;
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_new, false);
BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin);
BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
@@ -2198,12 +1845,15 @@ static void view_zoom_mouseloc_camera(
}
}
-static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my)
+/**
+ * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL.
+ */
+static void view_zoom_to_window_xy_3d(ARegion *ar, float dfac, const int zoom_xy[2])
{
RegionView3D *rv3d = ar->regiondata;
const float dist_new = rv3d->dist * dfac;
- if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
+ if (zoom_xy != NULL) {
float dvec[3];
float tvec[3];
float tpos[3];
@@ -2213,8 +1863,8 @@ static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my)
negate_v3_v3(tpos, rv3d->ofs);
- mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f;
- mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f;
+ mval_f[0] = (float)(((zoom_xy[0] - ar->winrct.xmin) * 2) - ar->winx) / 2.0f;
+ mval_f[1] = (float)(((zoom_xy[1] - ar->winrct.ymin) * 2) - ar->winy) / 2.0f;
/* Project cursor position into 3D space */
zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL);
@@ -2240,7 +1890,7 @@ static float viewzoom_scale_value(
const rcti *winrct,
const short viewzoom,
const bool zoom_invert, const bool zoom_invert_force,
- const int xy[2], const int xy_orig[2],
+ const int xy_curr[2], const int xy_init[2],
const float val, const float val_orig,
double *r_timer_lastdraw)
{
@@ -2252,10 +1902,10 @@ static float viewzoom_scale_value(
float fac;
if (U.uiflag & USER_ZOOM_HORIZ) {
- fac = (float)(xy_orig[0] - xy[0]);
+ fac = (float)(xy_init[0] - xy_curr[0]);
}
else {
- fac = (float)(xy_orig[1] - xy[1]);
+ fac = (float)(xy_init[1] - xy_curr[1]);
}
if (zoom_invert != zoom_invert_force) {
@@ -2273,8 +1923,8 @@ static float viewzoom_scale_value(
BLI_rcti_cent_x(winrct),
BLI_rcti_cent_y(winrct),
};
- float len_new = 5 + len_v2v2_int(ctr, xy);
- float len_old = 5 + len_v2v2_int(ctr, xy_orig);
+ float len_new = 5 + len_v2v2_int(ctr, xy_curr);
+ float len_old = 5 + len_v2v2_int(ctr, xy_init);
/* intentionally ignore 'zoom_invert' for scale */
if (zoom_invert_force) {
@@ -2288,12 +1938,12 @@ static float viewzoom_scale_value(
float len_old = 5;
if (U.uiflag & USER_ZOOM_HORIZ) {
- len_new += (winrct->xmax - xy[0]);
- len_old += (winrct->xmax - xy_orig[0]);
+ len_new += (winrct->xmax - (xy_curr[0]));
+ len_old += (winrct->xmax - (xy_init[0]));
}
else {
- len_new += (winrct->ymax - xy[1]);
- len_old += (winrct->ymax - xy_orig[1]);
+ len_new += (winrct->ymax - (xy_curr[1]));
+ len_old += (winrct->ymax - (xy_init[1]));
}
if (zoom_invert != zoom_invert_force) {
@@ -2307,25 +1957,48 @@ static float viewzoom_scale_value(
return zfac;
}
+static float viewzoom_scale_value_offset(
+ const rcti *winrct,
+ const short viewzoom,
+ const bool zoom_invert, const bool zoom_invert_force,
+ const int xy_curr[2], const int xy_init[2], const int xy_offset[2],
+ const float val, const float val_orig,
+ double *r_timer_lastdraw)
+{
+ const int xy_curr_offset[2] = {
+ xy_curr[0] + xy_offset[0],
+ xy_curr[1] + xy_offset[1],
+ };
+ const int xy_init_offset[2] = {
+ xy_init[0] + xy_offset[0],
+ xy_init[1] + xy_offset[1],
+ };
+ return viewzoom_scale_value(
+ winrct, viewzoom, zoom_invert, zoom_invert_force,
+ xy_curr_offset, xy_init_offset,
+ val, val_orig, r_timer_lastdraw);
+}
+
static void viewzoom_apply_camera(
ViewOpsData *vod, const int xy[2],
- const short viewzoom, const bool zoom_invert)
+ const short viewzoom, const bool zoom_invert, const bool zoom_to_pos)
{
float zfac;
- float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f;
+ float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f;
float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
- zfac = viewzoom_scale_value(
- &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx,
+ zfac = viewzoom_scale_value_offset(
+ &vod->ar->winrct, viewzoom, zoom_invert, true,
+ xy, vod->init.event_xy, vod->init.event_xy_offset,
zoomfac, zoomfac_prev,
- &vod->timer_lastdraw);
+ &vod->prev.time);
if (zfac != 1.0f && zfac != 0.0f) {
/* calculate inverted, then invert again (needed because of camera zoom scaling) */
zfac = 1.0f / zfac;
- view_zoom_mouseloc_camera(
- vod->scene, vod->v3d,
- vod->ar, zfac, vod->oldx, vod->oldy);
+ view_zoom_to_window_xy_camera(
+ vod->scene, vod->depsgraph, vod->v3d,
+ vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL);
}
ED_region_tag_redraw(vod->ar);
@@ -2333,32 +2006,34 @@ static void viewzoom_apply_camera(
static void viewzoom_apply_3d(
ViewOpsData *vod, const int xy[2],
- const short viewzoom, const bool zoom_invert)
+ const short viewzoom, const bool zoom_invert, const bool zoom_to_pos)
{
float zfac;
float dist_range[2];
ED_view3d_dist_range_get(vod->v3d, dist_range);
- zfac = viewzoom_scale_value(
- &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx,
- vod->rv3d->dist, vod->dist_prev,
- &vod->timer_lastdraw);
+ zfac = viewzoom_scale_value_offset(
+ &vod->ar->winrct, viewzoom, zoom_invert, false,
+ xy, vod->init.event_xy, vod->init.event_xy_offset,
+ vod->rv3d->dist, vod->init.dist,
+ &vod->prev.time);
if (zfac != 1.0f) {
const float zfac_min = dist_range[0] / vod->rv3d->dist;
const float zfac_max = dist_range[1] / vod->rv3d->dist;
CLAMP(zfac, zfac_min, zfac_max);
- view_zoom_mouseloc_3d(
- vod->ar, zfac, vod->oldx, vod->oldy);
+ view_zoom_to_window_xy_3d(
+ vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL);
}
/* these limits were in old code too */
CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
- if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+ if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->sa, vod->ar);
+ }
ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
@@ -2367,15 +2042,15 @@ static void viewzoom_apply_3d(
static void viewzoom_apply(
ViewOpsData *vod, const int xy[2],
- const short viewzoom, const bool zoom_invert)
+ const short viewzoom, const bool zoom_invert, const bool zoom_to_pos)
{
if ((vod->rv3d->persp == RV3D_CAMOB) &&
(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0)
{
- viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert);
+ viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
}
else {
- viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert);
+ viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
}
}
@@ -2409,12 +2084,16 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- else if (event->type == vod->origkey && event->val == KM_RELEASE) {
+ else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
if (event_code == VIEW_APPLY) {
- viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
+ viewzoom_apply(
+ vod, &event->x, U.viewzoom,
+ (U.uiflag & USER_ZOOM_INVERT) != 0,
+ (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) ? vod->prev.event_xy : NULL);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -2438,6 +2117,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int viewzoom_exec(bContext *C, wmOperator *op)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
@@ -2447,7 +2127,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
float dist_range[2];
const int delta = RNA_int_get(op->ptr, "delta");
- int mx, my;
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
if (op->customdata) {
ViewOpsData *vod = op->customdata;
@@ -2463,39 +2143,46 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
v3d = sa->spacedata.first;
rv3d = ar->regiondata;
- mx = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2;
- my = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2;
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d));
+ int zoom_xy_buf[2];
+ const int *zoom_xy = NULL;
+ if (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
+ zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2;
+ zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2;
+ zoom_xy = zoom_xy_buf;
+ }
+
ED_view3d_dist_range_get(v3d, dist_range);
if (delta < 0) {
const float step = 1.2f;
/* this min and max is also in viewmove() */
if (use_cam_zoom) {
- view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
+ view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy);
}
else {
if (rv3d->dist < dist_range[1]) {
- view_zoom_mouseloc_3d(ar, step, mx, my);
+ view_zoom_to_window_xy_3d(ar, step, zoom_xy);
}
}
}
else {
const float step = 1.0f / 1.2f;
if (use_cam_zoom) {
- view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
+ view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy);
}
else {
if (rv3d->dist > dist_range[0]) {
- view_zoom_mouseloc_3d(ar, step, mx, my);
+ view_zoom_to_window_xy_3d(ar, step, zoom_xy);
}
}
}
- if (rv3d->viewlock & RV3D_BOXVIEW)
+ if (rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(sa, ar);
+ }
ED_view3d_depth_tag_update(rv3d);
@@ -2509,49 +2196,19 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* this is an exact copy of viewzoom_modal_keymap */
-/* called in transform_ops.c, on each regeneration of keymaps */
-void viewdolly_modal_keymap(wmKeyConfig *keyconf)
-{
- static const EnumPropertyItem modal_items[] = {
- {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
-
- {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
- {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
-
- {0, NULL, 0, NULL, NULL}
- };
-
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal");
-
- /* this function is called for each spacetype, only needs to add map once */
- if (keymap && keymap->modal_items) return;
-
- keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items);
-
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
-
- /* disabled mode switching for now, can re-implement better, later on */
-#if 0
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
-#endif
-
- /* assign map to operators */
- WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly");
-}
-
/* viewdolly_invoke() copied this function, changes here may apply there */
static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
+
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event, false);
+ viewops_data_create(
+ C, op, event,
+ viewops_flag_from_prefs() |
+ (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2569,14 +2226,16 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
if (U.uiflag & USER_ZOOM_HORIZ) {
- vod->origx = vod->oldx = event->x;
- viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
- vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
- viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx;
}
+ viewzoom_apply(
+ vod, &event->prevx, USER_ZOOM_DOLLY,
+ (U.uiflag & USER_ZOOM_INVERT) != 0,
+ (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
@@ -2588,7 +2247,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (U.viewzoom == USER_ZOOM_CONT) {
/* needs a timer to continue redrawing */
vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
- vod->timer_lastdraw = PIL_check_seconds_timer();
+ vod->prev.time = PIL_check_seconds_timer();
}
/* add temp handler */
@@ -2607,8 +2266,6 @@ static void viewzoom_cancel(bContext *C, wmOperator *op)
void VIEW3D_OT_zoom(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Zoom View";
ot->description = "Zoom in/out in the view";
@@ -2624,15 +2281,56 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
- RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
- prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ /* properties */
+ view3d_operator_properties_common(
+ ot,
+ V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Dolly Operator
+ *
+ * Like zoom but translates the view offset along the view direction
+ * which avoids #RegionView3D.dist approaching zero.
+ * \{ */
+
+/* this is an exact copy of viewzoom_modal_keymap */
+/* called in transform_ops.c, on each regeneration of keymaps */
+void viewdolly_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items[] = {
+ {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
+
+ {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
+ {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
+
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal");
+
+ /* this function is called for each spacetype, only needs to add map once */
+ if (keymap && keymap->modal_items) return;
+
+ keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
+
+ /* disabled mode switching for now, can re-implement better, later on */
+#if 0
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
+#endif
+
+ /* assign map to operators */
+ WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly");
+}
-/* ************************ viewdolly ******************************** */
static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
{
View3D *v3d = CTX_wm_view3d(C);
@@ -2646,13 +2344,13 @@ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
}
}
-static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac)
+static void view_dolly_to_vector_3d(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac)
{
RegionView3D *rv3d = ar->regiondata;
madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac));
}
-static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_invert)
+static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_invert)
{
float zfac = 1.0;
@@ -2660,24 +2358,27 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv
float len1, len2;
if (U.uiflag & USER_ZOOM_HORIZ) {
- len1 = (vod->ar->winrct.xmax - x) + 5;
- len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
+ len1 = (vod->ar->winrct.xmax - xy[0]) + 5;
+ len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) + 5;
}
else {
- len1 = (vod->ar->winrct.ymax - y) + 5;
- len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
+ len1 = (vod->ar->winrct.ymax - xy[1]) + 5;
+ len2 = (vod->ar->winrct.ymax - vod->init.event_xy[1]) + 5;
}
- if (zoom_invert)
+ if (zoom_invert) {
SWAP(float, len1, len2);
+ }
zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist);
}
- if (zfac != 1.0f)
- view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac);
+ if (zfac != 1.0f) {
+ view_dolly_to_vector_3d(vod->ar, vod->init.ofs, vod->init.mousevec, zfac);
+ }
- if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+ if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->sa, vod->ar);
+ }
ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
@@ -2711,12 +2412,12 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- else if (event->type == vod->origkey && event->val == KM_RELEASE) {
+ else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
if (event_code == VIEW_APPLY) {
- viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ viewdolly_apply(vod, &event->x, (U.uiflag & USER_ZOOM_INVERT) != 0);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -2753,7 +2454,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
sa = vod->sa;
ar = vod->ar;
- copy_v3_v3(mousevec, vod->mousevec);
+ copy_v3_v3(mousevec, vod->init.mousevec);
}
else {
sa = CTX_wm_area(C);
@@ -2765,20 +2466,18 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
v3d = sa->spacedata.first;
rv3d = ar->regiondata;
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
+
/* overwrite the mouse vector with the view direction (zoom into the center) */
- if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) {
+ if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
normalize_v3_v3(mousevec, rv3d->viewinv[2]);
}
- if (delta < 0) {
- view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 0.2f);
- }
- else {
- view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.8f);
- }
+ view_dolly_to_vector_3d(ar, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f);
- if (rv3d->viewlock & RV3D_BOXVIEW)
+ if (rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(sa, ar);
+ }
ED_view3d_depth_tag_update(rv3d);
@@ -2816,7 +2515,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (vod->rv3d->persp != RV3D_PERSP) {
if (vod->rv3d->persp == RV3D_CAMOB) {
/* ignore rv3d->lpersp because dolly only makes sense in perspective mode */
- view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP);
+ ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP);
}
else {
vod->rv3d->persp = RV3D_PERSP;
@@ -2824,7 +2523,12 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(vod->ar);
}
- viewops_data_create(C, op, event, false);
+ const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init");
+
+ viewops_data_create(
+ C, op, event,
+ viewops_flag_from_prefs() |
+ (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
/* if one or the other zoom position aren't set, set from event */
@@ -2838,24 +2542,22 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* overwrite the mouse vector with the view direction (zoom into the center) */
- if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) {
- negate_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]);
- normalize_v3(vod->mousevec);
+ if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
+ negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]);
+ normalize_v3(vod->init.mousevec);
}
if (event->type == MOUSEZOOM) {
/* Bypass Zoom invert flag for track pads (pass false always) */
if (U.uiflag & USER_ZOOM_HORIZ) {
- vod->origx = vod->oldx = event->x;
- viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0);
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
}
else {
-
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
- vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
- viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0);
+ vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx;
}
+ viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -2893,14 +2595,23 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
- RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
- RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
+ /* properties */
+ view3d_operator_properties_common(
+ ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
}
-static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
- const float min[3], const float max[3],
- bool ok_dist, const int smooth_viewtx)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ *
+ * Move & Zoom the view to fit all of it's contents.
+ * \{ */
+
+static void view3d_from_minmax(
+ bContext *C, View3D *v3d, ARegion *ar,
+ const float min[3], const float max[3],
+ bool ok_dist, const int smooth_viewtx)
{
RegionView3D *rv3d = ar->regiondata;
float afm[3];
@@ -2966,10 +2677,13 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
/* smooth view does viewlock RV3D_BOXVIEW copy */
}
-/* same as view3d_from_minmax but for all regions (except cameras) */
-static void view3d_from_minmax_multi(bContext *C, View3D *v3d,
- const float min[3], const float max[3],
- const bool ok_dist, const int smooth_viewtx)
+/**
+ * Same as #view3d_from_minmax but for all regions (except cameras).
+ */
+static void view3d_from_minmax_multi(
+ bContext *C, View3D *v3d,
+ const float min[3], const float max[3],
+ const bool ok_dist, const int smooth_viewtx)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar;
@@ -2985,7 +2699,7 @@ static void view3d_from_minmax_multi(bContext *C, View3D *v3d,
}
}
-static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
+static int view3d_all_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -3050,8 +2764,6 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in
void VIEW3D_OT_view_all(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "View All";
ot->description = "View all objects in scene";
@@ -3064,11 +2776,19 @@ void VIEW3D_OT_view_all(wmOperatorType *ot)
/* flags */
ot->flag = 0;
- prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* properties */
+ view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS);
RNA_def_boolean(ot->srna, "center", 0, "Center", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ *
+ * Move & Zoom the view to fit selected contents.
+ * \{ */
+
/* like a localview without local!, was centerview() in 2.4x */
static int viewselected_exec(bContext *C, wmOperator *op)
{
@@ -3180,8 +2900,6 @@ static int viewselected_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_view_selected(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "View Selected";
ot->description = "Move the view to the selection center";
@@ -3194,17 +2912,22 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot)
/* flags */
ot->flag = 0;
- /* rna later */
- prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* properties */
+ view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Lock Clear Operator
+ * \{ */
+
static int view_lock_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
View3D *v3d = CTX_wm_view3d(C);
if (v3d) {
- ED_view3D_lock_clear(v3d);
+ ED_view3d_lock_clear(v3d);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
@@ -3231,6 +2954,12 @@ void VIEW3D_OT_view_lock_clear(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Lock to Active Operator
+ * \{ */
+
static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
{
View3D *v3d = CTX_wm_view3d(C);
@@ -3238,7 +2967,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
if (v3d) {
- ED_view3D_lock_clear(v3d);
+ ED_view3d_lock_clear(v3d);
v3d->ob_centre = obact; /* can be NULL */
@@ -3282,12 +3011,18 @@ void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Center Cursor Operator
+ * \{ */
+
static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
{
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
Scene *scene = CTX_data_scene(C);
-
+
if (rv3d) {
ARegion *ar = CTX_wm_region(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
@@ -3303,7 +3038,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
/* smooth view does viewlock RV3D_BOXVIEW copy */
}
-
+
return OPERATOR_FINISHED;
}
@@ -3313,15 +3048,21 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
ot->name = "Center View to Cursor";
ot->description = "Center the view so that the cursor is in the middle of the view";
ot->idname = "VIEW3D_OT_view_center_cursor";
-
+
/* api callbacks */
ot->exec = viewcenter_cursor_exec;
ot->poll = ED_operator_view3d_active;
-
+
/* flags */
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Center Pick Operator
+ * \{ */
+
static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
View3D *v3d = CTX_wm_view3d(C);
@@ -3372,8 +3113,15 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Camera Center Operator
+ * \{ */
+
static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
float xfac, yfac;
float size[2];
@@ -3388,7 +3136,7 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was
rv3d->camdx = rv3d->camdy = 0.0f;
- ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size);
+ ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size);
/* 4px is just a little room from the edge of the area */
xfac = (float)ar->winx / (float)(size[0] + 4);
@@ -3417,6 +3165,12 @@ void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Lock Center Operator
+ * \{ */
+
static int view3d_center_lock_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -3443,10 +3197,15 @@ void VIEW3D_OT_view_center_lock(wmOperatorType *ot)
ot->flag = 0;
}
-/* ********************* Set render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Render Border Operator
+ * \{ */
static int render_border_exec(bContext *C, wmOperator *op)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
@@ -3467,7 +3226,7 @@ static int render_border_exec(bContext *C, wmOperator *op)
/* calculate range */
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
}
else {
vb.xmin = 0;
@@ -3513,7 +3272,6 @@ static int render_border_exec(bContext *C, wmOperator *op)
}
return OPERATOR_FINISHED;
-
}
void VIEW3D_OT_render_border(wmOperatorType *ot)
@@ -3536,7 +3294,7 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* rna */
+ /* properties */
WM_operator_properties_border(ot);
prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only",
@@ -3544,7 +3302,11 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/* ********************* Clear render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Border Operator
+ * \{ */
static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3573,7 +3335,6 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
border->ymax = 1.0f;
return OPERATOR_FINISHED;
-
}
void VIEW3D_OT_clear_render_border(wmOperatorType *ot)
@@ -3591,7 +3352,11 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************* Border Zoom operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Border Zoom Operator
+ * \{ */
static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
{
@@ -3612,7 +3377,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* ZBuffer depth vars */
float depth_close = FLT_MAX;
- float p[3];
+ float cent[2], p[3];
/* note; otherwise opengl won't work */
view3d_operator_needs_opengl(C);
@@ -3629,22 +3394,22 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* Get Z Depths, needed for perspective, nice for ortho */
ED_view3d_draw_depth(&eval_ctx, CTX_data_depsgraph(C), ar, v3d, true);
-
+
{
/* avoid allocating the whole depth buffer */
ViewDepths depth_temp = {0};
/* avoid view3d_update_depths() for speed. */
view3d_update_depths_rect(ar, &depth_temp, &rect);
-
+
/* find the closest Z pixel */
depth_close = view3d_depth_near(&depth_temp);
-
+
MEM_SAFE_FREE(depth_temp.depths);
}
- float centx = (((float)rect.xmin) + ((float)rect.xmax)) / 2;
- float centy = (((float)rect.ymin) + ((float)rect.ymax)) / 2;
+ cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2;
+ cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2;
if (rv3d->is_persp) {
float p_corner[3];
@@ -3655,7 +3420,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* convert border to 3d coordinates */
- if ((!ED_view3d_unproject(ar, centx, centy, depth_close, p)) ||
+ if ((!ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) ||
(!ED_view3d_unproject(ar, rect.xmin, rect.ymin, depth_close, p_corner)))
{
return OPERATOR_CANCELLED;
@@ -3677,7 +3442,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
new_dist = rv3d->dist;
/* convert the drawn rectangle into 3d space */
- if (depth_close != FLT_MAX && ED_view3d_unproject(ar, centx, centy, depth_close, p)) {
+ if (depth_close != FLT_MAX && ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) {
negate_v3_v3(new_ofs, p);
}
else {
@@ -3719,8 +3484,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
C, v3d, ar, smooth_viewtx,
&(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist});
- if (rv3d->viewlock & RV3D_BOXVIEW)
+ if (rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(CTX_wm_area(C), ar);
+ }
return OPERATOR_FINISHED;
}
@@ -3755,18 +3521,25 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
/* flags */
ot->flag = 0;
- /* rna */
+ /* properties */
WM_operator_properties_gesture_border_zoom(ot);
}
-/* sets the view to 1:1 camera/render-pixel */
-static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Camera Zoom 1:1 Operator
+ *
+ * Sets the view to 1:1 camera/render-pixel.
+ * \{ */
+
+static void view3d_set_1_to_1_viewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d)
{
RegionView3D *rv3d = ar->regiondata;
float size[2];
int im_width = (scene->r.size * scene->r.xsch) / 100;
-
- ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size);
+
+ ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size);
rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]);
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
@@ -3774,6 +3547,7 @@ static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d)
static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op))
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d;
@@ -3782,7 +3556,7 @@ static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op))
/* no NULL check is needed, poll checks */
ED_view3d_context_user_region(C, &v3d, &ar);
- view3d_set_1_to_1_viewborder(scene, ar, v3d);
+ view3d_set_1_to_1_viewborder(scene, depsgraph, ar, v3d);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
@@ -3804,7 +3578,11 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot)
ot->flag = 0;
}
-/* ********************* Changing view operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Axis/Type Operator
+ * \{ */
static const EnumPropertyItem prop_view_items[] = {
{RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"},
@@ -3820,10 +3598,11 @@ static const EnumPropertyItem prop_view_items[] = {
/* would like to make this a generic function - outside of transform */
-static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
- const float quat_[4],
- short view, int perspo, bool align_active,
- const int smooth_viewtx)
+static void axis_set_view(
+ bContext *C, View3D *v3d, ARegion *ar,
+ const float quat_[4],
+ short view, int perspo, bool align_active,
+ const int smooth_viewtx)
{
RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */
float quat[4];
@@ -4002,7 +3781,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams) {
.camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat,
.dist = &rv3d->dist, .lens = &v3d->lens});
-
}
else {
/* return to settings of last view */
@@ -4043,6 +3821,14 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Orbit Operator
+ *
+ * Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate.
+ * \{ */
+
static const EnumPropertyItem prop_view_orbit_items[] = {
{V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
{V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
@@ -4086,7 +3872,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
float quat_new[4];
if (view_opposite == RV3D_VIEW_USER) {
- view3d_ensure_persp(v3d, ar);
+ ED_view3d_persp_ensure(v3d, ar);
}
if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
@@ -4157,17 +3943,19 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot)
/* flags */
ot->flag = 0;
-
+
/* properties */
prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
-
}
+/** \} */
-/* ************************ viewroll ******************************** */
+/* -------------------------------------------------------------------- */
+/** \name View Roll Operator
+ * \{ */
static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4], const float dvec[3], float angle)
{
@@ -4194,19 +3982,20 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
tot = vod->ar->winrct.xmax - vod->ar->winrct.xmin;
len1 = (vod->ar->winrct.xmax - x) / tot;
- len2 = (vod->ar->winrct.xmax - vod->origx) / tot;
+ len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) / tot;
angle = (len1 - len2) * (float)M_PI * 4.0f;
}
if (angle != 0.0f)
- view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle);
+ view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle);
if (vod->use_dyn_ofs) {
- view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs);
+ view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs);
}
- if (vod->rv3d->viewlock & RV3D_BOXVIEW)
+ if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->sa, vod->ar);
+ }
ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
@@ -4239,7 +4028,7 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- else if (event->type == vod->origkey && event->val == KM_RELEASE) {
+ else if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
@@ -4343,17 +4132,17 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event, false);
+ viewops_data_create(C, op, event, viewops_flag_from_prefs());
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
/* overwrite the mouse vector with the view direction */
- normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]);
- negate_v3(vod->mousevec);
+ normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]);
+ negate_v3(vod->init.mousevec);
if (event->type == MOUSEROTATE) {
- vod->origx = vod->oldx = event->x;
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
viewroll_apply(vod, event->prevx, event->prevy);
ED_view3d_depth_tag_update(vod->rv3d);
@@ -4409,6 +4198,14 @@ static const EnumPropertyItem prop_view_pan_items[] = {
{0, NULL, 0, NULL, NULL}
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ *
+ * Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move.
+ * \{ */
+
static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int x = 0, y = 0;
@@ -4420,10 +4217,10 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else if (pandir == V3D_VIEW_PANDOWN) { y = 25; }
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event, false);
+ viewops_data_create(C, op, event, viewops_flag_from_prefs());
ViewOpsData *vod = op->customdata;
- viewmove_apply(vod, vod->oldx + x, vod->oldy + y);
+ viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -4444,11 +4241,17 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
/* flags */
ot->flag = 0;
-
+
/* Properties */
ot->prop = RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Toggle Perspective/Orthographic Operator
+ * \{ */
+
static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op))
{
View3D *v3d_dummy;
@@ -4467,7 +4270,6 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op))
}
return OPERATOR_FINISHED;
-
}
void VIEW3D_OT_view_persportho(wmOperatorType *ot)
@@ -4485,6 +4287,14 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot)
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Navigate Operator
+ *
+ * Wraps walk/fly modes.
+ * \{ */
+
static int view3d_navigate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
eViewNavigation_Method mode = U.navigation_mode;
@@ -4514,8 +4324,11 @@ void VIEW3D_OT_navigate(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
}
+/** \} */
-/* ******************** add background image operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name Background Image Add Operator
+ * \{ */
static CameraBGImage *background_image_add(bContext *C)
{
@@ -4536,7 +4349,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven
Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
Image *ima;
CameraBGImage *bgpic;
-
+
ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
/* may be NULL, continue anyway */
@@ -4566,7 +4379,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
WM_operator_properties_filesel(
@@ -4574,8 +4387,12 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Background Image Remove Operator
+ * \{ */
-/* ***** remove image operator ******* */
static int background_image_remove_exec(bContext *C, wmOperator *op)
{
Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
@@ -4593,13 +4410,11 @@ static int background_image_remove_exec(bContext *C, wmOperator *op)
BKE_camera_background_image_remove(cam, bgpic_rem);
WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
-
return OPERATOR_FINISHED;
}
else {
return OPERATOR_CANCELLED;
}
-
}
void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
@@ -4615,12 +4430,18 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* flags */
ot->flag = 0;
-
+
/* properties */
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove", 0, INT_MAX);
}
-/* ********************* set clipping operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Clipping Planes Operator
+ *
+ * Draw border or toggle off.
+ * \{ */
static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float mat[4][4])
{
@@ -4677,7 +4498,6 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
}
-/* toggles */
void VIEW3D_OT_clip_border(wmOperatorType *ot)
{
@@ -4697,11 +4517,15 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
/* flags */
ot->flag = 0;
- /* rna */
+ /* properties */
WM_operator_properties_border(ot);
}
-/* ***************** 3d cursor cursor op ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Cursor Operator
+ * \{ */
/* cursor position in vec, result in vec, mval in region coords */
/* note: cannot use event->mval here (called by object_add() */
@@ -4712,14 +4536,14 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
RegionView3D *rv3d = ar->regiondata;
bool flip;
bool depth_used = false;
-
+
/* normally the caller should ensure this,
* but this is called from areas that aren't already dealing with the viewport */
if (rv3d == NULL)
return;
ED_view3d_calc_zfac(rv3d, fp, &flip);
-
+
/* reset the depth based on the view offset (we _know_ the offset is infront of us) */
if (flip) {
negate_v3_v3(fp, rv3d->ofs);
@@ -4727,7 +4551,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ );
}
- if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */
+ if (U.uiflag & USER_DEPTH_CURSOR) { /* maybe this should be accessed some other way */
EvaluationContext eval_ctx;
struct Depsgraph *graph = CTX_data_depsgraph(C);
@@ -4808,26 +4632,27 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* flags */
// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* rna later */
-
}
-/* ***************** manipulator op ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Enable Transform Manipulator Operator
+ * \{ */
static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
View3D *v3d = CTX_wm_view3d(C);
v3d->twtype = 0;
-
+
if (RNA_boolean_get(op->ptr, "translate"))
v3d->twtype |= V3D_MANIP_TRANSLATE;
if (RNA_boolean_get(op->ptr, "rotate"))
v3d->twtype |= V3D_MANIP_ROTATE;
if (RNA_boolean_get(op->ptr, "scale"))
v3d->twtype |= V3D_MANIP_SCALE;
-
+
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
@@ -4841,12 +4666,12 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
ot->name = "Enable 3D Manipulator";
ot->description = "Enable the transform manipulator for use";
ot->idname = "VIEW3D_OT_enable_manipulator";
-
+
/* api callbacks */
ot->invoke = enable_manipulator_invoke;
ot->poll = ED_operator_view3d_active;
-
- /* rna later */
+
+ /* properties */
prop = RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
@@ -4855,7 +4680,11 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ************************* Toggle rendered shading *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Render Shading Operator
+ * \{ */
static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -4884,315 +4713,4 @@ void VIEW3D_OT_toggle_render(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
}
-/* ************************* below the line! *********************** */
-
-
-static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin)
-{
- ViewDepths depth_temp = {0};
- rcti rect;
- float depth_close;
-
- if (margin == 0) {
- /* Get Z Depths, needed for perspective, nice for ortho */
- rect.xmin = mval[0];
- rect.ymin = mval[1];
- rect.xmax = mval[0] + 1;
- rect.ymax = mval[1] + 1;
- }
- else {
- BLI_rcti_init_pt_radius(&rect, mval, margin);
- }
-
- view3d_update_depths_rect(ar, &depth_temp, &rect);
- depth_close = view3d_depth_near(&depth_temp);
- MEM_SAFE_FREE(depth_temp.depths);
- return depth_close;
-}
-
-/**
- * Get the world-space 3d location from a screen-space 2d point.
- *
- * \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space location.
- * \param fallback_depth_pt: Use this points depth when no depth can be found.
- */
-bool ED_view3d_autodist(
- const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d,
- const int mval[2], float mouse_worldloc[3],
- const bool alphaoverride, const float fallback_depth_pt[3])
-{
- float depth_close;
- int margin_arr[] = {0, 2, 4};
- int i;
- bool depth_ok = false;
-
- /* Get Z Depths, needed for perspective, nice for ortho */
- ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride);
-
- /* Attempt with low margin's first */
- i = 0;
- do {
- depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
- depth_ok = (depth_close != FLT_MAX);
- } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
-
- if (depth_ok) {
- float centx = (float)mval[0] + 0.5f;
- float centy = (float)mval[1] + 0.5f;
-
- if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) {
- return true;
- }
- }
-
- if (fallback_depth_pt) {
- ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
- return true;
- }
- else {
- return false;
- }
-}
-
-void ED_view3d_autodist_init(
- const EvaluationContext *eval_ctx, struct Depsgraph *graph,
- ARegion *ar, View3D *v3d, int mode)
-{
- /* Get Z Depths, needed for perspective, nice for ortho */
- switch (mode) {
- case 0:
- ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true);
- break;
- case 1:
- {
- Scene *scene = DEG_get_evaluated_scene(graph);
- ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d);
- break;
- }
- }
-}
-
-/* no 4x4 sampling, run #ED_view3d_autodist_init first */
-bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3],
- int margin, float *force_depth)
-{
- float depth;
-
- /* Get Z Depths, needed for perspective, nice for ortho */
- if (force_depth)
- depth = *force_depth;
- else
- depth = view_autodist_depth_margin(ar, mval, margin);
-
- if (depth == FLT_MAX)
- return false;
-
- float centx = (float)mval[0] + 0.5f;
- float centy = (float)mval[1] + 0.5f;
- return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc);
-}
-
-bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
-{
- *depth = view_autodist_depth_margin(ar, mval, margin);
-
- return (*depth != FLT_MAX);
-}
-
-static bool depth_segment_cb(int x, int y, void *userData)
-{
- struct { ARegion *ar; int margin; float depth; } *data = userData;
- int mval[2];
- float depth;
-
- mval[0] = x;
- mval[1] = y;
-
- depth = view_autodist_depth_margin(data->ar, mval, data->margin);
-
- if (depth != FLT_MAX) {
- data->depth = depth;
- return 0;
- }
- else {
- return 1;
- }
-}
-
-bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int mval_end[2],
- int margin, float *depth)
-{
- struct { ARegion *ar; int margin; float depth; } data = {NULL};
- int p1[2];
- int p2[2];
-
- data.ar = ar;
- data.margin = margin;
- data.depth = FLT_MAX;
-
- copy_v2_v2_int(p1, mval_sta);
- copy_v2_v2_int(p2, mval_end);
-
- BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
-
- *depth = data.depth;
-
- return (*depth != FLT_MAX);
-}
-
-/* problem - ofs[3] can be on same location as camera itself.
- * Blender needs proper dist value for zoom.
- * use fallback_dist to override small values
- */
-float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist)
-{
- float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float dist;
-
- mul_m4_v4(mat, pos);
- add_v3_v3(pos, ofs);
- mul_m4_v4(mat, dir);
- normalize_v3(dir);
-
- dist = dot_v3v3(pos, dir);
-
- if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
- dist = fallback_dist;
- }
-
- return dist;
-}
-
-/**
- * Set the dist without moving the view (compensate with #RegionView3D.ofs)
- *
- * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
- */
-void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
-{
- float viewinv[4];
- float tvec[3];
-
- BLI_assert(dist >= 0.0f);
-
- copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
- /* rv3d->viewinv isn't always valid */
-#if 0
- mul_mat3_m4_v3(rv3d->viewinv, tvec);
-#else
- invert_qt_qt_normalized(viewinv, rv3d->viewquat);
- mul_qt_v3(viewinv, tvec);
-#endif
- sub_v3_v3(rv3d->ofs, tvec);
-
- rv3d->dist = dist;
-}
-
-/**
- * Set the view transformation from a 4x4 matrix.
- *
- * \param mat The view 4x4 transformation matrix to assign.
- * \param ofs The view offset, normally from RegionView3D.ofs.
- * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs, normally from RegionView3D.dist.
- */
-void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist)
-{
- float nmat[3][3];
-
- /* dist depends on offset */
- BLI_assert(dist == NULL || ofs != NULL);
-
- copy_m3_m4(nmat, mat);
- normalize_m3(nmat);
-
- /* Offset */
- if (ofs)
- negate_v3_v3(ofs, mat[3]);
-
- /* Quat */
- if (quat) {
- mat3_normalized_to_quat(quat, nmat);
- invert_qt_normalized(quat);
- }
-
- if (ofs && dist) {
- madd_v3_v3fl(ofs, nmat[2], *dist);
- }
-}
-
-/**
- * Calculate the view transformation matrix from RegionView3D input.
- * The resulting matrix is equivalent to RegionView3D.viewinv
- * \param mat The view 4x4 transformation matrix to calculate.
- * \param ofs The view offset, normally from RegionView3D.ofs.
- * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs, normally from RegionView3D.dist.
- */
-void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
-{
- float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
- float dvec[3] = {0.0f, 0.0f, dist};
-
- quat_to_mat4(mat, iviewquat);
- mul_mat3_m4_v3(mat, dvec);
- sub_v3_v3v3(mat[3], dvec, ofs);
-}
-
-/**
- * Set the RegionView3D members from an objects transformation and optionally lens.
- * \param ob The object to set the view to.
- * \param ofs The view offset to be set, normally from RegionView3D.ofs.
- * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs to be set, normally from RegionView3D.dist.
- * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens.
- */
-void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
-{
- ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
-
- if (lens) {
- CameraParams params;
-
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, ob);
- *lens = params.lens;
- }
-}
-
-/**
- * Set the object transformation from RegionView3D members.
- * \param ob The object which has the transformation assigned.
- * \param ofs The view offset, normally from RegionView3D.ofs.
- * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist The view distance from ofs, normally from RegionView3D.dist.
- */
-void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist)
-{
- float mat[4][4];
-
- ED_view3d_to_m4(mat, ofs, quat, dist);
- BKE_object_apply_mat4(ob, mat, true, true);
-}
-
-/**
- * Use to store the last view, before entering camera view.
- */
-void ED_view3d_lastview_store(RegionView3D *rv3d)
-{
- copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
- rv3d->lview = rv3d->view;
- if (rv3d->persp != RV3D_CAMOB) {
- rv3d->lpersp = rv3d->persp;
- }
-}
-
-void ED_view3D_lock_clear(View3D *v3d)
-{
- v3d->ob_centre = NULL;
- v3d->ob_centre_bone[0] = '\0';
- v3d->ob_centre_cursor = false;
- v3d->flag2 &= ~V3D_LOCK_CAMERA;
-}
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 5e7eddb1c22..d2aa19509d7 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -58,6 +58,8 @@
#include "GPU_immediate.h"
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
@@ -193,6 +195,7 @@ typedef struct FlyInfo {
RegionView3D *rv3d;
View3D *v3d;
ARegion *ar;
+ const struct Depsgraph *depsgraph;
Scene *scene;
wmTimer *timer; /* needed for redraws */
@@ -242,7 +245,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar),
float x1, x2, y1, y2;
if (fly->scene->camera) {
- ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
xoff = viewborder.xmin;
yoff = viewborder.ymin;
}
@@ -343,6 +346,10 @@ enum {
static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ EvaluationContext eval_ctx;
+
+ CTX_data_eval_ctx(C, &eval_ctx);
+
rctf viewborder;
float upvec[3]; /* tmp */
@@ -351,6 +358,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->rv3d = CTX_wm_region_view3d(C);
fly->v3d = CTX_wm_view3d(C);
fly->ar = CTX_wm_region(C);
+ fly->depsgraph = CTX_data_depsgraph(C);
fly->scene = CTX_data_scene(C);
#ifdef NDOF_FLY_DEBUG
@@ -417,12 +425,12 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
}
fly->v3d_camera_control = ED_view3d_cameracontrol_acquire(
- C, fly->scene, fly->v3d, fly->rv3d,
+ &eval_ctx, fly->scene, fly->v3d, fly->rv3d,
(U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
/* calculate center */
if (fly->scene->camera) {
- ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
fly->width = BLI_rctf_size_x(&viewborder);
fly->height = BLI_rctf_size_y(&viewborder);
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index f86f6423f93..d1968166904 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -111,6 +111,7 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_render(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
+void view3d_boxview_sync(ScrArea *sa, ARegion *ar);
void view3d_orbit_apply_dyn_ofs(
float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
@@ -153,7 +154,7 @@ void draw_object_select(
const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, struct ARegion *ar, View3D *v3d,
Base *base, const short dflag);
-void draw_mesh_object_outline(View3D *v3d, Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]);
+void draw_mesh_object_outline(View3D *v3d, struct Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]);
bool draw_glsl_material(Scene *scene, struct ViewLayer *view_layer, struct Object *ob, View3D *v3d, const char dt);
void draw_object_instance(const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline, const float wire_col[4]);
@@ -233,9 +234,6 @@ void ED_view3d_draw_select_loop(
void ED_view3d_draw_depth_loop(
const struct EvaluationContext *eval_ctx, Scene *scene, ARegion *ar, View3D *v3d);
-void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame);
-
void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);
void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect);
@@ -279,8 +277,12 @@ void ED_view3d_smooth_view_force_finish(
struct bContext *C,
struct View3D *v3d, struct ARegion *ar);
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect);
-void view3d_viewmatrix_set(const struct EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d);
+void view3d_winmatrix_set(
+ const struct Depsgraph *depsgraph,
+ ARegion *ar, const View3D *v3d, const rcti *rect);
+void view3d_viewmatrix_set(
+ const struct EvaluationContext *eval_ctx, Scene *scene,
+ const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
@@ -295,7 +297,7 @@ void view3d_buttons_register(struct ARegionType *art);
/* view3d_camera_control.c */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
- const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d,
+ const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root);
void ED_view3d_cameracontrol_update(
struct View3DCameraControl *vctrl,
@@ -304,7 +306,7 @@ void ED_view3d_cameracontrol_update(
void ED_view3d_cameracontrol_release(
struct View3DCameraControl *vctrl,
const bool restore);
-Object *ED_view3d_cameracontrol_object_get(
+struct Object *ED_view3d_cameracontrol_object_get(
struct View3DCameraControl *vctrl);
/* view3d_toolbar.c */
@@ -337,11 +339,14 @@ void VIEW3D_WGT_camera_view(struct wmManipulatorGroupType *wgt);
void VIEW3D_WGT_force_field(struct wmManipulatorGroupType *wgt);
void VIEW3D_WGT_empty_image(struct wmManipulatorGroupType *wgt);
void VIEW3D_WGT_armature_spline(struct wmManipulatorGroupType *wgt);
+void VIEW3D_WGT_navigate(struct wmManipulatorGroupType *wgt);
void VIEW3D_WGT_ruler(struct wmManipulatorGroupType *wgt);
void VIEW3D_WT_ruler_item(struct wmManipulatorType *wt);
void VIEW3D_OT_ruler_add(struct wmOperatorType *ot);
+void VIEW3D_WT_navigate_rotate(struct wmManipulatorType *wt);
+
/* draw_volume.c */
void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
const float min[3], const float max[3],
@@ -364,7 +369,7 @@ extern bool view3d_camera_border_hack_test;
void VP_legacy_drawcursor(Scene *scene, struct ViewLayer *view_layer, ARegion *ar, View3D *v3d);
void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect);
void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect);
-void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect);
+void VP_legacy_draw_selected_name(Scene *scene, struct Object *ob, rcti *rect);
void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit);
void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth);
void VP_legacy_view3d_main_region_setup_view(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]);
@@ -372,7 +377,7 @@ bool VP_legacy_view3d_stereo3d_active(struct wmWindow *win, Scene *scene, View3D
void VP_legacy_view3d_stereo3d_setup(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar);
void draw_dupli_objects(const struct EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, Base *base);
bool VP_legacy_use_depth(Scene *scene, View3D *v3d);
-void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d);
+void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d);
void VP_drawrenderborder(ARegion *ar, View3D *v3d);
void VP_view3d_draw_background_none(void);
void VP_view3d_draw_background_world(Scene *scene, RegionView3D *rv3d);
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c
index d020571930a..6a45ec5095f 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c
@@ -378,11 +378,12 @@ static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmManipulato
struct CameraViewWidgetGroup *viewgroup = mgroup->customdata;
ARegion *ar = CTX_wm_region(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
RegionView3D *rv3d = ar->regiondata;
if (rv3d->persp == RV3D_CAMOB) {
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewgroup->state.view_border, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewgroup->state.view_border, false);
}
else {
viewgroup->state.view_border = (rctf){.xmin = 0, .ymin = 0, .xmax = ar->winx, .ymax = ar->winy};
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c
new file mode 100644
index 00000000000..6a5d63b180f
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c
@@ -0,0 +1,359 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_manipulator_navigate.c
+ * \ingroup spview3d
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_screen.h"
+#include "ED_manipulator_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name View3D Navigation Manipulator Group
+ * \{ */
+
+/* Offset from screen edge. */
+#define MANIPULATOR_OFFSET_FAC 2.5
+/* Size of main icon. */
+#define MANIPULATOR_SIZE 64
+/* Factor for size of smaller button. */
+#define MANIPULATOR_MINI_FAC 0.5
+/* How much mini buttons offset from the primary. */
+#define MANIPULATOR_MINI_OFFSET_FAC 0.6666f
+
+
+enum {
+ MPR_MOVE = 0,
+ MPR_ROTATE = 1,
+ MPR_ZOOM = 2,
+
+ /* just buttons */
+ /* overlaps MPR_ORTHO (switch between) */
+ MPR_PERSP = 3,
+ MPR_ORTHO = 4,
+ MPR_CAMERA = 5,
+
+ MPR_TOTAL = 6,
+};
+
+/* Vector icons compatible with 'GPU_batch_from_poly_2d_encoded' */
+static const uchar shape_camera[] = {
+ 0xa3, 0x19, 0x78, 0x55, 0x4d, 0x19, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xa9, 0x19,
+ 0xa9, 0x19, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a,
+ 0x4d, 0x19, 0x47, 0x19, 0x65, 0x55, 0x41, 0x55, 0x41, 0x9e, 0x43, 0xa8, 0x38, 0xb3,
+ 0x34, 0xc3, 0x38, 0xd2, 0x43, 0xdd, 0x53, 0xe1, 0x62, 0xdd, 0x6d, 0xd2, 0x72, 0xc3,
+ 0x78, 0xc3, 0x7c, 0xd2, 0x87, 0xdd, 0x96, 0xe1, 0xa6, 0xdd, 0xb1, 0xd2, 0xb5, 0xc3,
+ 0xb1, 0xb3, 0xa6, 0xa8, 0xa9, 0x9e, 0xa9, 0x8c, 0xbb, 0x8c, 0xbb, 0x86, 0xc7, 0x86,
+ 0xe0, 0x9e, 0xe0, 0x55, 0xc7, 0x6d, 0xbb, 0x6d, 0xbb, 0x67, 0xa9, 0x67, 0xa9, 0x55,
+ 0x8a, 0x55, 0xa9, 0x19, 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0,
+ 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x4f, 0xf5, 0x7c, 0xb3, 0x78, 0xc3,
+ 0x72, 0xc3, 0x6d, 0xb3, 0x62, 0xa8, 0x53, 0xa4, 0x43, 0xa8, 0x41, 0x9e, 0xa9, 0x9e,
+ 0xa6, 0xa8, 0x96, 0xa4, 0x87, 0xa8, 0x87, 0xa8,
+};
+static const uchar shape_ortho[] = {
+ 0x85, 0x15, 0x85, 0x7c, 0xde, 0xb3, 0xde, 0xb8, 0xd9, 0xba, 0x80, 0x85, 0x27, 0xba,
+ 0x22, 0xb8, 0x22, 0xb3, 0x7b, 0x7c, 0x7b, 0x15, 0x80, 0x12, 0x80, 0x12, 0x1d, 0xba,
+ 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f,
+ 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x0d, 0x1d, 0x45, 0x1d, 0x45, 0xb0, 0x0a,
+ 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff,
+ 0x80, 0xf2, 0xe3, 0xba, 0xe3, 0x45, 0x80, 0x0d, 0x7f, 0x00, 0x7f, 0x00,
+};
+static const uchar shape_pan[] = {
+ 0xbf, 0x4c, 0xbf, 0x66, 0x99, 0x66, 0x99, 0x40, 0xb2, 0x40, 0x7f, 0x0d, 0x7f, 0x00,
+ 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5,
+ 0x80, 0xff, 0x80, 0xf2, 0xb3, 0xbf, 0x99, 0xbf, 0x99, 0x99, 0xbf, 0x99, 0xbf, 0xb2,
+ 0xf2, 0x7f, 0xf2, 0x7f, 0x40, 0xb3, 0x40, 0x99, 0x66, 0x99, 0x66, 0xbf, 0x4d, 0xbf,
+ 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f,
+ 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x7f, 0x0d, 0x4c, 0x40, 0x66, 0x40, 0x66, 0x66,
+ 0x40, 0x66, 0x40, 0x4d, 0x0d, 0x80, 0x0d, 0x80,
+};
+static const uchar shape_persp[] = {
+ 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f,
+ 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x07, 0x30, 0x50, 0x18, 0xbd,
+ 0x80, 0xdb, 0xe8, 0xbd, 0xf5, 0xb0, 0xf5, 0xb0, 0x83, 0x0f, 0x87, 0x7b, 0xe2, 0xb7,
+ 0xe3, 0xba, 0xe0, 0xbb, 0x80, 0x87, 0x20, 0xbb, 0x1d, 0xba, 0x1d, 0xb7, 0x78, 0x7b,
+ 0x7d, 0x0f, 0x80, 0x0c, 0x80, 0x0c, 0xd0, 0x50, 0x80, 0x07, 0x7f, 0x00, 0xb0, 0x0a,
+ 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xe8, 0xbd, 0xe8, 0xbd,
+};
+static const uchar shape_zoom[] = {
+ 0xad, 0x7f, 0xf1, 0x7f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff,
+ 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0d, 0x7f, 0x52, 0x7f, 0x69, 0xb7,
+ 0x48, 0xb7, 0x80, 0xd8, 0xb8, 0xb7, 0x96, 0xb7, 0x96, 0xb7, 0x7f, 0x2f, 0x0d, 0x7f,
+ 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xda, 0x25,
+ 0xf5, 0x4f, 0xff, 0x80, 0xf1, 0x7f, 0xf1, 0x7f,
+};
+
+
+struct NavigateManipulatorInfo {
+ const char *opname;
+ const char *manipulator;
+ const unsigned char *shape;
+ uint shape_size;
+};
+
+#define SHAPE_VARS(shape_id) shape = shape_id, .shape_size = ARRAY_SIZE(shape_id)
+
+struct NavigateManipulatorInfo g_navigate_params[MPR_TOTAL] = {
+ {
+ .opname = "VIEW3D_OT_move",
+ .manipulator = "MANIPULATOR_WT_button_2d",
+ .SHAPE_VARS(shape_pan),
+ }, {
+ .opname = "VIEW3D_OT_rotate",
+ .manipulator = "VIEW3D_WT_navigate_rotate",
+ .shape = NULL,
+ .shape_size = 0,
+ }, {
+ .opname = "VIEW3D_OT_zoom",
+ .manipulator = "MANIPULATOR_WT_button_2d",
+ .SHAPE_VARS(shape_zoom),
+ }, {
+ .opname = "VIEW3D_OT_view_persportho",
+ .manipulator = "MANIPULATOR_WT_button_2d",
+ .SHAPE_VARS(shape_persp),
+ }, {
+ .opname = "VIEW3D_OT_view_persportho",
+ .manipulator = "MANIPULATOR_WT_button_2d",
+ .SHAPE_VARS(shape_ortho),
+ }, {
+ .opname = "VIEW3D_OT_viewnumpad",
+ .manipulator = "MANIPULATOR_WT_button_2d",
+ .SHAPE_VARS(shape_camera),
+ },
+};
+
+#undef SHAPE_VARS
+
+struct NavigateWidgetGroup {
+ wmManipulator *mpr_array[MPR_TOTAL];
+ /* Store the view state to check for changes. */
+ struct {
+ struct {
+ short winx, winy;
+ } ar;
+ struct {
+ char is_persp;
+ char viewlock;
+ } rv3d;
+ } state;
+ int region_size[2];
+ bool is_persp;
+};
+
+static bool WIDGETGROUP_navigate_poll(const bContext *UNUSED(C), wmManipulatorGroupType *UNUSED(wgt))
+{
+ if (U.manipulator_flag & USER_MANIPULATOR_DRAW_NAVIGATE) {
+ return true;
+ }
+ return false;
+
+}
+
+static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ struct NavigateWidgetGroup *navgroup = MEM_callocN(sizeof(struct NavigateWidgetGroup), __func__);
+
+ navgroup->region_size[0] = -1;
+ navgroup->region_size[1] = -1;
+
+ wmOperatorType *ot_viewnumpad = WM_operatortype_find("VIEW3D_OT_viewnumpad", true);
+
+ for (int i = 0; i < MPR_TOTAL; i++) {
+ const struct NavigateManipulatorInfo *info = &g_navigate_params[i];
+ navgroup->mpr_array[i] = WM_manipulator_new(info->manipulator, mgroup, NULL);
+ wmManipulator *mpr = navgroup->mpr_array[i];
+ mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR | WM_MANIPULATOR_DRAW_MODAL;
+ mpr->color[3] = 0.2f;
+ mpr->color_hi[3] = 0.4f;
+
+ /* may be overwritten later */
+ mpr->scale_basis = (MANIPULATOR_SIZE * MANIPULATOR_MINI_FAC) / 2;
+ if (info->shape != NULL) {
+ PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "shape");
+ RNA_property_string_set_bytes(
+ mpr->ptr, prop,
+ (const char *)info->shape, info->shape_size);
+ }
+
+ wmOperatorType *ot = WM_operatortype_find(info->opname, true);
+ WM_manipulator_operator_set(mpr, 0, ot, NULL);
+ }
+
+ {
+ wmManipulator *mpr = navgroup->mpr_array[MPR_CAMERA];
+ PointerRNA *ptr = WM_manipulator_operator_set(mpr, 0, ot_viewnumpad, NULL);
+ RNA_enum_set(ptr, "type", RV3D_VIEW_CAMERA);
+ }
+
+ /* Click only buttons (not modal). */
+ {
+ int mpr_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA};
+ for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) {
+ wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]];
+ RNA_boolean_set(mpr->ptr, "show_drag", false);
+ }
+ }
+
+ /* Modal operators, don't use initial mouse location since we're clicking on a button. */
+ {
+ int mpr_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM};
+ for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) {
+ wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]];
+ wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, 0);
+ RNA_boolean_set(&mpop->ptr, "use_mouse_init", false);
+ }
+ }
+
+ {
+ wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE];
+ mpr->scale_basis = MANIPULATOR_SIZE / 2;
+ char mapping[6] = {
+ RV3D_VIEW_LEFT,
+ RV3D_VIEW_RIGHT,
+ RV3D_VIEW_FRONT,
+ RV3D_VIEW_BACK,
+ RV3D_VIEW_BOTTOM,
+ RV3D_VIEW_TOP,
+ };
+
+ for (int part_index = 0; part_index < 6; part_index += 1) {
+ PointerRNA *ptr = WM_manipulator_operator_set(mpr, part_index + 1, ot_viewnumpad, NULL);
+ RNA_enum_set(ptr, "type", mapping[part_index]);
+ }
+
+ /* When dragging an axis, use this instead. */
+ mpr->drag_part = 0;
+ }
+
+ mgroup->customdata = navgroup;
+}
+
+static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ struct NavigateWidgetGroup *navgroup = mgroup->customdata;
+ ARegion *ar = CTX_wm_region(C);
+ const RegionView3D *rv3d = ar->regiondata;
+
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(navgroup->mpr_array[MPR_ROTATE]->matrix_offset[i], rv3d->viewmat[i]);
+ }
+
+ if ((navgroup->state.ar.winx == ar->winx) &&
+ (navgroup->state.ar.winy == ar->winy) &&
+ (navgroup->state.rv3d.is_persp == rv3d->is_persp) &&
+ (navgroup->state.rv3d.viewlock == rv3d->viewlock))
+ {
+ return;
+ }
+
+
+ navgroup->state.ar.winx = ar->winx;
+ navgroup->state.ar.winy = ar->winy;
+ navgroup->state.rv3d.is_persp = rv3d->is_persp;
+ navgroup->state.rv3d.viewlock = rv3d->viewlock;
+
+
+ const float icon_size = MANIPULATOR_SIZE;
+ const float icon_offset = (icon_size / 2.0) * MANIPULATOR_OFFSET_FAC * U.ui_scale;
+ const float icon_offset_mini = icon_size * MANIPULATOR_MINI_OFFSET_FAC * U.ui_scale;
+ const float co[2] = {ar->winx - icon_offset, ar->winy - icon_offset};
+
+ wmManipulator *mpr;
+
+ for (uint i = 0; i < ARRAY_SIZE(navgroup->mpr_array); i++) {
+ mpr = navgroup->mpr_array[i];
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true);
+ }
+
+ if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
+ mpr = navgroup->mpr_array[MPR_ROTATE];
+ mpr->matrix_basis[3][0] = co[0];
+ mpr->matrix_basis[3][1] = co[1];
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+
+ mpr = navgroup->mpr_array[MPR_MOVE];
+ mpr->matrix_basis[3][0] = co[0] + icon_offset_mini;
+ mpr->matrix_basis[3][1] = co[1] - icon_offset_mini;
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+
+ mpr = navgroup->mpr_array[MPR_ZOOM];
+ mpr->matrix_basis[3][0] = co[0] - icon_offset_mini;
+ mpr->matrix_basis[3][1] = co[1] - icon_offset_mini;
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+
+ mpr = navgroup->mpr_array[rv3d->is_persp ? MPR_ORTHO : MPR_PERSP];
+ mpr->matrix_basis[3][0] = co[0] + icon_offset_mini;
+ mpr->matrix_basis[3][1] = co[1] + icon_offset_mini;
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+
+ mpr = navgroup->mpr_array[MPR_CAMERA];
+ mpr->matrix_basis[3][0] = co[0] - icon_offset_mini;
+ mpr->matrix_basis[3][1] = co[1] + icon_offset_mini;
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+ }
+ else {
+ /* RV3D_LOCKED: only show supported buttons. */
+ mpr = navgroup->mpr_array[MPR_MOVE];
+ mpr->matrix_basis[3][0] = co[0] + icon_offset_mini;
+ mpr->matrix_basis[3][1] = co[1] + icon_offset_mini;
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+
+ mpr = navgroup->mpr_array[MPR_ZOOM];
+ mpr->matrix_basis[3][0] = co[0];
+ mpr->matrix_basis[3][1] = co[1] + icon_offset_mini;
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+ }
+}
+
+void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "View3D Navigate";
+ wgt->idname = "VIEW3D_WGT_navigate";
+
+ wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT |
+ WM_MANIPULATORGROUPTYPE_SCALE |
+ WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL);
+
+ wgt->poll = WIDGETGROUP_navigate_poll;
+ wgt->setup = WIDGETGROUP_navigate_setup;
+ wgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c
new file mode 100644
index 00000000000..424b5dae402
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c
@@ -0,0 +1,307 @@
+/*
+ * ***** 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 view3d_manipulator_navigate_type.c
+ * \ingroup wm
+ *
+ * \name Custom Orientation/Navigation Manipulator for the 3D View
+ *
+ * \brief Simple manipulator to axis and translate.
+ *
+ * - scale_basis: used for the size.
+ * - matrix_basis: used for the location.
+ * - matrix_offset: used to store the orientation.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_sort_utils.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+#include "view3d_intern.h"
+
+#define DIAL_RESOLUTION 32
+
+#define HANDLE_SIZE 0.33
+
+static void axis_geom_draw(
+ const wmManipulator *mpr, const float color[4], const bool UNUSED(select))
+{
+ glLineWidth(mpr->line_width);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ const uint pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* flip z for reverse */
+ const float cone_coords[5][3] = {
+ {-1, -1, 4},
+ {-1, +1, 4},
+ {+1, +1, 4},
+ {+1, -1, 4},
+ {0, 0, 2},
+ };
+
+ struct {
+ float depth;
+ char index;
+ char axis;
+ char is_pos;
+ } axis_order[6] = {
+ {-mpr->matrix_offset[0][2], 0, 0, false},
+ {+mpr->matrix_offset[0][2], 1, 0, true},
+ {-mpr->matrix_offset[1][2], 2, 1, false},
+ {+mpr->matrix_offset[1][2], 3, 1, true},
+ {-mpr->matrix_offset[2][2], 4, 2, false},
+ {+mpr->matrix_offset[2][2], 5, 2, true},
+ };
+ qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float);
+
+ const float scale_axis = 0.25f;
+ static const float axis_highlight[4] = {1, 1, 1, 1};
+ static const float axis_nop[4] = {1, 1, 1, 0};
+ static const float axis_black[4] = {0, 0, 0, 1};
+ static float axis_color[3][4];
+ gpuPushMatrix();
+ gpuMultMatrix(mpr->matrix_offset);
+
+ bool draw_center_done = false;
+
+ for (int axis_index = 0; axis_index < ARRAY_SIZE(axis_order); axis_index++) {
+ const int index = axis_order[axis_index].index;
+ const int axis = axis_order[axis_index].axis;
+ const bool is_pos = axis_order[axis_index].is_pos;
+
+ /* Draw slightly before, so axis aligned arrows draw ontop. */
+ if ((draw_center_done == false) && (axis_order[axis_index].depth > -0.01f)) {
+
+ /* Circle defining active area (revert back to 2D space). */
+ {
+ gpuPopMatrix();
+ immUniformColor4fv(color);
+ imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION);
+ gpuPushMatrix();
+ gpuMultMatrix(mpr->matrix_offset);
+ }
+
+ /* Center cube. */
+ {
+ float center[3], size[3];
+
+ zero_v3(center);
+ copy_v3_fl(size, HANDLE_SIZE);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_LEQUAL);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glLineWidth(1.0f);
+ /* Just draw depth values. */
+ immUniformColor4fv(axis_nop);
+ imm_draw_cube_fill_3d(pos_id, center, size);
+ immUniformColor4fv(axis_black);
+ madd_v3_v3fl(
+ center,
+ (float [3]){
+ mpr->matrix_offset[0][2],
+ mpr->matrix_offset[1][2],
+ mpr->matrix_offset[2][2]},
+ 0.08f);
+ imm_draw_cube_wire_3d(pos_id, center, size);
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ draw_center_done = true;
+ }
+ UI_GetThemeColor3fv(TH_AXIS_X + axis, axis_color[axis]);
+ axis_color[axis][3] = 1.0f;
+
+ const int index_z = axis;
+ const int index_y = (axis + 1) % 3;
+ const int index_x = (axis + 2) % 3;
+
+#define ROTATED_VERT(v_orig) \
+ { \
+ float v[3]; \
+ copy_v3_v3(v, v_orig); \
+ if (is_pos == 0) { \
+ v[2] *= -1.0f; \
+ } \
+ immVertex3f(pos_id, v[index_x] * scale_axis, v[index_y] * scale_axis, v[index_z] * scale_axis); \
+ } ((void)0)
+
+ bool ok = true;
+
+ /* skip view align axis */
+ if (len_squared_v2(mpr->matrix_offset[axis]) < 1e-6f && (mpr->matrix_offset[axis][2] > 0.0f) == is_pos) {
+ ok = false;
+ }
+ if (ok) {
+ immUniformColor4fv(index + 1 == mpr->highlight_part ? axis_highlight : axis_color[axis]);
+ immBegin(GWN_PRIM_TRI_FAN, 6);
+ ROTATED_VERT(cone_coords[4]);
+ for (int j = 0; j <= 4; j++) {
+ ROTATED_VERT(cone_coords[j % 4]);
+ }
+ immEnd();
+ }
+
+#undef ROTATED_VERT
+ }
+
+ gpuPopMatrix();
+ immUnbindProgram();
+}
+
+static void axis3d_draw_intern(
+ const bContext *UNUSED(C), wmManipulator *mpr,
+ const bool select, const bool highlight)
+{
+ const float *color = highlight ? mpr->color_hi : mpr->color;
+ float matrix_final[4][4];
+ float matrix_unit[4][4];
+
+ unit_m4(matrix_unit);
+
+ WM_manipulator_calc_matrix_final_params(
+ mpr,
+ &((struct WM_ManipulatorMatrixParams) {
+ .matrix_offset = matrix_unit,
+ }), matrix_final);
+
+ gpuPushMatrix();
+ gpuMultMatrix(matrix_final);
+
+ glEnable(GL_BLEND);
+ axis_geom_draw(mpr, color, select);
+ glDisable(GL_BLEND);
+ gpuPopMatrix();
+}
+
+static void manipulator_axis_draw(const bContext *C, wmManipulator *mpr)
+{
+ const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL;
+ const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
+
+ (void)is_modal;
+
+ glEnable(GL_BLEND);
+ axis3d_draw_intern(C, mpr, false, is_highlight);
+ glDisable(GL_BLEND);
+}
+
+static int manipulator_axis_test_select(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ float point_local[2] = {UNPACK2(event->mval)};
+ sub_v2_v2(point_local, mpr->matrix_basis[3]);
+ mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale));
+
+ const float len_sq = len_squared_v2(point_local);
+ if (len_sq > 1.0) {
+ return -1;
+ }
+
+ int part_best = -1;
+ int part_index = 1;
+ /* Use 'SQUARE(HANDLE_SIZE)' if we want to be able to _not_ focus on one of the axis. */
+ float i_best_len_sq = FLT_MAX;
+ for (int i = 0; i < 3; i++) {
+ for (int is_pos = 0; is_pos < 2; is_pos++) {
+ float co[2] = {
+ mpr->matrix_offset[i][0] * (is_pos ? 1 : -1),
+ mpr->matrix_offset[i][1] * (is_pos ? 1 : -1),
+ };
+
+ bool ok = true;
+
+ /* Check if we're viewing on an axis, there is no point to clicking on the current axis so show the reverse. */
+ if (len_squared_v2(co) < 1e-6f && (mpr->matrix_offset[i][2] > 0.0f) == is_pos) {
+ ok = false;
+ }
+
+ if (ok) {
+ const float len_axis_sq = len_squared_v2v2(co, point_local);
+ if (len_axis_sq < i_best_len_sq) {
+ part_best = part_index;
+ i_best_len_sq = len_axis_sq;
+ }
+ }
+ part_index += 1;
+ }
+ }
+
+ if (part_best != -1) {
+ return part_best;
+ }
+
+ /* The 'mpr->scale_final' is already applied when projecting. */
+ if (len_sq < 1.0f) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static int manipulator_axis_cursor_get(wmManipulator *mpr)
+{
+ if (mpr->highlight_part > 0) {
+ return CURSOR_EDIT;
+ }
+ return BC_NSEW_SCROLLCURSOR;
+}
+
+void VIEW3D_WT_navigate_rotate(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "VIEW3D_WT_navigate_rotate";
+
+ /* api callbacks */
+ wt->draw = manipulator_axis_draw;
+ wt->test_select = manipulator_axis_test_select;
+ wt->cursor_get = manipulator_axis_cursor_get;
+
+ wt->struct_size = sizeof(wmManipulator);
+}
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
index 230b4f44c16..e8d540bcc9d 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
@@ -148,6 +148,11 @@ static RulerItem *ruler_item_add(wmManipulatorGroup *mgroup)
return ruler_item;
}
+static void ruler_item_remove(bContext *C, wmManipulatorGroup *mgroup, RulerItem *ruler_item)
+{
+ WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, &ruler_item->mpr, C);
+}
+
static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
char *numstr, size_t numstr_size, int prec)
{
@@ -908,16 +913,24 @@ static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool c
{
wmManipulatorGroup *mgroup = mpr->parent_mgroup;
RulerInfo *ruler_info = mgroup->customdata;
- RulerItem *ruler_item = (RulerItem *)mpr;
- RulerInteraction *inter = mpr->interaction_data;
if (!cancel) {
if (ruler_info->state == RULER_STATE_DRAG) {
+ RulerItem *ruler_item = (RulerItem *)mpr;
+ RulerInteraction *inter = mpr->interaction_data;
/* rubber-band angle removal */
- if (ruler_item && (inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) {
- if (!inter->inside_region) {
+ if (!inter->inside_region) {
+ if ((inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) {
ruler_item->flag &= ~RULERITEM_USE_ANGLE;
}
+ else {
+ /* Not ideal, since the ruler isn't a mode and we don't want to override delete key
+ * use dragging out of the view for removal. */
+ ruler_item_remove(C, mgroup, ruler_item);
+ ruler_item = NULL;
+ mpr = NULL;
+ inter = NULL;
+ }
}
if (ruler_info->snap_flag & RULER_SNAP_OK) {
ruler_info->snap_flag &= ~RULER_SNAP_OK;
@@ -928,7 +941,9 @@ static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool c
view3d_ruler_to_gpencil(C, mgroup);
}
- MEM_SAFE_FREE(mpr->interaction_data);
+ if (mpr) {
+ MEM_SAFE_FREE(mpr->interaction_data);
+ }
ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
}
@@ -996,7 +1011,7 @@ void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt)
wgt->name = "Ruler Widgets";
wgt->idname = view3d_wgt_ruler_id;
- wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE;
+ wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL;
wgt->mmap_params.spaceid = SPACE_VIEW3D;
wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index f8b02f0b405..ba3e78b25b9 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -277,6 +277,11 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[
/* More Generic Window/Ray/Vector projection functions
* *************************************************** */
+float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
+{
+ return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
+}
+
/**
* Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
*/
@@ -304,6 +309,7 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
}
static void view3d_win_to_ray_segment(
+ const struct Depsgraph *depsgraph,
const ARegion *ar, const View3D *v3d, const float mval[2],
float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
{
@@ -321,7 +327,7 @@ static void view3d_win_to_ray_segment(
start_offset = -end_offset;
}
else {
- ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false);
+ ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &start_offset, &end_offset, false);
}
if (r_ray_start) {
@@ -360,12 +366,13 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float
* \return success, false if the ray is totally clipped.
*/
bool ED_view3d_win_to_ray_ex(
+ const struct Depsgraph *depsgraph,
const ARegion *ar, const View3D *v3d, const float mval[2],
float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
{
float ray_end[3];
- view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
+ view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
/* bounds clipping */
if (do_clip) {
@@ -389,10 +396,11 @@ bool ED_view3d_win_to_ray_ex(
* \return success, false if the ray is totally clipped.
*/
bool ED_view3d_win_to_ray(
+ const struct Depsgraph *depsgraph,
const ARegion *ar, const View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
{
- return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
+ return ED_view3d_win_to_ray_ex(depsgraph,ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
}
/**
@@ -622,10 +630,11 @@ void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3
* \param do_clip Optionally clip the ray by the view clipping planes.
* \return success, false if the segment is totally clipped.
*/
-bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2],
+bool ED_view3d_win_to_segment(const struct Depsgraph *depsgraph,
+ const ARegion *ar, View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip)
{
- view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
+ view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
/* bounds clipping */
if (do_clip) {
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
new file mode 100644
index 00000000000..7bb3f443ac6
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -0,0 +1,1436 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_utils.c
+ * \ingroup spview3d
+ *
+ * 3D View checks and manipulation (no operators).
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_camera.h"
+#include "BKE_context.h"
+#include "BKE_object.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_matrix.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name View Data Access Utilities
+ *
+ * \{ */
+
+float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d)
+{
+ if (v3d && v3d->localvd) return v3d->cursor;
+ else return scene->cursor;
+}
+
+Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
+{
+ /* establish the camera object, so we can default to view mapping if anything is wrong with it */
+ if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
+ return v3d->camera->data;
+ }
+ else {
+ return NULL;
+ }
+}
+
+void ED_view3d_dist_range_get(
+ const View3D *v3d,
+ float r_dist_range[2])
+{
+ r_dist_range[0] = v3d->grid * 0.001f;
+ r_dist_range[1] = v3d->far * 10.0f;
+}
+
+/**
+ * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
+ */
+bool ED_view3d_clip_range_get(
+ const Depsgraph *depsgraph,
+ const View3D *v3d, const RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend,
+ const bool use_ortho_factor)
+{
+ CameraParams params;
+
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
+
+ if (use_ortho_factor && params.is_ortho) {
+ const float fac = 2.0f / (params.clipend - params.clipsta);
+ params.clipsta *= fac;
+ params.clipend *= fac;
+ }
+
+ if (r_clipsta) *r_clipsta = params.clipsta;
+ if (r_clipend) *r_clipend = params.clipend;
+
+ return params.is_ortho;
+}
+
+bool ED_view3d_viewplane_get(
+ const Depsgraph *depsgraph,
+ const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
+ rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
+{
+ CameraParams params;
+
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
+ BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
+
+ if (r_viewplane) *r_viewplane = params.viewplane;
+ if (r_clipsta) *r_clipsta = params.clipsta;
+ if (r_clipend) *r_clipend = params.clipend;
+ if (r_pixsize) *r_pixsize = params.viewdx;
+
+ return params.is_ortho;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name View State/Context Utilities
+ *
+ * \{ */
+
+/**
+ * Use this call when executing an operator,
+ * event system doesn't set for each event the OpenGL drawing context.
+ */
+void view3d_operator_needs_opengl(const bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ view3d_region_operator_needs_opengl(win, ar);
+}
+
+void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
+{
+ /* for debugging purpose, context should always be OK */
+ if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) {
+ printf("view3d_region_operator_needs_opengl error, wrong region\n");
+ }
+ else {
+ RegionView3D *rv3d = ar->regiondata;
+
+ wmSubWindowSet(win, ar->swinid);
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(rv3d->viewmat);
+ }
+}
+
+/**
+ * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727]
+ */
+void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
+{
+ float viewdist;
+
+ if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
+ return;
+ }
+
+ viewdist = rv3d->dist;
+
+ /* special exception for ortho camera (viewdist isnt used for perspective cameras) */
+ if (dist != 0.0f) {
+ if (rv3d->persp == RV3D_CAMOB) {
+ if (rv3d->is_persp == false) {
+ viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
+ }
+ }
+ }
+
+ bglPolygonOffset(viewdist, dist);
+}
+
+bool ED_view3d_context_activate(bContext *C)
+{
+ bScreen *sc = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar;
+
+ /* sa can be NULL when called from python */
+ if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
+ sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
+ }
+
+ if (sa == NULL) {
+ return false;
+ }
+
+ ar = BKE_area_find_region_active_win(sa);
+ if (ar == NULL) {
+ return false;
+ }
+
+ /* bad context switch .. */
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Clipping Utilities
+ *
+ * \{ */
+
+void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
+{
+ int val;
+
+ for (val = 0; val < 4; val++) {
+ normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
+ if (UNLIKELY(is_flip)) {
+ negate_v3(clip[val]);
+ }
+
+ clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
+ }
+}
+
+void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect)
+{
+ /* init in case unproject fails */
+ memset(bb->vec, 0, sizeof(bb->vec));
+
+ /* four clipping planes and bounding volume */
+ /* first do the bounding volume */
+ for (int val = 0; val < 4; val++) {
+ float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
+ float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
+
+ ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]);
+ ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]);
+ }
+
+ /* optionally transform to object space */
+ if (ob) {
+ float imat[4][4];
+ invert_m4_m4(imat, ob->obmat);
+
+ for (int val = 0; val < 8; val++) {
+ mul_m4_v3(imat, bb->vec[val]);
+ }
+ }
+
+ /* verify if we have negative scale. doing the transform before cross
+ * product flips the sign of the vector compared to doing cross product
+ * before transform then, so we correct for that. */
+ int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false;
+
+ ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Bound-Box Utilities
+ *
+ * \{ */
+
+static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
+{
+ int a, flag = -1, fl;
+
+ for (a = 0; a < 8; a++) {
+ float vec[4], min, max;
+ copy_v3_v3(vec, bb->vec[a]);
+ vec[3] = 1.0;
+ mul_m4_v4(persmatob, vec);
+ max = vec[3];
+ min = -vec[3];
+
+ fl = 0;
+ if (vec[0] < min) fl += 1;
+ if (vec[0] > max) fl += 2;
+ if (vec[1] < min) fl += 4;
+ if (vec[1] > max) fl += 8;
+ if (vec[2] < min) fl += 16;
+ if (vec[2] > max) fl += 32;
+
+ flag &= fl;
+ if (flag == 0) return true;
+ }
+
+ return false;
+}
+
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
+{
+ /* return 1: draw */
+
+ float persmatob[4][4];
+
+ if (bb == NULL) return true;
+ if (bb->flag & BOUNDBOX_DISABLED) return true;
+
+ mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
+
+ return view3d_boundbox_clip_m4(bb, persmatob);
+}
+
+bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
+{
+ if (bb == NULL) return true;
+ if (bb->flag & BOUNDBOX_DISABLED) return true;
+
+ return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Perspective & Mode Switching
+ *
+ * Misc view utility functions.
+ * \{ */
+
+bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
+{
+ return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
+}
+
+/**
+ * Use to store the last view, before entering camera view.
+ */
+void ED_view3d_lastview_store(RegionView3D *rv3d)
+{
+ copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
+ rv3d->lview = rv3d->view;
+ if (rv3d->persp != RV3D_CAMOB) {
+ rv3d->lpersp = rv3d->persp;
+ }
+}
+
+void ED_view3d_lock_clear(View3D *v3d)
+{
+ v3d->ob_centre = NULL;
+ v3d->ob_centre_bone[0] = '\0';
+ v3d->ob_centre_cursor = false;
+ v3d->flag2 &= ~V3D_LOCK_CAMERA;
+}
+
+/**
+ * For viewport operators that exit camera perspective.
+ *
+ * \note This differs from simply setting ``rv3d->persp = persp`` because it
+ * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
+ * otherwise switching out of camera view may jump to a different part of the scene.
+ */
+void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp)
+{
+ BLI_assert(rv3d->persp == RV3D_CAMOB);
+ BLI_assert(persp != RV3D_CAMOB);
+
+ if (v3d->camera) {
+ rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
+ ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
+ }
+
+ if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
+ rv3d->persp = persp;
+ }
+}
+/**
+ * Action to take when rotating the view,
+ * handle auto-persp and logic for switching out of views.
+ *
+ * shared with NDOF.
+ */
+bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
+
+ BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
+
+ if (ED_view3d_camera_lock_check(v3d, rv3d))
+ return false;
+
+ if (rv3d->persp != RV3D_PERSP) {
+ if (rv3d->persp == RV3D_CAMOB) {
+ /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */
+ char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp;
+ ED_view3d_persp_switch_from_camera(v3d, rv3d, persp);
+ }
+ else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
+ rv3d->persp = RV3D_PERSP;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera Lock API
+ *
+ * Lock the camera to the view-port, allowing view manipulation to transform the camera.
+ * \{ */
+
+/**
+ * \return true when the view-port is locked to its camera.
+ */
+bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
+{
+ return ((v3d->camera) &&
+ (!ID_IS_LINKED(v3d->camera)) &&
+ (v3d->flag2 & V3D_LOCK_CAMERA) &&
+ (rv3d->persp == RV3D_CAMOB));
+}
+
+/**
+ * Apply the camera object transformation to the view-port.
+ * (needed so we can use regular view-port manipulation operators, that sync back to the camera).
+ */
+void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
+{
+ if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+ if (calc_dist) {
+ /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
+ rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
+ }
+ ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
+ }
+}
+
+void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
+{
+ ED_view3d_camera_lock_init_ex(v3d, rv3d, true);
+}
+
+/**
+ * Apply the view-port transformation back to the camera object.
+ *
+ * \return true if the camera is moved.
+ */
+bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
+{
+ if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+ ObjectTfmProtectedChannels obtfm;
+ Object *root_parent;
+
+ if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
+ Object *ob_update;
+ float tmat[4][4];
+ float imat[4][4];
+ float view_mat[4][4];
+ float diff_mat[4][4];
+ float parent_mat[4][4];
+
+ while (root_parent->parent) {
+ root_parent = root_parent->parent;
+ }
+
+ ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+
+ normalize_m4_m4(tmat, v3d->camera->obmat);
+
+ invert_m4_m4(imat, tmat);
+ mul_m4_m4m4(diff_mat, view_mat, imat);
+
+ mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
+
+ BKE_object_tfm_protected_backup(root_parent, &obtfm);
+ BKE_object_apply_mat4(root_parent, parent_mat, true, false);
+ BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
+
+ ob_update = v3d->camera;
+ while (ob_update) {
+ DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
+ WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
+ ob_update = ob_update->parent;
+ }
+ }
+ else {
+ /* always maintain the same scale */
+ const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
+ BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
+ ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+ BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
+
+ DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+ WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
+ }
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_view3d_camera_autokey(
+ Scene *scene, ID *id_key,
+ struct bContext *C, const bool do_rotate, const bool do_translate)
+{
+ if (autokeyframe_cfra_can_key(scene, id_key)) {
+ const float cfra = (float)CFRA;
+ ListBase dsources = {NULL, NULL};
+
+ /* add data-source override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
+
+ /* insert keyframes
+ * 1) on the first frame
+ * 2) on each subsequent frame
+ * TODO: need to check in future that frame changed before doing this
+ */
+ if (do_rotate) {
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_translate) {
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp data */
+ BLI_freelistN(&dsources);
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * Call after modifying a locked view.
+ *
+ * \note Not every view edit currently auto-keys (numpad for eg),
+ * this is complicated because of smoothview.
+ */
+bool ED_view3d_camera_lock_autokey(
+ View3D *v3d, RegionView3D *rv3d,
+ struct bContext *C, const bool do_rotate, const bool do_translate)
+{
+ /* similar to ED_view3d_cameracontrol_update */
+ if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+ Scene *scene = CTX_data_scene(C);
+ ID *id_key;
+ Object *root_parent;
+ if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
+ while (root_parent->parent) {
+ root_parent = root_parent->parent;
+ }
+ id_key = &root_parent->id;
+ }
+ else {
+ id_key = &v3d->camera->id;
+ }
+
+ return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+
+/* -------------------------------------------------------------------- */
+/** \name Box View Support
+ *
+ * Use with quad-split so each view is clipped by the bounds of each view axis.
+ * \{ */
+
+static void view3d_boxview_clip(ScrArea *sa)
+{
+ ARegion *ar;
+ BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
+ float clip[6][4];
+ float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
+ int val;
+
+ /* create bounding box */
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (rv3d->viewlock & RV3D_BOXCLIP) {
+ if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+ if (ar->winx > ar->winy) x1 = rv3d->dist;
+ else x1 = ar->winx * rv3d->dist / ar->winy;
+
+ if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx;
+ else y1 = rv3d->dist;
+ copy_v2_v2(ofs, rv3d->ofs);
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+ ofs[2] = rv3d->ofs[2];
+
+ if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx;
+ else z1 = rv3d->dist;
+ }
+ }
+ }
+ }
+
+ for (val = 0; val < 8; val++) {
+ if (ELEM(val, 0, 3, 4, 7))
+ bb->vec[val][0] = -x1 - ofs[0];
+ else
+ bb->vec[val][0] = x1 - ofs[0];
+
+ if (ELEM(val, 0, 1, 4, 5))
+ bb->vec[val][1] = -y1 - ofs[1];
+ else
+ bb->vec[val][1] = y1 - ofs[1];
+
+ if (val > 3)
+ bb->vec[val][2] = -z1 - ofs[2];
+ else
+ bb->vec[val][2] = z1 - ofs[2];
+ }
+
+ /* normals for plane equations */
+ normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
+ normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
+ normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
+ normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
+ normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
+ normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
+
+ /* then plane equations */
+ for (val = 0; val < 6; val++) {
+ clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
+ }
+
+ /* create bounding box */
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (rv3d->viewlock & RV3D_BOXCLIP) {
+ rv3d->rflag |= RV3D_CLIPPING;
+ memcpy(rv3d->clip, clip, sizeof(clip));
+ if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
+ rv3d->clipbb = MEM_dupallocN(bb);
+ }
+ }
+ }
+ MEM_freeN(bb);
+}
+
+/**
+ * Find which axis values are shared between both views and copy to \a rv3d_dst
+ * taking axis flipping into account.
+ */
+static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
+{
+ /* absolute axis values above this are considered to be set (will be ~1.0f) */
+ const float axis_eps = 0.5f;
+ float viewinv[4];
+
+ /* use the view rotation to identify which axis to sync on */
+ float view_axis_all[4][3] = {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f}};
+
+ float *view_src_x = &view_axis_all[0][0];
+ float *view_src_y = &view_axis_all[1][0];
+
+ float *view_dst_x = &view_axis_all[2][0];
+ float *view_dst_y = &view_axis_all[3][0];
+ int i;
+
+
+ /* we could use rv3d->viewinv, but better not depend on view matrix being updated */
+ if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) {
+ return;
+ }
+ invert_qt_normalized(viewinv);
+ mul_qt_v3(viewinv, view_src_x);
+ mul_qt_v3(viewinv, view_src_y);
+
+ if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) {
+ return;
+ }
+ invert_qt_normalized(viewinv);
+ mul_qt_v3(viewinv, view_dst_x);
+ mul_qt_v3(viewinv, view_dst_y);
+
+ /* check source and dest have a matching axis */
+ for (i = 0; i < 3; i++) {
+ if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
+ ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
+ {
+ rv3d_dst->ofs[i] = rv3d_src->ofs[i];
+ }
+ }
+}
+
+/* sync center/zoom view of region to others, for view transforms */
+void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
+{
+ ARegion *artest;
+ RegionView3D *rv3d = ar->regiondata;
+ short clip = 0;
+
+ for (artest = sa->regionbase.first; artest; artest = artest->next) {
+ if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3dtest = artest->regiondata;
+
+ if (rv3dtest->viewlock & RV3D_LOCKED) {
+ rv3dtest->dist = rv3d->dist;
+ view3d_boxview_sync_axis(rv3dtest, rv3d);
+ clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
+
+ ED_region_tag_redraw(artest);
+ }
+ }
+ }
+
+ if (clip) {
+ view3d_boxview_clip(sa);
+ }
+}
+
+/* for home, center etc */
+void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
+{
+ ARegion *artest;
+ RegionView3D *rv3d = ar->regiondata;
+ bool clip = false;
+
+ for (artest = sa->regionbase.first; artest; artest = artest->next) {
+ if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3dtest = artest->regiondata;
+
+ if (rv3dtest->viewlock) {
+ rv3dtest->dist = rv3d->dist;
+ copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
+ ED_region_tag_redraw(artest);
+
+ clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0);
+ }
+ }
+ }
+
+ if (clip) {
+ view3d_boxview_clip(sa);
+ }
+}
+
+/* 'clip' is used to know if our clip setting has changed */
+void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
+{
+ ARegion *ar_sync = NULL;
+ RegionView3D *rv3d = ar->regiondata;
+ short viewlock;
+ /* this function copies flags from the first of the 3 other quadview
+ * regions to the 2 other, so it assumes this is the region whose
+ * properties are always being edited, weak */
+ viewlock = rv3d->viewlock;
+
+ if ((viewlock & RV3D_LOCKED) == 0) {
+ do_clip = (viewlock & RV3D_BOXCLIP) != 0;
+ viewlock = 0;
+ }
+ else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
+ do_clip = true;
+ viewlock &= ~RV3D_BOXCLIP;
+ }
+
+ for (; ar; ar = ar->prev) {
+ if (ar->alignment == RGN_ALIGN_QSPLIT) {
+ rv3d = ar->regiondata;
+ rv3d->viewlock = viewlock;
+
+ if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
+ rv3d->rflag &= ~RV3D_BOXCLIP;
+ }
+
+ /* use ar_sync so we sync with one of the aligned views below
+ * else the view jumps on changing view settings like 'clip'
+ * since it copies from the perspective view */
+ ar_sync = ar;
+ }
+ }
+
+ if (rv3d->viewlock & RV3D_BOXVIEW) {
+ view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
+ }
+
+ /* ensure locked regions have an axis, locked user views don't make much sense */
+ if (viewlock & RV3D_LOCKED) {
+ int index_qsplit = 0;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->alignment == RGN_ALIGN_QSPLIT) {
+ rv3d = ar->regiondata;
+ if (rv3d->viewlock) {
+ if (!RV3D_VIEW_IS_AXIS(rv3d->view)) {
+ rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
+ rv3d->persp = RV3D_ORTHO;
+ ED_view3d_lock(rv3d);
+ }
+ }
+ index_qsplit++;
+ }
+ }
+ }
+
+ ED_area_tag_redraw(sa);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Auto-Depth Utilities
+ * \{ */
+
+static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin)
+{
+ ViewDepths depth_temp = {0};
+ rcti rect;
+ float depth_close;
+
+ if (margin == 0) {
+ /* Get Z Depths, needed for perspective, nice for ortho */
+ rect.xmin = mval[0];
+ rect.ymin = mval[1];
+ rect.xmax = mval[0] + 1;
+ rect.ymax = mval[1] + 1;
+ }
+ else {
+ BLI_rcti_init_pt_radius(&rect, mval, margin);
+ }
+
+ view3d_update_depths_rect(ar, &depth_temp, &rect);
+ depth_close = view3d_depth_near(&depth_temp);
+ MEM_SAFE_FREE(depth_temp.depths);
+ return depth_close;
+}
+
+/**
+ * Get the world-space 3d location from a screen-space 2d point.
+ *
+ * \param mval: Input screen-space pixel location.
+ * \param mouse_worldloc: Output world-space location.
+ * \param fallback_depth_pt: Use this points depth when no depth can be found.
+ */
+bool ED_view3d_autodist(
+ const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d,
+ const int mval[2], float mouse_worldloc[3],
+ const bool alphaoverride, const float fallback_depth_pt[3])
+{
+ float depth_close;
+ int margin_arr[] = {0, 2, 4};
+ int i;
+ bool depth_ok = false;
+
+ /* Get Z Depths, needed for perspective, nice for ortho */
+ ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride);
+
+ /* Attempt with low margin's first */
+ i = 0;
+ do {
+ depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
+ depth_ok = (depth_close != FLT_MAX);
+ } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
+
+ if (depth_ok) {
+ float centx = (float)mval[0] + 0.5f;
+ float centy = (float)mval[1] + 0.5f;
+
+ if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) {
+ return true;
+ }
+ }
+
+ if (fallback_depth_pt) {
+ ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+void ED_view3d_autodist_init(
+ const EvaluationContext *eval_ctx, struct Depsgraph *graph,
+ ARegion *ar, View3D *v3d, int mode)
+{
+ /* Get Z Depths, needed for perspective, nice for ortho */
+ switch (mode) {
+ case 0:
+ ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true);
+ break;
+ case 1:
+ {
+ Scene *scene = DEG_get_evaluated_scene(graph);
+ ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d);
+ break;
+ }
+ }
+}
+
+/* no 4x4 sampling, run #ED_view3d_autodist_init first */
+bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3],
+ int margin, float *force_depth)
+{
+ float depth;
+
+ /* Get Z Depths, needed for perspective, nice for ortho */
+ if (force_depth)
+ depth = *force_depth;
+ else
+ depth = view_autodist_depth_margin(ar, mval, margin);
+
+ if (depth == FLT_MAX)
+ return false;
+
+ float centx = (float)mval[0] + 0.5f;
+ float centy = (float)mval[1] + 0.5f;
+ return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc);
+}
+
+bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
+{
+ *depth = view_autodist_depth_margin(ar, mval, margin);
+
+ return (*depth != FLT_MAX);
+}
+
+static bool depth_segment_cb(int x, int y, void *userData)
+{
+ struct { ARegion *ar; int margin; float depth; } *data = userData;
+ int mval[2];
+ float depth;
+
+ mval[0] = x;
+ mval[1] = y;
+
+ depth = view_autodist_depth_margin(data->ar, mval, data->margin);
+
+ if (depth != FLT_MAX) {
+ data->depth = depth;
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+bool ED_view3d_autodist_depth_seg(
+ ARegion *ar, const int mval_sta[2], const int mval_end[2],
+ int margin, float *depth)
+{
+ struct { ARegion *ar; int margin; float depth; } data = {NULL};
+ int p1[2];
+ int p2[2];
+
+ data.ar = ar;
+ data.margin = margin;
+ data.depth = FLT_MAX;
+
+ copy_v2_v2_int(p1, mval_sta);
+ copy_v2_v2_int(p2, mval_end);
+
+ BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
+
+ *depth = data.depth;
+
+ return (*depth != FLT_MAX);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Radius/Distance Utilities
+ *
+ * Use to calculate a distance to a point based on it's radius.
+ * \{ */
+
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
+{
+ return radius * (1.0f / tanf(angle / 2.0f));
+}
+
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
+{
+ return radius / (DEFAULT_SENSOR_WIDTH / lens);
+}
+
+/**
+ * Return a new RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param ar Can be NULL if \a use_aspect is false.
+ * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect Increase the distance to account for non 1:1 view aspect.
+ * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
+float ED_view3d_radius_to_dist(
+ const View3D *v3d, const ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius)
+{
+ float dist;
+
+ BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
+ BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
+
+ if (persp == RV3D_ORTHO) {
+ dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
+ }
+ else {
+ float lens, sensor_size, zoom;
+ float angle;
+
+ if (persp == RV3D_CAMOB) {
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ params.clipsta = v3d->near;
+ params.clipend = v3d->far;
+ BKE_camera_params_from_object(&params, v3d->camera);
+
+ lens = params.lens;
+ sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+
+ /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
+ zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
+ }
+ else {
+ lens = v3d->lens;
+ sensor_size = DEFAULT_SENSOR_WIDTH;
+ zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ }
+
+ angle = focallength_to_fov(lens, sensor_size);
+
+ /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
+ angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
+
+ dist = ED_view3d_radius_to_dist_persp(angle, radius);
+ }
+
+ if (use_aspect) {
+ const RegionView3D *rv3d = ar->regiondata;
+
+ float winx, winy;
+
+ if (persp == RV3D_CAMOB) {
+ /* camera frame x/y in pixels */
+ winx = ar->winx / rv3d->viewcamtexcofac[0];
+ winy = ar->winy / rv3d->viewcamtexcofac[1];
+ }
+ else {
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ if (winx && winy) {
+ float aspect = winx / winy;
+ if (aspect < 1.0f) {
+ aspect = 1.0f / aspect;
+ }
+ dist *= aspect;
+ }
+ }
+
+ return dist;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Distance Utilities
+ * \{ */
+
+/* problem - ofs[3] can be on same location as camera itself.
+ * Blender needs proper dist value for zoom.
+ * use fallback_dist to override small values
+ */
+float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist)
+{
+ float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float dist;
+
+ mul_m4_v4(mat, pos);
+ add_v3_v3(pos, ofs);
+ mul_m4_v4(mat, dir);
+ normalize_v3(dir);
+
+ dist = dot_v3v3(pos, dir);
+
+ if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
+ dist = fallback_dist;
+ }
+
+ return dist;
+}
+
+/**
+ * Set the dist without moving the view (compensate with #RegionView3D.ofs)
+ *
+ * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
+ */
+void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
+{
+ float viewinv[4];
+ float tvec[3];
+
+ BLI_assert(dist >= 0.0f);
+
+ copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
+ /* rv3d->viewinv isn't always valid */
+#if 0
+ mul_mat3_m4_v3(rv3d->viewinv, tvec);
+#else
+ invert_qt_qt_normalized(viewinv, rv3d->viewquat);
+ mul_qt_v3(viewinv, tvec);
+#endif
+ sub_v3_v3(rv3d->ofs, tvec);
+
+ rv3d->dist = dist;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Axis Utilities
+ * \{ */
+static float view3d_quat_axis[6][4] = {
+ {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */
+ {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */
+ {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */
+ {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */
+ {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */
+ {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */
+};
+
+
+bool ED_view3d_quat_from_axis_view(const char view, float quat[4])
+{
+ if (RV3D_VIEW_IS_AXIS(view)) {
+ copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon)
+{
+ /* quat values are all unit length */
+
+ char view;
+
+ for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
+ if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) {
+ return view;
+ }
+ }
+
+ return RV3D_VIEW_USER;
+}
+
+char ED_view3d_lock_view_from_index(int index)
+{
+ switch (index) {
+ case 0: return RV3D_VIEW_FRONT;
+ case 1: return RV3D_VIEW_TOP;
+ case 2: return RV3D_VIEW_RIGHT;
+ default: return RV3D_VIEW_USER;
+ }
+
+}
+
+char ED_view3d_axis_view_opposite(char view)
+{
+ switch (view) {
+ case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK;
+ case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT;
+ case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT;
+ case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT;
+ case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM;
+ case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP;
+ }
+
+ return RV3D_VIEW_USER;
+}
+
+
+bool ED_view3d_lock(RegionView3D *rv3d)
+{
+ return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Transform Utilities
+ * \{ */
+
+/**
+ * Set the view transformation from a 4x4 matrix.
+ *
+ * \param mat The view 4x4 transformation matrix to assign.
+ * \param ofs The view offset, normally from RegionView3D.ofs.
+ * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs, normally from RegionView3D.dist.
+ */
+void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist)
+{
+ float nmat[3][3];
+
+ /* dist depends on offset */
+ BLI_assert(dist == NULL || ofs != NULL);
+
+ copy_m3_m4(nmat, mat);
+ normalize_m3(nmat);
+
+ /* Offset */
+ if (ofs)
+ negate_v3_v3(ofs, mat[3]);
+
+ /* Quat */
+ if (quat) {
+ mat3_normalized_to_quat(quat, nmat);
+ invert_qt_normalized(quat);
+ }
+
+ if (ofs && dist) {
+ madd_v3_v3fl(ofs, nmat[2], *dist);
+ }
+}
+
+/**
+ * Calculate the view transformation matrix from RegionView3D input.
+ * The resulting matrix is equivalent to RegionView3D.viewinv
+ * \param mat The view 4x4 transformation matrix to calculate.
+ * \param ofs The view offset, normally from RegionView3D.ofs.
+ * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs, normally from RegionView3D.dist.
+ */
+void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
+{
+ float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
+ float dvec[3] = {0.0f, 0.0f, dist};
+
+ quat_to_mat4(mat, iviewquat);
+ mul_mat3_m4_v3(mat, dvec);
+ sub_v3_v3v3(mat[3], dvec, ofs);
+}
+
+/**
+ * Set the RegionView3D members from an objects transformation and optionally lens.
+ * \param ob The object to set the view to.
+ * \param ofs The view offset to be set, normally from RegionView3D.ofs.
+ * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs to be set, normally from RegionView3D.dist.
+ * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens.
+ */
+void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
+{
+ ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
+
+ if (lens) {
+ CameraParams params;
+
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, ob);
+ *lens = params.lens;
+ }
+}
+
+/**
+ * Set the object transformation from RegionView3D members.
+ * \param ob The object which has the transformation assigned.
+ * \param ofs The view offset, normally from RegionView3D.ofs.
+ * \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
+ * \param dist The view distance from ofs, normally from RegionView3D.dist.
+ */
+void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist)
+{
+ float mat[4][4];
+ ED_view3d_to_m4(mat, ofs, quat, dist);
+ BKE_object_apply_mat4(ob, mat, true, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Depth Buffer Utilities
+ * \{ */
+
+float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
+{
+ ViewDepths *vd = vc->rv3d->depths;
+
+ int x = mval[0];
+ int y = mval[1];
+
+ if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
+ return vd->depths[y * vd->w + x];
+ }
+ else {
+ BLI_assert(1.0 <= vd->depth_range[1]);
+ return 1.0f;
+ }
+}
+
+bool ED_view3d_depth_read_cached_normal(
+ const ViewContext *vc, const int mval[2],
+ float r_normal[3])
+{
+ /* Note: we could support passing in a radius.
+ * For now just read 9 pixels. */
+
+ /* pixels surrounding */
+ bool depths_valid[9] = {false};
+ float coords[9][3] = {{0}};
+
+ ARegion *ar = vc->ar;
+ const ViewDepths *depths = vc->rv3d->depths;
+
+ for (int x = 0, i = 0; x < 2; x++) {
+ for (int y = 0; y < 2; y++) {
+ const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
+
+ const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) {
+ depths_valid[i] = true;
+ }
+ }
+ i++;
+ }
+ }
+
+ const int edges[2][6][2] = {
+ /* x edges */
+ {{0, 1}, {1, 2},
+ {3, 4}, {4, 5},
+ {6, 7}, {7, 8}},
+ /* y edges */
+ {{0, 3}, {3, 6},
+ {1, 4}, {4, 7},
+ {2, 5}, {5, 8}},
+ };
+
+ float cross[2][3] = {{0.0f}};
+
+ for (int i = 0; i < 6; i++) {
+ for (int axis = 0; axis < 2; axis++) {
+ if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
+ float delta[3];
+ sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
+ add_v3_v3(cross[axis], delta);
+ }
+ }
+ }
+
+ cross_v3_v3v3(r_normal, cross[0], cross[1]);
+
+ if (normalize_v3(r_normal) != 0.0f) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_view3d_depth_unproject(
+ const ARegion *ar,
+ const int mval[2], const double depth,
+ float r_location_world[3])
+{
+ float centx = (float)mval[0] + 0.5f;
+ float centy = (float)mval[1] + 0.5f;
+ return ED_view3d_unproject(ar, centx, centy, depth, r_location_world);
+}
+
+void ED_view3d_depth_tag_update(RegionView3D *rv3d)
+{
+ if (rv3d->depths)
+ rv3d->depths->damaged = true;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 882f0ec0bc0..0597f2806b3 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -28,7 +28,6 @@
* \ingroup spview3d
*/
-
#include "DNA_camera_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -39,7 +38,6 @@
#include "BLI_rect.h"
#include "BLI_utildefines.h"
-#include "BKE_anim.h"
#include "BKE_action.h"
#include "BKE_camera.h"
#include "BKE_context.h"
@@ -48,12 +46,9 @@
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_screen.h"
#include "DEG_depsgraph.h"
-#include "BIF_glutil.h"
-
#include "UI_resources.h"
#include "GPU_glew.h"
@@ -64,10 +59,10 @@
#include "WM_types.h"
#include "ED_screen.h"
-#include "ED_armature.h"
#include "DRW_engine.h"
+#include "DEG_depsgraph_query.h"
#ifdef WITH_GAMEENGINE
# include "BLI_listbase.h"
@@ -78,53 +73,14 @@
# include "BL_System.h"
#endif
-
#include "view3d_intern.h" /* own include */
-/* use this call when executing an operator,
- * event system doesn't set for each event the
- * opengl drawing context */
-void view3d_operator_needs_opengl(const bContext *C)
-{
- wmWindow *win = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
-
- view3d_region_operator_needs_opengl(win, ar);
-}
-
-void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
-{
- /* for debugging purpose, context should always be OK */
- if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) {
- printf("view3d_region_operator_needs_opengl error, wrong region\n");
- }
- else {
- RegionView3D *rv3d = ar->regiondata;
-
- wmSubWindowSet(win, ar->swinid);
- gpuLoadProjectionMatrix(rv3d->winmat);
- gpuLoadMatrix(rv3d->viewmat);
- }
-}
-
-float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d)
-{
- if (v3d && v3d->localvd) return v3d->cursor;
- else return scene->cursor;
-}
-
-Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
-{
- /* establish the camera object, so we can default to view mapping if anything is wrong with it */
- if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
- return v3d->camera->data;
- }
- else {
- return NULL;
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Smooth View Operator & Utilities
+ *
+ * Use for view transitions to have smooth (animated) transitions.
+ * \{ */
-/* ****************** smooth view operator ****************** */
/* This operator is one of the 'timer refresh' ones like animation playback */
struct SmoothView3DState {
@@ -273,7 +229,7 @@ void ED_view3d_smooth_view_ex(
* this means small rotations wont lag */
if (sview->quat && !sview->ofs && !sview->dist) {
/* scale the time allowed by the rotation */
- sms.time_allowed *= (double)angle_normalized_qtqt(sms.dst.quat, sms.src.quat) / M_PI; /* 180deg == 1.0 */
+ sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) / M_PI; /* 180deg == 1.0 */
}
/* ensure it shows correct */
@@ -401,6 +357,8 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
+ /* Event handling won't know if a UI item has been moved under the pointer. */
+ WM_event_add_mousemove(C);
}
if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) {
@@ -462,22 +420,25 @@ void ED_view3d_smooth_view_force_finish(
void VIEW3D_OT_smoothview(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Smooth View";
ot->description = "";
ot->idname = "VIEW3D_OT_smoothview";
-
+
/* api callbacks */
ot->invoke = view3d_smoothview_invoke;
-
+
/* flags */
ot->flag = OPTYPE_INTERNAL;
ot->poll = ED_operator_view3d_active;
}
-/* ****************** change view operators ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera to View Operator
+ * \{ */
static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -541,6 +502,12 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera Fit Frame to Selected Operator
+ * \{ */
+
/* unlike VIEW3D_OT_view_selected this is for framing a render and not
* meant to take into account vertex/bone selection for eg. */
static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
@@ -600,6 +567,12 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object as Camera Operator
+ * \{ */
+
static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob, const int smooth_viewtx)
{
Main *bmain = CTX_data_main(C);
@@ -650,7 +623,7 @@ static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob
}
static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
-{
+{
View3D *v3d;
ARegion *ar;
RegionView3D *rv3d;
@@ -703,7 +676,6 @@ int ED_operator_rv3d_user_region_poll(bContext *C)
void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Set Active Object as Camera";
ot->description = "Set the active object as the active camera for this view or scene";
@@ -717,289 +689,23 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************** */
-
-void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
-{
- int val;
-
- for (val = 0; val < 4; val++) {
- normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
- if (UNLIKELY(is_flip)) {
- negate_v3(clip[val]);
- }
-
- clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
- }
-}
-
-void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect)
-{
- /* init in case unproject fails */
- memset(bb->vec, 0, sizeof(bb->vec));
-
- /* four clipping planes and bounding volume */
- /* first do the bounding volume */
- for (int val = 0; val < 4; val++) {
- float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
- float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
-
- ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]);
- ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]);
- }
-
- /* optionally transform to object space */
- if (ob) {
- float imat[4][4];
- invert_m4_m4(imat, ob->obmat);
-
- for (int val = 0; val < 8; val++) {
- mul_m4_v3(imat, bb->vec[val]);
- }
- }
-
- /* verify if we have negative scale. doing the transform before cross
- * product flips the sign of the vector compared to doing cross product
- * before transform then, so we correct for that. */
- int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false;
-
- ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
-}
-
-static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
-{
- int a, flag = -1, fl;
-
- for (a = 0; a < 8; a++) {
- float vec[4], min, max;
- copy_v3_v3(vec, bb->vec[a]);
- vec[3] = 1.0;
- mul_m4_v4(persmatob, vec);
- max = vec[3];
- min = -vec[3];
-
- fl = 0;
- if (vec[0] < min) fl += 1;
- if (vec[0] > max) fl += 2;
- if (vec[1] < min) fl += 4;
- if (vec[1] > max) fl += 8;
- if (vec[2] < min) fl += 16;
- if (vec[2] > max) fl += 32;
-
- flag &= fl;
- if (flag == 0) return true;
- }
-
- return false;
-}
-
-bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
-{
- /* return 1: draw */
-
- float persmatob[4][4];
-
- if (bb == NULL) return true;
- if (bb->flag & BOUNDBOX_DISABLED) return true;
-
- mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
-
- return view3d_boundbox_clip_m4(bb, persmatob);
-}
-
-bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
-{
- if (bb == NULL) return true;
- if (bb->flag & BOUNDBOX_DISABLED) return true;
-
- return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
-}
+/** \} */
/* -------------------------------------------------------------------- */
-
-/** \name Depth Utilities
+/** \name Window and View Matrix Calculation
* \{ */
-float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
-{
- ViewDepths *vd = vc->rv3d->depths;
-
- int x = mval[0];
- int y = mval[1];
-
- if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
- return vd->depths[y * vd->w + x];
- }
- else {
- BLI_assert(1.0 <= vd->depth_range[1]);
- return 1.0f;
- }
-}
-
-bool ED_view3d_depth_read_cached_normal(
- const ViewContext *vc, const int mval[2],
- float r_normal[3])
-{
- /* Note: we could support passing in a radius.
- * For now just read 9 pixels. */
-
- /* pixels surrounding */
- bool depths_valid[9] = {false};
- float coords[9][3] = {{0}};
-
- ARegion *ar = vc->ar;
- const ViewDepths *depths = vc->rv3d->depths;
-
- for (int x = 0, i = 0; x < 2; x++) {
- for (int y = 0; y < 2; y++) {
- const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
-
- const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
- if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) {
- depths_valid[i] = true;
- }
- }
- i++;
- }
- }
-
- const int edges[2][6][2] = {
- /* x edges */
- {{0, 1}, {1, 2},
- {3, 4}, {4, 5},
- {6, 7}, {7, 8}},
- /* y edges */
- {{0, 3}, {3, 6},
- {1, 4}, {4, 7},
- {2, 5}, {5, 8}},
- };
-
- float cross[2][3] = {{0.0f}};
-
- for (int i = 0; i < 6; i++) {
- for (int axis = 0; axis < 2; axis++) {
- if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
- float delta[3];
- sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
- add_v3_v3(cross[axis], delta);
- }
- }
- }
-
- cross_v3_v3v3(r_normal, cross[0], cross[1]);
-
- if (normalize_v3(r_normal) != 0.0f) {
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ED_view3d_depth_unproject(
- const ARegion *ar,
- const int mval[2], const double depth,
- float r_location_world[3])
-{
- float centx = (float)mval[0] + 0.5f;
- float centy = (float)mval[1] + 0.5f;
- return ED_view3d_unproject(ar, centx, centy, depth, r_location_world);
-}
-
-/** \} */
-
-void ED_view3d_depth_tag_update(RegionView3D *rv3d)
-{
- if (rv3d->depths)
- rv3d->depths->damaged = true;
-}
-
-void ED_view3d_dist_range_get(
- const View3D *v3d,
- float r_dist_range[2])
-{
- r_dist_range[0] = v3d->grid * 0.001f;
- r_dist_range[1] = v3d->far * 10.0f;
-}
-
-/* copies logic of get_view3d_viewplane(), keep in sync */
-bool ED_view3d_clip_range_get(
- const View3D *v3d, const RegionView3D *rv3d,
- float *r_clipsta, float *r_clipend,
- const bool use_ortho_factor)
-{
- CameraParams params;
-
- BKE_camera_params_init(&params);
- BKE_camera_params_from_view3d(&params, v3d, rv3d);
-
- if (use_ortho_factor && params.is_ortho) {
- const float fac = 2.0f / (params.clipend - params.clipsta);
- params.clipsta *= fac;
- params.clipend *= fac;
- }
-
- if (r_clipsta) *r_clipsta = params.clipsta;
- if (r_clipend) *r_clipend = params.clipend;
-
- return params.is_ortho;
-}
-
-bool ED_view3d_viewplane_get(
- const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
- rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
-{
- CameraParams params;
-
- BKE_camera_params_init(&params);
- BKE_camera_params_from_view3d(&params, v3d, rv3d);
- BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
-
- if (r_viewplane) *r_viewplane = params.viewplane;
- if (r_clipsta) *r_clipsta = params.clipsta;
- if (r_clipend) *r_clipend = params.clipend;
- if (r_pixsize) *r_pixsize = params.viewdx;
-
- return params.is_ortho;
-}
-
-/**
- * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727]
- */
-void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
-{
- float viewdist;
-
- if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
- return;
- }
-
- viewdist = rv3d->dist;
-
- /* special exception for ortho camera (viewdist isnt used for perspective cameras) */
- if (dist != 0.0f) {
- if (rv3d->persp == RV3D_CAMOB) {
- if (rv3d->is_persp == false) {
- viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
- }
- }
- }
-
- bglPolygonOffset(viewdist, dist);
-}
-
/**
* \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
+void view3d_winmatrix_set(const Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
float clipsta, clipend;
bool is_ortho;
- is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
+ is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
rv3d->is_persp = !is_ortho;
#if 0
@@ -1041,80 +747,28 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat);
}
-static float view3d_quat_axis[6][4] = {
- {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */
- {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */
- {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */
- {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */
- {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */
- {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */
-};
-
-
-bool ED_view3d_quat_from_axis_view(const char view, float quat[4])
-{
- if (RV3D_VIEW_IS_AXIS(view)) {
- copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]);
- return true;
- }
- else {
- return false;
- }
-}
-
-char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon)
-{
- /* quat values are all unit length */
-
- char view;
-
- for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
- if (angle_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]) < epsilon) {
- return view;
- }
- }
-
- return RV3D_VIEW_USER;
-}
-
-char ED_view3d_lock_view_from_index(int index)
-{
- switch (index) {
- case 0: return RV3D_VIEW_FRONT;
- case 1: return RV3D_VIEW_TOP;
- case 2: return RV3D_VIEW_RIGHT;
- default: return RV3D_VIEW_USER;
- }
-
-}
-
-char ED_view3d_axis_view_opposite(char view)
-{
- switch (view) {
- case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK;
- case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT;
- case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT;
- case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT;
- case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM;
- case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP;
- }
-
- return RV3D_VIEW_USER;
-}
-
-
-bool ED_view3d_lock(RegionView3D *rv3d)
-{
- return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
-}
-
-/* don't set windows active in here, is used by renderwin too */
-void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d)
+/**
+ * Sets #RegionView3D.viewmat
+ *
+ * \param eval_ctx: Context.
+ * \param scene: Scene for camera and cursor location.
+ * \param v3d: View 3D space data.
+ * \param rv3d: 3D region which stores the final matrices.
+ * \param rect_scale: Optional 2D scale argument,
+ * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
+ *
+ * \note don't set windows active in here, is used by renderwin too.
+ */
+void view3d_viewmatrix_set(
+ const EvaluationContext *eval_ctx, Scene *scene,
+ const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2])
{
if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */
if (v3d->camera) {
- BKE_object_where_is_calc(eval_ctx, scene, v3d->camera);
- obmat_to_viewmat(rv3d, v3d->camera);
+ const Depsgraph *depsgraph = eval_ctx->depsgraph;
+ Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_object_where_is_calc(eval_ctx, scene, camera_object);
+ obmat_to_viewmat(rv3d, camera_object);
}
else {
quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
@@ -1168,6 +822,17 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons
mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f);
vec[2] = 0.0f;
+
+ if (rect_scale) {
+ /* Since 'RegionView3D.winmat' has been calculated and this function doesn't take the 'ARegion'
+ * we don't know about the region size.
+ * Use 'rect_scale' when drawing a sub-region to apply 2D offset,
+ * scaled by the difference between the sub-region and the region size.
+ */
+ vec[0] /= rect_scale[0];
+ vec[1] /= rect_scale[1];
+ }
+
mul_mat3_m4_v3(persinv, vec);
translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]);
}
@@ -1175,6 +840,12 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name OpenGL Select Utilities
+ * \{ */
+
/**
* Optionally cache data for multiple calls to #view3d_opengl_select
*
@@ -1326,6 +997,12 @@ finally:
return hits;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer Utilities
+ * \{ */
+
int ED_view3d_view_layer_set(int lay, const int *values, int *active)
{
int i, tot = 0;
@@ -1364,43 +1041,43 @@ int ED_view3d_view_layer_set(int lay, const int *values, int *active)
return lay;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Game Engine Operator
+ *
+ * Start the game engine (handles context switching).
+ * \{ */
+
#ifdef WITH_GAMEENGINE
static ListBase queue_back;
-static void SaveState(bContext *C, wmWindow *win)
+static void game_engine_save_state(bContext *C, wmWindow *win)
{
Object *obact = CTX_data_active_object(C);
-
+
glPushAttrib(GL_ALL_ATTRIB_BITS);
if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
GPU_paint_set_mipmap(1);
-
+
queue_back = win->queue;
-
+
BLI_listbase_clear(&win->queue);
-
- //XXX waitcursor(1);
}
-static void RestoreState(bContext *C, wmWindow *win)
+static void game_engine_restore_state(bContext *C, wmWindow *win)
{
Object *obact = CTX_data_active_object(C);
-
+
if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
GPU_paint_set_mipmap(0);
- //XXX curarea->win_swap = 0;
- //XXX curarea->head_swap = 0;
- //XXX allqueue(REDRAWVIEW3D, 1);
- //XXX allqueue(REDRAWBUTSALL, 0);
- //XXX reset_slowparents();
- //XXX waitcursor(0);
- //XXX G.qual = 0;
-
- if (win) /* check because closing win can set to NULL */
+ /* check because closing win can set to NULL */
+ if (win) {
win->queue = queue_back;
-
+ }
+
GPU_state_init();
glPopAttrib();
@@ -1471,33 +1148,6 @@ static int game_engine_poll(bContext *C)
return 1;
}
-bool ED_view3d_context_activate(bContext *C)
-{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar;
-
- /* sa can be NULL when called from python */
- if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
- sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
- }
-
- if (sa == NULL) {
- return false;
- }
-
- ar = BKE_area_find_region_active_win(sa);
- if (ar == NULL) {
- return false;
- }
-
- /* bad context switch .. */
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- return true;
-}
-
static int game_engine_exec(bContext *C, wmOperator *op)
{
#ifdef WITH_GAMEENGINE
@@ -1509,12 +1159,12 @@ static int game_engine_exec(bContext *C, wmOperator *op)
RegionView3D *rv3d;
rcti cam_frame;
- (void)op; /* unused */
-
+ UNUSED_VARS(op);
+
/* bad context switch .. */
if (!ED_view3d_context_activate(C))
return OPERATOR_CANCELLED;
-
+
/* redraw to hide any menus/popups, we don't go back to
* the window manager until after this operator exits */
WM_redraw_windows(C);
@@ -1526,16 +1176,17 @@ static int game_engine_exec(bContext *C, wmOperator *op)
ar = CTX_wm_region(C);
view3d_operator_needs_opengl(C);
-
+
game_set_commmandline_options(&startscene->gm);
if ((rv3d->persp == RV3D_CAMOB) &&
(startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) &&
(startscene->gm.stereoflag != STEREO_DOME))
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
/* Letterbox */
rctf cam_framef;
- ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false);
+ ED_view3d_calc_camera_border(startscene, depsgraph, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false);
cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
@@ -1550,7 +1201,7 @@ static int game_engine_exec(bContext *C, wmOperator *op)
}
- SaveState(C, prevwin);
+ game_engine_save_state(C, prevwin);
StartKetsjiShell(C, ar, &cam_frame, 1);
@@ -1559,7 +1210,7 @@ static int game_engine_exec(bContext *C, wmOperator *op)
prevwin = NULL;
CTX_wm_window_set(C, NULL);
}
-
+
ED_area_tag_redraw(CTX_wm_area(C));
if (prevwin) {
@@ -1570,7 +1221,7 @@ static int game_engine_exec(bContext *C, wmOperator *op)
CTX_wm_area_set(C, prevsa);
}
- RestoreState(C, prevwin);
+ game_engine_restore_state(C, prevwin);
//XXX restore_all_scene_cfra(scene_cfra_store);
BKE_scene_set_background(CTX_data_main(C), startscene);
@@ -1580,7 +1231,7 @@ static int game_engine_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
#else
- (void)C; /* unused */
+ UNUSED_VARS(C);
BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
return OPERATOR_CANCELLED;
#endif
@@ -1588,168 +1239,15 @@ static int game_engine_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_game_start(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Start Game Engine";
ot->description = "Start game engine";
ot->idname = "VIEW3D_OT_game_start";
-
+
/* api callbacks */
ot->exec = game_engine_exec;
-
- ot->poll = game_engine_poll;
-}
-
-/* ************************************** */
-
-float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
-{
- return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
-}
-
-float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
-{
- return radius * (1.0f / tanf(angle / 2.0f));
-}
-
-float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
-{
- return radius / (DEFAULT_SENSOR_WIDTH / lens);
-}
-
-/**
- * Return a new RegionView3D.dist value to fit the \a radius.
- *
- * \note Depth isn't taken into account, this will fit a flat plane exactly,
- * but points towards the view (with a perspective projection),
- * may be within the radius but outside the view. eg:
- *
- * <pre>
- * +
- * pt --> + /^ radius
- * / |
- * / |
- * view + +
- * \ |
- * \ |
- * \|
- * +
- * </pre>
- *
- * \param ar Can be NULL if \a use_aspect is false.
- * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera)
- * \param use_aspect Increase the distance to account for non 1:1 view aspect.
- * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
- */
-float ED_view3d_radius_to_dist(
- const View3D *v3d, const ARegion *ar,
- const char persp, const bool use_aspect,
- const float radius)
-{
- float dist;
-
- BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
- BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
-
- if (persp == RV3D_ORTHO) {
- dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
- }
- else {
- float lens, sensor_size, zoom;
- float angle;
-
- if (persp == RV3D_CAMOB) {
- CameraParams params;
- BKE_camera_params_init(&params);
- params.clipsta = v3d->near;
- params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
-
- lens = params.lens;
- sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
- /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
- zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
- }
- else {
- lens = v3d->lens;
- sensor_size = DEFAULT_SENSOR_WIDTH;
- zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
- }
-
- angle = focallength_to_fov(lens, sensor_size);
-
- /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
- angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
-
- dist = ED_view3d_radius_to_dist_persp(angle, radius);
- }
-
- if (use_aspect) {
- const RegionView3D *rv3d = ar->regiondata;
-
- float winx, winy;
-
- if (persp == RV3D_CAMOB) {
- /* camera frame x/y in pixels */
- winx = ar->winx / rv3d->viewcamtexcofac[0];
- winy = ar->winy / rv3d->viewcamtexcofac[1];
- }
- else {
- winx = ar->winx;
- winy = ar->winy;
- }
-
- if (winx && winy) {
- float aspect = winx / winy;
- if (aspect < 1.0f) {
- aspect = 1.0f / aspect;
- }
- dist *= aspect;
- }
- }
-
- return dist;
-}
-
-/* view matrix properties utilities */
-
-/* unused */
-#if 0
-void ED_view3d_operator_properties_viewmat(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(prop, PROP_HIDDEN);
-}
-
-void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op)
-{
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ED_view3d_context_rv3d(C);
-
- if (!RNA_struct_property_is_set(op->ptr, "region_width"))
- RNA_int_set(op->ptr, "region_width", ar->winx);
-
- if (!RNA_struct_property_is_set(op->ptr, "region_height"))
- RNA_int_set(op->ptr, "region_height", ar->winy);
-
- if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix"))
- RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat);
+ ot->poll = game_engine_poll;
}
-void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4])
-{
- *winx = RNA_int_get(op->ptr, "region_width");
- *winy = RNA_int_get(op->ptr, "region_height");
-
- RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat);
-}
-#endif
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 76da1faf530..e65f9abae27 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -60,6 +60,8 @@
#include "RE_engine.h"
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
#ifdef WITH_INPUT_NDOF
@@ -249,6 +251,7 @@ typedef struct WalkInfo {
RegionView3D *rv3d;
View3D *v3d;
ARegion *ar;
+ const struct Depsgraph *depsgraph;
Scene *scene;
ViewLayer *view_layer;
RenderEngineType *engine_type;
@@ -334,7 +337,7 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a
rctf viewborder;
if (walk->scene->camera) {
- ED_view3d_calc_camera_border(walk->scene, ar, walk->v3d, walk->rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(walk->scene, walk->depsgraph, ar, walk->v3d, walk->rv3d, &viewborder, false);
xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f;
yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f;
}
@@ -509,10 +512,14 @@ static float userdef_speed = -1.f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
+ EvaluationContext eval_ctx;
+
+ CTX_data_eval_ctx(C, &eval_ctx);
walk->rv3d = CTX_wm_region_view3d(C);
walk->v3d = CTX_wm_view3d(C);
walk->ar = CTX_wm_region(C);
+ walk->depsgraph = CTX_data_depsgraph(C);
walk->scene = CTX_data_scene(C);
walk->view_layer = CTX_data_view_layer(C);
walk->engine_type = CTX_data_engine_type(C);
@@ -608,7 +615,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
- C, walk->scene, walk->v3d, walk->rv3d,
+ &eval_ctx, walk->scene, walk->v3d, walk->rv3d,
(U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
/* center the mouse */
@@ -716,7 +723,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
return;
}
- if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) {
+ if ((walk->is_cursor_absolute == false) && event->is_motion_absolute) {
walk->is_cursor_absolute = true;
copy_v2_v2_int(walk->prev_mval, event->mval);
copy_v2_v2_int(walk->center_mval, event->mval);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 5a63532b0f5..9f7b438e338 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1969,7 +1969,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
// If modal, save settings back in scene if not set as operator argument
- if (t->flag & T_MODAL) {
+ if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
/* save settings if not set in operator */
/* skip saving proportional edit if it was not actually used */
@@ -1989,10 +1989,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->proportional_objects = (proportional != PROP_EDIT_OFF);
}
- if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
- !RNA_property_is_set(op->ptr, prop))
- {
- ts->proportional_size = t->prop_size;
+ if ((prop = RNA_struct_find_property(op->ptr, "proportional_size"))) {
+ ts->proportional_size =
+ RNA_property_is_set(op->ptr, prop) ? RNA_property_float_get(op->ptr, prop) : t->prop_size;
}
if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
@@ -5654,12 +5653,12 @@ static void slide_origdata_interp_data_vert(
if (sod->layer_math_map_num) {
if (do_loop_weight) {
for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
+ BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
}
}
else {
for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
+ BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
}
}
}
@@ -6034,7 +6033,9 @@ static void calcEdgeSlide_mval_range(
continue;
/* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) {
+ if (use_occlude_geometry &&
+ !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, t->obedit))
+ {
continue;
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index d9bfcd0c289..4ad66c0a9a5 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -43,6 +43,7 @@
/* ************************** Types ***************************** */
+struct Depsgraph;
struct TransInfo;
struct TransData;
struct TransformOrientation;
@@ -468,6 +469,7 @@ typedef struct TransInfo {
struct bContext *context; /* Only valid (non null) during an operator called function. */
struct ScrArea *sa;
struct ARegion *ar;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct ViewLayer *view_layer;
struct RenderEngineType *engine_type;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 10a7677f42b..1aa4513e99b 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1115,6 +1115,7 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
*/
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *sce = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1125,7 +1126,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
bGPdata *gpd = CTX_data_gpencil_data(C);
RenderEngineType *engine_type = CTX_data_engine_type(C);
PropertyRNA *prop;
-
+
+ t->depsgraph = depsgraph;
t->scene = sce;
t->view_layer = view_layer;
t->engine_type = engine_type;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 0e0c2f3ae25..0643687c29a 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -1155,6 +1155,8 @@ static void manipulator_xform_message_subscribe(
else {
BLI_assert(0);
}
+
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh);
}
/** \} */
@@ -1177,14 +1179,17 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
#define MANIPULATOR_NEW_ARROW(v, draw_style) { \
man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \
RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
+ WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \
} ((void)0)
#define MANIPULATOR_NEW_DIAL(v, draw_options) { \
man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \
RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \
+ WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \
} ((void)0)
#define MANIPULATOR_NEW_PRIM(v, draw_style) { \
man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \
RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
+ WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \
} ((void)0)
/* add/init widgets - order matters! */
@@ -1604,6 +1609,7 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup
manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
+ WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true);
float dims[3];
sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 63cd5291193..f8b11a0bcae 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -735,10 +735,19 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
SWAP(BMVert *, v_pair[0], v_pair[1]);
}
- add_v3_v3v3(normal, v_pair[0]->no, v_pair[1]->no);
- sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
- /* flip the plane normal so we point outwards */
- negate_v3(plane);
+ add_v3_v3v3(normal, v_pair[1]->no, v_pair[0]->no);
+ sub_v3_v3v3(plane, v_pair[1]->co, v_pair[0]->co);
+
+ if (normalize_v3(plane) != 0.0f) {
+ /* For edges it'd important the resulting matrix can rotate around the edge,
+ * project onto the plane so we can use a fallback value. */
+ project_plane_normalized_v3_v3v3(normal, normal, plane);
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ /* in the case the normal and plane are aligned,
+ * use a fallback normal which is orthogonal to the plane. */
+ ortho_v3_v3(normal, plane);
+ }
+ }
}
result = ORIENTATION_EDGE;
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index ce8de2ef4d3..8f0590eb5b9 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -141,7 +141,7 @@ struct SnapObjectContext {
/* -------------------------------------------------------------------- */
/** Common utilities
-* \{ */
+ * \{ */
typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data);
@@ -264,7 +264,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
/* -------------------------------------------------------------------- */
/** \name Ray Cast Funcs
-* \{ */
+ * \{ */
/* Store all ray-hits
* Support for storing all depths, not just the first (raycast 'all') */
@@ -2372,6 +2372,7 @@ bool ED_transform_snap_object_project_view3d_ex(
ED_view3d_win_to_vector(ar, mval, ray_normal);
ED_view3d_clip_range_get(
+ sctx->eval_ctx.depsgraph,
sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata,
&depth_range[0], &depth_range[1], false);
@@ -2438,6 +2439,7 @@ bool ED_transform_snap_object_project_all_view3d_ex(
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_ex(
+ sctx->eval_ctx.depsgraph,
sctx->v3d_data.ar, sctx->v3d_data.v3d,
mval, NULL, ray_normal, ray_start, true))
{
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index db6f2c27623..45fa35766f1 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -622,7 +622,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- unsigned int pos;
+ unsigned int pos, color;
efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */
ts = scene->toolsettings;
@@ -671,58 +671,61 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
if (sima->flag & SI_DRAW_STRETCH) {
draw_uvs_stretch(sima, scene, em, efa_act);
}
- else if (!(sima->flag & SI_NO_DRAWFACES)) {
- /* draw transparent faces */
- UI_GetThemeColor4ubv(TH_FACE, col1);
- UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
-
- pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- for (unsigned int i = 0; i < em->tottri; i++) {
- efa = em->looptris[i][0]->f;
+ else {
+ unsigned int tri_count = 0;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
if (uvedit_face_visible_test(scene, ima, efa)) {
- const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset);
BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- if (efa == efa_act) {
- /* only once */
- immUniformThemeColor(TH_EDITMESH_ACTIVE);
- }
- else {
- immUniformColor4ubv(is_select ? col2 : col1);
- }
-
- immBegin(GWN_PRIM_TRIS, (em->looptris[i][0]->f->len - 2) * 3);
- draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos);
- immEnd();
+ tri_count += efa->len - 2;
}
else {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
- immUnbindProgram();
+ if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) {
+ /* draw transparent faces */
+ UI_GetThemeColor4ubv(TH_FACE, col1);
+ UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
- glDisable(GL_BLEND);
- }
- else {
- /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, ima, efa)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ Gwn_VertFormat *format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ immBegin(GWN_PRIM_TRIS, tri_count * 3);
+ for (unsigned int i = 0; i < em->tottri; i++) {
+ efa = em->looptris[i][0]->f;
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset);
+
+ if (efa == efa_act) {
+ /* only once */
+ unsigned char tmp_col[4];
+ UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col);
+ immAttrib4ubv(color, tmp_col);
+ }
+ else {
+ immAttrib4ubv(color, is_select ? col2 : col1);
+ }
+
+ draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos);
+ }
}
- else {
- if (efa == efa_act)
- efa_act = NULL;
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ immEnd();
+
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+ }
+ else {
+ if (efa_act && !uvedit_face_visible_test(scene, ima, efa_act)) {
+ efa_act = NULL;
}
}
-
}
/* 3. draw active face stippled */
@@ -813,7 +816,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
Gwn_VertFormat *format = immVertexFormat();
pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
if (interpedges) {
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
@@ -900,7 +903,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
Gwn_VertFormat *format = immVertexFormat();
pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index f8aef2a08ae..0b09a3c2442 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -157,7 +157,7 @@ static PyObject *Freestyle_blendRamp(PyObject * /*self*/, PyObject *args)
return Vector_CreatePyObject(a, 3, NULL);
}
-#include "BKE_texture.h" /* do_colorband() */
+#include "BKE_colorband.h" /* BKE_colorband_evaluate() */
static char Freestyle_evaluateColorRamp___doc__[] =
".. function:: evaluateColorRamp(ramp, in)\n"
@@ -184,7 +184,7 @@ static PyObject *Freestyle_evaluateColorRamp(PyObject * /*self*/, PyObject *args
return NULL;
}
coba = (ColorBand *)py_srna->ptr.data;
- if (!do_colorband(coba, in, out)) {
+ if (!BKE_colorband_evaluate(coba, in, out)) {
PyErr_SetString(PyExc_ValueError, "failed to evaluate the color ramp");
return NULL;
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 18a1ef36bdc..0ac842d90a0 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -52,6 +52,7 @@ set(INC_SYS
set(SRC
intern/gpu_basic_shader.c
intern/gpu_batch.c
+ intern/gpu_batch_presets.c
intern/gpu_buffers.c
intern/gpu_codegen.c
intern/gpu_compositing.c
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 6d16092996e..d2f3409dc07 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -33,19 +33,36 @@
#include "../../../intern/gawain/gawain/gwn_batch.h"
+struct rctf;
+
// TODO: CMake magic to do this:
// #include "gawain/batch.h"
+#include "BLI_compiler_attrs.h"
+
#include "GPU_shader.h"
/* Extend GWN_batch_program_set to use Blender’s library of built-in shader programs. */
-void GWN_batch_program_set_builtin(Gwn_Batch *, GPUBuiltinShader);
-/* Replacement for gluSphere */
-Gwn_Batch *GPU_batch_preset_sphere(int lod);
-Gwn_Batch *GPU_batch_preset_sphere_wire(int lod);
+/* gpu_batch.c */
+void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) ATTR_NONNULL(1);
+
+Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void gpu_batch_init(void);
void gpu_batch_exit(void);
+/* gpu_batch_presets.c */
+/* Replacement for gluSphere */
+Gwn_Batch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT;
+Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT;
+
+void gpu_batch_presets_init(void);
+void gpu_batch_presets_exit(void);
+
#endif /* __GPU_BATCH_H__ */
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 30fd4bd30b8..0d8a7a45ee9 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -238,10 +238,16 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
/* update */
+enum {
+ GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR = (1 << 0),
+ GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
+};
+
void GPU_pbvh_mesh_buffers_update(
GPU_PBVH_Buffers *buffers, const struct MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
- const int (*face_vert_indices)[3], bool show_diffuse_color);
+ const int (*face_vert_indices)[3],
+ const int update_flags);
void GPU_pbvh_bmesh_buffers_update(
GPU_PBVH_Buffers *buffers,
@@ -249,13 +255,13 @@ void GPU_pbvh_bmesh_buffers_update(
struct GSet *bm_faces,
struct GSet *bm_unique_verts,
struct GSet *bm_other_verts,
- bool show_diffuse_color);
+ const int update_flags);
void GPU_pbvh_grid_buffers_update(
GPU_PBVH_Buffers *buffers, struct CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
int *grid_indices, int totgrid, const struct CCGKey *key,
- bool show_diffuse_color);
+ const int update_flags);
/* draw */
void GPU_pbvh_buffers_draw(
@@ -267,6 +273,7 @@ struct Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fas
void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
+bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask);
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
void GPU_pbvh_multires_buffers_free(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 705ef1997c1..c58d98c201e 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -83,7 +83,7 @@ void GPU_framebuffer_recursive_downsample(
* - wrapper around framebuffer and texture for simple offscreen drawing
* - changes size if graphics card can't support it */
-GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]);
+GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256]);
void GPU_offscreen_free(GPUOffScreen *ofs);
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 82e215f6fae..1b64d66469b 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -67,6 +67,7 @@ typedef enum GPUTextureFormat {
GPU_RGBA8,
GPU_RG32F,
GPU_RG16F,
+ GPU_RG16I,
GPU_R32F,
GPU_R16F,
GPU_RG8,
@@ -82,7 +83,6 @@ typedef enum GPUTextureFormat {
GPU_RG32I,
GPU_RG32UI,
GPU_RG16,
- GPU_RG16I,
GPU_RG16UI,
GPU_RG8I,
GPU_RG8UI,
@@ -152,6 +152,8 @@ GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_ou
GPUTexture *GPU_texture_create_2D_custom(
int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_custom_multisample(
+ int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]);
GPUTexture *GPU_texture_create_2D_array_custom(
int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]);
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index f2bb05a6d1e..580ff64befb 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -47,10 +47,8 @@ typedef struct GPUViewport GPUViewport;
typedef struct ViewportMemoryPool {
struct BLI_mempool *calls;
struct BLI_mempool *calls_generate;
- struct BLI_mempool *calls_dynamic;
struct BLI_mempool *shgroups;
struct BLI_mempool *uniforms;
- struct BLI_mempool *attribs;
struct BLI_mempool *passes;
} ViewportMemoryPool;
@@ -106,6 +104,7 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs);
void GPU_viewport_clear_from_offscreen(GPUViewport *viewport);
ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport);
+struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport);
void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type);
void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type);
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 5d347fc80e8..0400fc1025b 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -25,147 +25,257 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/** \file blender/gpu/intern/gpu_basic_shader.c
+ * \ingroup gpu
+ */
+
+#include "MEM_guardedalloc.h"
+
#include "BLI_utildefines.h"
+#include "BLI_rect.h"
#include "BLI_math.h"
+#include "BLI_polyfill2d.h"
+#include "BLI_sort_utils.h"
-#include "GPU_batch.h"
+
+#include "GPU_batch.h" /* own include */
#include "gpu_shader_private.h"
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id)
{
GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
GWN_batch_program_set(batch, shader->program, shader->interface);
}
-static Gwn_Batch *sphere_high = NULL;
-static Gwn_Batch *sphere_med = NULL;
-static Gwn_Batch *sphere_low = NULL;
-static Gwn_Batch *sphere_wire_low = NULL;
-static Gwn_Batch *sphere_wire_med = NULL;
+/** \} */
-static Gwn_VertBuf *vbo;
-static Gwn_VertFormat format = {0};
-static unsigned int pos_id, nor_id;
-static unsigned int vert;
-static void batch_sphere_lat_lon_vert(float lat, float lon)
-{
- float pos[3];
- pos[0] = sinf(lat) * cosf(lon);
- pos[1] = cosf(lat);
- pos[2] = sinf(lat) * sinf(lon);
- GWN_vertbuf_attr_set(vbo, nor_id, vert, pos);
- GWN_vertbuf_attr_set(vbo, pos_id, vert++, pos);
-}
+/* -------------------------------------------------------------------- */
+/** \name Batch Creation
+ * \{ */
-/* Replacement for gluSphere */
-static Gwn_Batch *batch_sphere(int lat_res, int lon_res)
+/**
+ * Creates triangles from a byte-array of polygons.
+ *
+ * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
+ *
+ * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
+ * \param polys_flat_len: Length of the array (must be an even number).
+ * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
+ */
+Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const rctf *rect)
{
- const float lon_inc = 2 * M_PI / lon_res;
- const float lat_inc = M_PI / lat_res;
- float lon, lat;
+ const uchar (*polys)[2] = (const void *)polys_flat;
+ const uint polys_len = polys_flat_len / 2;
+ BLI_assert(polys_flat_len == polys_len * 2);
- if (format.attrib_ct == 0) {
- pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- }
+ /* Over alloc in both cases */
+ float (*verts)[2] = MEM_mallocN(sizeof(*verts) * polys_len, __func__);
+ float (*verts_step)[2] = verts;
+ uint (*tris)[3] = MEM_mallocN(sizeof(*tris) * polys_len, __func__);
+ uint (*tris_step)[3] = tris;
- vbo = GWN_vertbuf_create_with_format(&format);
- GWN_vertbuf_data_alloc(vbo, (lat_res - 1) * lon_res * 6);
- vert = 0;
-
- lon = 0.0f;
- for (int i = 0; i < lon_res; i++, lon += lon_inc) {
- lat = 0.0f;
- for (int j = 0; j < lat_res; j++, lat += lat_inc) {
- if (j != lat_res - 1) { /* Pole */
- batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc);
- batch_sphere_lat_lon_vert(lat + lat_inc, lon);
- batch_sphere_lat_lon_vert(lat, lon);
- }
+ const float range_uchar[2] = {
+ (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f,
+ (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f,
+ };
+ const float min_uchar[2] = {
+ (rect ? rect->xmin : -1.0f),
+ (rect ? rect->ymin : -1.0f),
+ };
- if (j != 0) { /* Pole */
- batch_sphere_lat_lon_vert(lat, lon + lon_inc);
- batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc);
- batch_sphere_lat_lon_vert(lat, lon);
+ uint i_poly = 0;
+ uint i_vert = 0;
+ while (i_poly != polys_len) {
+ for (uint j = 0; j < 2; j++) {
+ verts[i_vert][j] = min_uchar[j] + ((float)polys[i_poly][j] * range_uchar[j]);
+ }
+ i_vert++;
+ i_poly++;
+ if (polys[i_poly - 1][0] == polys[i_poly][0] &&
+ polys[i_poly - 1][1] == polys[i_poly][1])
+ {
+ const uint verts_step_len = (&verts[i_vert]) - verts_step;
+ BLI_assert(verts_step_len >= 3);
+ const uint tris_len = (verts_step_len - 2);
+ BLI_polyfill_calc(verts_step, verts_step_len, -1, tris_step);
+ /* offset indices */
+ if (verts_step != verts) {
+ uint *t = tris_step[0];
+ const uint offset = (verts_step - verts);
+ uint tot = tris_len * 3;
+ while (tot--) {
+ *t += offset;
+ t++;
+ }
+ BLI_assert(t == tris_step[tris_len]);
}
+ verts_step += verts_step_len;
+ tris_step += tris_len;
+ i_poly++;
+ /* ignore the duplicate point */
}
}
- return GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ /* We have vertices and tris, make a batch from this. */
+ static Gwn_VertFormat format = {0};
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ const uint verts_len = (verts_step - verts);
+ const uint tris_len = (tris_step - tris);
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, verts_len);
+
+ Gwn_VertBufRaw pos_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ for (uint i = 0; i < verts_len; i++) {
+ copy_v2_v2(GWN_vertbuf_raw_step(&pos_step), verts[i]);
+ }
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tris_len, verts_len);
+ for (uint i = 0; i < tris_len; i++) {
+ GWN_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i]));
+ }
+ Gwn_IndexBuf *indexbuf = GWN_indexbuf_build(&elb);
+
+ MEM_freeN(tris);
+ MEM_freeN(verts);
+
+ return GWN_batch_create_ex(
+ GWN_PRIM_TRIS, vbo,
+ indexbuf,
+ GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
}
-static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res)
+Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const rctf *rect)
{
- const float lon_inc = 2 * M_PI / lon_res;
- const float lat_inc = M_PI / lat_res;
- float lon, lat;
+ const uchar (*polys)[2] = (const void *)polys_flat;
+ const uint polys_len = polys_flat_len / 2;
+ BLI_assert(polys_flat_len == polys_len * 2);
- if (format.attrib_ct == 0) {
- pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ /* Over alloc */
+ /* Lines are pairs of (x, y) byte locations packed into an int32_t. */
+ int32_t *lines = MEM_mallocN(sizeof(*lines) * polys_len, __func__);
+ int32_t *lines_step = lines;
+
+ const float range_uchar[2] = {
+ (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f,
+ (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f,
+ };
+ const float min_uchar[2] = {
+ (rect ? rect->xmin : -1.0f),
+ (rect ? rect->ymin : -1.0f),
+ };
+
+ uint i_poly_prev = 0;
+ uint i_poly = 0;
+ while (i_poly != polys_len) {
+ i_poly++;
+ if (polys[i_poly - 1][0] == polys[i_poly][0] &&
+ polys[i_poly - 1][1] == polys[i_poly][1])
+ {
+ const uchar (*polys_step)[2] = polys + i_poly_prev;
+ const uint polys_step_len = i_poly - i_poly_prev;
+ BLI_assert(polys_step_len >= 2);
+ for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) {
+ union {
+ uint8_t as_u8[4];
+ uint16_t as_u16[2];
+ uint32_t as_u32;
+ } data;
+ data.as_u16[0] = *((const uint16_t *)polys_step[i_prev]);
+ data.as_u16[1] = *((const uint16_t *)polys_step[i]);
+ if (data.as_u16[0] > data.as_u16[1]) {
+ SWAP(uint16_t, data.as_u16[0], data.as_u16[1]);
+ }
+ *lines_step = data.as_u32;
+ lines_step++;
+ }
+ i_poly++;
+ i_poly_prev = i_poly;
+ /* ignore the duplicate point */
+ }
}
- vbo = GWN_vertbuf_create_with_format(&format);
- GWN_vertbuf_data_alloc(vbo, (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2));
- vert = 0;
+ uint lines_len = lines_step - lines;
- lon = 0.0f;
- for (int i = 0; i < lon_res; i++, lon += lon_inc) {
- lat = 0.0f;
- for (int j = 0; j < lat_res; j++, lat += lat_inc) {
- batch_sphere_lat_lon_vert(lat + lat_inc, lon);
- batch_sphere_lat_lon_vert(lat, lon);
+ /* Hide Lines (we could make optional) */
+ {
+ qsort(lines, lines_len, sizeof(int32_t), BLI_sortutil_cmp_int);
+ lines_step = lines;
- if (j != lat_res - 1) { /* Pole */
- batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc);
- batch_sphere_lat_lon_vert(lat + lat_inc, lon);
+ if (lines[0] != lines[1]) {
+ *lines_step++ = lines[0];
+ }
+ for (uint i_prev = 0, i = 1; i < lines_len; i_prev = i++) {
+ if (lines[i] != lines[i_prev]) {
+ *lines_step++ = lines[i];
}
}
+ lines_len = lines_step - lines;
}
- return GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
-}
+ /* We have vertices and tris, make a batch from this. */
+ static Gwn_VertFormat format = {0};
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
-Gwn_Batch *GPU_batch_preset_sphere(int lod)
-{
- BLI_assert(lod >= 0 && lod <= 2);
-
- if (lod == 0)
- return sphere_low;
- else if (lod == 1)
- return sphere_med;
- else
- return sphere_high;
-}
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ const uint vbo_len_capacity = lines_len * 2;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
-Gwn_Batch *GPU_batch_preset_sphere_wire(int lod)
-{
- BLI_assert(lod >= 0 && lod <= 1);
+ Gwn_VertBufRaw pos_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
- if (lod == 0)
- return sphere_wire_low;
- else
- return sphere_wire_med;
+ for (uint i = 0; i < lines_len; i++) {
+ union {
+ uint8_t as_u8_pair[2][2];
+ uint32_t as_u32;
+ } data;
+ data.as_u32 = lines[i];
+ for (uint k = 0; k < 2; k++) {
+ float *pos_v2 = GWN_vertbuf_raw_step(&pos_step);
+ for (uint j = 0; j < 2; j++) {
+ pos_v2[j] = min_uchar[j] + ((float)data.as_u8_pair[k][j] * range_uchar[j]);
+ }
+ }
+ }
+ BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
+ MEM_freeN(lines);
+ return GWN_batch_create_ex(
+ GWN_PRIM_LINES, vbo,
+ NULL,
+ GWN_BATCH_OWNS_VBO);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Init/Exit
+ * \{ */
+
void gpu_batch_init(void)
{
- /* Hard coded resolution */
- sphere_low = batch_sphere(8, 16);
- sphere_med = batch_sphere(16, 10);
- sphere_high = batch_sphere(32, 24);
-
- sphere_wire_low = batch_sphere_wire(6, 8);
- sphere_wire_med = batch_sphere_wire(8, 16);
+ gpu_batch_presets_init();
}
void gpu_batch_exit(void)
{
- GWN_batch_discard(sphere_low);
- GWN_batch_discard(sphere_med);
- GWN_batch_discard(sphere_high);
- GWN_batch_discard(sphere_wire_low);
- GWN_batch_discard(sphere_wire_med);
+ gpu_batch_presets_exit();
}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
new file mode 100644
index 00000000000..9db04832a51
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -0,0 +1,200 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_batch_presets.c
+ * \ingroup gpu
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "GPU_batch.h"
+#include "gpu_shader_private.h"
+
+/* Struct to store 3D Batches and their format */
+static struct {
+ struct {
+ Gwn_Batch *sphere_high;
+ Gwn_Batch *sphere_med;
+ Gwn_Batch *sphere_low;
+ Gwn_Batch *sphere_wire_low;
+ Gwn_Batch *sphere_wire_med;
+ } batch;
+
+ Gwn_VertFormat format;
+
+ struct {
+ uint pos, nor;
+ } attr_id;
+} g_presets_3d = {0};
+
+/* We may want 2D presets later. */
+
+/* -------------------------------------------------------------------- */
+/** \name 3D Primitives
+ * \{ */
+
+static void batch_sphere_lat_lon_vert(
+ Gwn_VertBufRaw *pos_step, Gwn_VertBufRaw *nor_step,
+ float lat, float lon)
+{
+ float pos[3];
+ pos[0] = sinf(lat) * cosf(lon);
+ pos[1] = cosf(lat);
+ pos[2] = sinf(lat) * sinf(lon);
+ copy_v3_v3(GWN_vertbuf_raw_step(pos_step), pos);
+ copy_v3_v3(GWN_vertbuf_raw_step(nor_step), pos);
+}
+
+/* Replacement for gluSphere */
+static Gwn_Batch *batch_sphere(int lat_res, int lon_res)
+{
+ const float lon_inc = 2 * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ float lon, lat;
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format);
+ const uint vbo_len = (lat_res - 1) * lon_res * 6;
+ GWN_vertbuf_data_alloc(vbo, vbo_len);
+
+ Gwn_VertBufRaw pos_step, nor_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step);
+ GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step);
+
+ lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ lat = 0.0f;
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ if (j != lat_res - 1) { /* Pole */
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon);
+ }
+
+ if (j != 0) { /* Pole */
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon);
+ }
+ }
+ }
+
+ BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step));
+ BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step));
+
+ return GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
+}
+
+static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res)
+{
+ const float lon_inc = 2 * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ float lon, lat;
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format);
+ const uint vbo_len = (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2);
+ GWN_vertbuf_data_alloc(vbo, vbo_len);
+
+ Gwn_VertBufRaw pos_step, nor_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step);
+ GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step);
+
+ lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ lat = 0.0f;
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon);
+
+ if (j != lat_res - 1) { /* Pole */
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
+ }
+ }
+ }
+
+ BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step));
+ BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step));
+
+ return GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
+}
+
+Gwn_Batch *GPU_batch_preset_sphere(int lod)
+{
+ BLI_assert(lod >= 0 && lod <= 2);
+
+ if (lod == 0) {
+ return g_presets_3d.batch.sphere_low;
+ }
+ else if (lod == 1) {
+ return g_presets_3d.batch.sphere_med;
+ }
+ else {
+ return g_presets_3d.batch.sphere_high;
+ }
+}
+
+Gwn_Batch *GPU_batch_preset_sphere_wire(int lod)
+{
+ BLI_assert(lod >= 0 && lod <= 1);
+
+ if (lod == 0) {
+ return g_presets_3d.batch.sphere_wire_low;
+ }
+ else {
+ return g_presets_3d.batch.sphere_wire_med;
+ }
+}
+
+/** \} */
+
+
+void gpu_batch_presets_init(void)
+{
+ if (g_presets_3d.format.attrib_ct == 0) {
+ Gwn_VertFormat *format = &g_presets_3d.format;
+ g_presets_3d.attr_id.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ g_presets_3d.attr_id.nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Hard coded resolution */
+ g_presets_3d.batch.sphere_low = batch_sphere(8, 16);
+ g_presets_3d.batch.sphere_med = batch_sphere(16, 10);
+ g_presets_3d.batch.sphere_high = batch_sphere(32, 24);
+
+ g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8);
+ g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16);
+}
+
+void gpu_batch_presets_exit(void)
+{
+ GWN_batch_discard(g_presets_3d.batch.sphere_low);
+ GWN_batch_discard(g_presets_3d.batch.sphere_med);
+ GWN_batch_discard(g_presets_3d.batch.sphere_high);
+ GWN_batch_discard(g_presets_3d.batch.sphere_wire_low);
+ GWN_batch_discard(g_presets_3d.batch.sphere_wire_med);
+}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 3a6b0a2a72d..d0efee79ab0 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -980,6 +980,8 @@ struct GPU_PBVH_Buffers {
bool smooth;
bool show_diffuse_color;
+ bool show_mask;
+
bool use_matcaps;
float diffuse_color[4];
};
@@ -1053,10 +1055,15 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key,
void GPU_pbvh_mesh_buffers_update(
GPU_PBVH_Buffers *buffers, const MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
- const int (*face_vert_indices)[3], bool show_diffuse_color)
+ const int (*face_vert_indices)[3],
+ const int update_flags)
{
+ const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0;
+ const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
+
buffers->vmask = vmask;
buffers->show_diffuse_color = show_diffuse_color;
+ buffers->show_mask = show_mask;
buffers->use_matcaps = GPU_material_use_matcaps_get();
{
@@ -1103,7 +1110,7 @@ void GPU_pbvh_mesh_buffers_update(
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
for (uint j = 0; j < 3; j++) {
int vidx = face_vert_indices[i][j];
- if (vmask) {
+ if (vmask && show_mask) {
int v_index = buffers->mloop[lt->tri[j]].v;
uchar color_ub[3];
gpu_color_from_mask_copy(vmask[v_index], diffuse_color, color_ub);
@@ -1142,7 +1149,7 @@ void GPU_pbvh_mesh_buffers_update(
}
uchar color_ub[3];
- if (vmask) {
+ if (vmask && show_mask) {
float fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
gpu_color_from_mask_copy(fmask, diffuse_color, color_ub);
}
@@ -1193,6 +1200,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
#endif
buffers->show_diffuse_color = false;
+ buffers->show_mask = true;
buffers->use_matcaps = false;
/* Count the number of visible triangles */
@@ -1257,11 +1265,15 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
void GPU_pbvh_grid_buffers_update(
GPU_PBVH_Buffers *buffers, CCGElem **grids,
const DMFlagMat *grid_flag_mats, int *grid_indices,
- int totgrid, const CCGKey *key, bool show_diffuse_color)
+ int totgrid, const CCGKey *key,
+ const int update_flags)
{
+ const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0;
+ const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
int i, j, k, x, y;
buffers->show_diffuse_color = show_diffuse_color;
+ buffers->show_mask = show_mask;
buffers->use_matcaps = GPU_material_use_matcaps_get();
buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
@@ -1308,8 +1320,13 @@ void GPU_pbvh_grid_buffers_update(
if (has_mask) {
uchar color_ub[3];
- gpu_color_from_mask_copy(*CCG_elem_mask(key, elem),
- diffuse_color, color_ub);
+ if (show_mask) {
+ gpu_color_from_mask_copy(*CCG_elem_mask(key, elem),
+ diffuse_color, color_ub);
+ }
+ else {
+ F3TOCHAR3(diffuse_color, color_ub);
+ }
GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub);
}
}
@@ -1341,13 +1358,18 @@ void GPU_pbvh_grid_buffers_update(
if (has_mask) {
uchar color_ub[3];
- gpu_color_from_mask_quad_copy(key,
- elems[0],
- elems[1],
- elems[2],
- elems[3],
- diffuse_color,
- color_ub);
+ if (show_mask) {
+ gpu_color_from_mask_quad_copy(key,
+ elems[0],
+ elems[1],
+ elems[2],
+ elems[3],
+ diffuse_color,
+ color_ub);
+ }
+ else {
+ F3TOCHAR3(diffuse_color, color_ub);
+ }
GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub);
}
}
@@ -1483,6 +1505,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
buffers->totgrid = totgrid;
buffers->show_diffuse_color = false;
+ buffers->show_mask = true;
buffers->use_matcaps = false;
/* Count the number of quads */
@@ -1544,7 +1567,8 @@ static void gpu_bmesh_vert_to_buffer_copy__gwn(
const float fno[3],
const float *fmask,
const int cd_vert_mask_offset,
- const float diffuse_color[4])
+ const float diffuse_color[4],
+ const bool show_mask)
{
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
@@ -1559,9 +1583,17 @@ static void gpu_bmesh_vert_to_buffer_copy__gwn(
{
uchar color_ub[3];
+ float effective_mask;
+ if (show_mask) {
+ effective_mask = fmask ? *fmask
+ : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ }
+ else {
+ effective_mask = 0.0f;
+ }
+
gpu_color_from_mask_copy(
- fmask ? *fmask :
- BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset),
+ effective_mask,
diffuse_color,
color_ub);
GWN_vertbuf_attr_set(vert_buf, vbo_id->col, *v_index, color_ub);
@@ -1620,8 +1652,10 @@ void GPU_pbvh_bmesh_buffers_update(
GSet *bm_faces,
GSet *bm_unique_verts,
GSet *bm_other_verts,
- bool show_diffuse_color)
+ const int update_flags)
{
+ const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0;
+ const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
int tottri, totvert, maxvert = 0;
float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
@@ -1629,6 +1663,7 @@ void GPU_pbvh_bmesh_buffers_update(
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
buffers->show_diffuse_color = show_diffuse_color;
+ buffers->show_mask = show_mask;
buffers->use_matcaps = GPU_material_use_matcaps_get();
/* Count visible triangles */
@@ -1684,14 +1719,16 @@ void GPU_pbvh_bmesh_buffers_update(
gpu_bmesh_vert_to_buffer_copy__gwn(
BLI_gsetIterator_getKey(&gs_iter),
buffers->vert_buf, &vbo_id, &v_index, NULL, NULL,
- cd_vert_mask_offset, diffuse_color);
+ cd_vert_mask_offset, diffuse_color,
+ show_mask);
}
GSET_ITER (gs_iter, bm_other_verts) {
gpu_bmesh_vert_to_buffer_copy__gwn(
BLI_gsetIterator_getKey(&gs_iter),
buffers->vert_buf, &vbo_id, &v_index, NULL, NULL,
- cd_vert_mask_offset, diffuse_color);
+ cd_vert_mask_offset, diffuse_color,
+ show_mask);
}
maxvert = v_index;
@@ -1724,7 +1761,8 @@ void GPU_pbvh_bmesh_buffers_update(
gpu_bmesh_vert_to_buffer_copy__gwn(
v[i], buffers->vert_buf, &vbo_id,
&v_index, f->no, &fmask,
- cd_vert_mask_offset, diffuse_color);
+ cd_vert_mask_offset, diffuse_color,
+ show_mask);
}
}
}
@@ -1796,6 +1834,7 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
buffers->use_bmesh = true;
buffers->smooth = smooth_shading;
buffers->show_diffuse_color = false;
+ buffers->show_mask = true;
buffers->use_matcaps = false;
return buffers;
@@ -1883,6 +1922,11 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
return !equals_v3v3(diffuse_color, buffers->diffuse_color);
}
+bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask)
+{
+ return (buffers->show_mask != show_mask);
+}
+
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
@@ -1892,7 +1936,7 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
}
GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
- GWN_vertbuf_discard(buffers->vert_buf);
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
#ifdef USE_BASE_ELEM
if (buffers->baseelemarray)
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 12ed67cdf4e..3de363cc76e 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -1007,7 +1007,7 @@ bool GPU_fx_do_composite_pass(
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
/* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
- GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, NULL, NULL);
+ GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL);
GPU_texture_unbind(fx->dof_half_downsampled_far);
GPU_framebuffer_texture_detach(fx->dof_far_blur);
@@ -1023,7 +1023,7 @@ bool GPU_fx_do_composite_pass(
/* have to clear the buffer unfortunately */
glClear(GL_COLOR_BUFFER_BIT);
/* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
- GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, NULL, NULL);
+ GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL);
GWN_batch_program_use_end(fx->point_batch);
/* disable bindings */
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 6830e73cb03..09013cd29bd 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -650,7 +650,7 @@ struct GPUOffScreen {
GPUTexture *depth;
};
-GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256])
+GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256])
{
GPUOffScreen *ofs;
@@ -683,7 +683,12 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_
return NULL;
}
- ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out);
+ if (high_bitdepth) {
+ ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, GPU_RGBA16F, NULL, samples, err_out);
+ }
+ else {
+ ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out);
+ }
if (!ofs->color) {
GPU_offscreen_free(ofs);
return NULL;
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index e2883b53047..2e6c1cbf9df 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -48,6 +48,7 @@
#include "BLI_rand.h"
#include "BKE_anim.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -55,7 +56,6 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_scene.h"
-#include "BKE_texture.h"
#include "BKE_group.h"
#include "IMB_imbuf_types.h"
@@ -994,7 +994,7 @@ static void ramp_blend(
GPU_link(mat, names[type], fac, col1, col2, r_col);
}
-static void do_colorband_blend(
+static void BKE_colorband_eval_blend(
GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type,
GPUNodeLink *incol, GPUNodeLink **r_col)
{
@@ -1003,7 +1003,7 @@ static void do_colorband_blend(
int size;
/* do colorband */
- colorband_table_RGBA(coba, &array, &size);
+ BKE_colorband_evaluate_table_rgba(coba, &array, &size);
GPU_link(mat, "valtorgb", fac, GPU_texture(size, array), &col, &tmp);
/* use alpha in fac */
@@ -1026,7 +1026,7 @@ static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
GPU_link(mat, "ramp_rgbtobw", *diff, &fac);
/* colorband + blend */
- do_colorband_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff);
+ BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff);
}
}
}
@@ -1063,7 +1063,7 @@ static void add_to_diffuse(
}
/* colorband + blend */
- do_colorband_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol);
+ BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol);
}
}
else
@@ -1085,7 +1085,7 @@ static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
GPU_link(mat, "ramp_rgbtobw", *spec, &fac);
/* colorband + blend */
- do_colorband_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
+ BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
}
}
@@ -1117,7 +1117,7 @@ static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t
}
/* colorband + blend */
- do_colorband_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
+ BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
}
}
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 252eede8758..d6b641af225 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -115,9 +115,9 @@ static GLenum gpu_texture_get_format(
int components, GPUTextureFormat data_type,
GLenum *format, GLenum *data_format, bool *is_depth, bool *is_stencil, unsigned int *bytesize)
{
- if (data_type == GPU_DEPTH_COMPONENT24 ||
- data_type == GPU_DEPTH_COMPONENT16 ||
- data_type == GPU_DEPTH_COMPONENT32F)
+ if (ELEM(data_type, GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+ GPU_DEPTH_COMPONENT32F))
{
*is_depth = true;
*is_stencil = false;
@@ -133,14 +133,29 @@ static GLenum gpu_texture_get_format(
else {
*is_depth = false;
*is_stencil = false;
- *data_format = GL_FLOAT;
- switch (components) {
- case 1: *format = GL_RED; break;
- case 2: *format = GL_RG; break;
- case 3: *format = GL_RGB; break;
- case 4: *format = GL_RGBA; break;
- default: break;
+ /* Integer formats */
+ if (ELEM(data_type, GPU_RG16I)) {
+ *data_format = GL_INT;
+
+ switch (components) {
+ case 1: *format = GL_RED_INTEGER; break;
+ case 2: *format = GL_RG_INTEGER; break;
+ case 3: *format = GL_RGB_INTEGER; break;
+ case 4: *format = GL_RGBA_INTEGER; break;
+ default: break;
+ }
+ }
+ else {
+ *data_format = GL_FLOAT;
+
+ switch (components) {
+ case 1: *format = GL_RED; break;
+ case 2: *format = GL_RG; break;
+ case 3: *format = GL_RGB; break;
+ case 4: *format = GL_RGBA; break;
+ default: break;
+ }
}
}
@@ -156,6 +171,7 @@ static GLenum gpu_texture_get_format(
*bytesize = 12;
break;
case GPU_RG16F:
+ case GPU_RG16I:
case GPU_DEPTH24_STENCIL8:
case GPU_DEPTH_COMPONENT32F:
case GPU_RGBA8:
@@ -188,6 +204,7 @@ static GLenum gpu_texture_get_format(
case GPU_RG32F: return GL_RG32F;
case GPU_RGB16F: return GL_RGB16F;
case GPU_RG16F: return GL_RG16F;
+ case GPU_RG16I: return GL_RG16I;
case GPU_RGBA8: return GL_RGBA8;
case GPU_R32F: return GL_R32F;
case GPU_R16F: return GL_R16F;
@@ -663,6 +680,12 @@ GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels,
return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out);
}
+GPUTexture *GPU_texture_create_2D_custom_multisample(
+ int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, samples, false, err_out);
+}
+
GPUTexture *GPU_texture_create_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
{
return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, err_out);
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index bd563a36f57..3ef53b3a6c3 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -84,6 +84,7 @@ struct GPUViewport {
DefaultTextureList *txl;
ViewportMemoryPool vmempool; /* Used for rendering data structure. */
+ struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */
ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */
};
@@ -114,6 +115,7 @@ GPUViewport *GPU_viewport_create(void)
GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport");
viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList");
viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList");
+ viewport->idatalist = DRW_instance_data_list_create();
viewport->size[0] = viewport->size[1] = -1;
@@ -210,6 +212,11 @@ ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport)
return &viewport->vmempool;
}
+struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport)
+{
+ return viewport->idatalist;
+}
+
void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport)
{
return viewport->fbl;
@@ -583,22 +590,19 @@ void GPU_viewport_free(GPUViewport *viewport)
if (viewport->vmempool.calls_generate != NULL) {
BLI_mempool_destroy(viewport->vmempool.calls_generate);
}
- if (viewport->vmempool.calls_dynamic != NULL) {
- BLI_mempool_destroy(viewport->vmempool.calls_dynamic);
- }
if (viewport->vmempool.shgroups != NULL) {
BLI_mempool_destroy(viewport->vmempool.shgroups);
}
if (viewport->vmempool.uniforms != NULL) {
BLI_mempool_destroy(viewport->vmempool.uniforms);
}
- if (viewport->vmempool.attribs != NULL) {
- BLI_mempool_destroy(viewport->vmempool.attribs);
- }
if (viewport->vmempool.passes != NULL) {
BLI_mempool_destroy(viewport->vmempool.passes);
}
+ DRW_instance_data_list_free(viewport->idatalist);
+ MEM_freeN(viewport->idatalist);
+
GPU_viewport_debug_depth_free(viewport);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl
index 74c8f6f3103..d0f2a8dcd51 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl
@@ -7,7 +7,6 @@
uniform mat4 ViewMatrix;
-uniform mat4 ObjectModelMatrix;
uniform mat4 ViewProjectionMatrix;
@@ -38,7 +37,7 @@ void main()
bone_mat[1] = normalize(bone_mat[1]);
bone_mat[2] = normalize(bone_mat[2]);
- mat3 nor_mat = transpose(inverse(mat3(ViewMatrix * ObjectModelMatrix) * bone_mat));
+ mat3 nor_mat = transpose(inverse(mat3(ViewMatrix) * bone_mat));
/* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */
const float size = 2.0f;
@@ -116,7 +115,7 @@ void main()
ob_pos.xyz = bone_mat * ob_pos.xyz;
ob_pos.w = 1.0f;
- gl_Position = ViewProjectionMatrix * ObjectModelMatrix * (ob_pos + ob_bone_origin);
+ gl_Position = ViewProjectionMatrix * (ob_pos + ob_bone_origin);
normal = normalize(nor_mat * nor);
finalColor = color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl
index a36eb1dec77..1bdad924bd2 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl
@@ -7,11 +7,8 @@
* Note that if one of head/tail radius is negative, it assumes it only works on the other end of the bone
* (used to draw head/tail spheres). */
-
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
-uniform mat4 ObjectModelMatrix;
-
/* ---- Instanciated Attribs ---- */
in vec4 pos; /* z encodes head (== 0.0f), tail (== 1.0f) or in-between; w encodes inner (0.0f) or outer border. */
@@ -36,7 +33,7 @@ void main()
vec4 tail = bone_mat * vec4(0.0f, 1.0f, 0.0f, 1.0f);
/* We generate our XY axes in object space, Y axis being aligned with bone in view space. */
- mat4 obview_mat = ViewMatrix * ObjectModelMatrix;
+ mat4 obview_mat = ViewMatrix;
mat4 iobview_mat = inverse(obview_mat);
vec4 view_bone_vec = obview_mat * normalize(tail - head);
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
index 195d4849d99..9876717b297 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
@@ -1,7 +1,6 @@
uniform mat4 ViewMatrix;
uniform mat4 ViewProjectionMatrix;
-uniform mat4 ObjectModelMatrix;
/* ---- Instanciated Attribs ---- */
in vec3 pos;
@@ -16,11 +15,10 @@ flat out vec4 finalColor;
void main()
{
- mat4 FinalModelMatrix = ObjectModelMatrix * InstanceModelMatrix;
- mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * FinalModelMatrix;
+ mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * InstanceModelMatrix;
/* This is slow and run per vertex, but it's still faster than
* doing it per instance on CPU and sending it on via instance attrib */
- mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * FinalModelMatrix)));
+ mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix)));
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
normal = NormalMatrix * nor;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 9d22fbba65e..780f4f59fb9 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1004,8 +1004,8 @@ void texco_orco(vec3 attorco, out vec3 orco)
void texco_uv(vec2 attuv, out vec3 uv)
{
- /* disabled for now, works together with leaving out mtex_2d_mapping
- uv = vec3(attuv * 2.0 - vec2(1.0), 0.0); */
+ /* disabled for now, works together with leaving out mtex_2d_mapping */
+ // uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0); */
uv = vec3(attuv, 0.0);
}
@@ -4135,9 +4135,14 @@ void node_bevel(float radius, vec3 N, out vec3 result)
result = N;
}
+void node_displacement(float height, float dist, vec3 N, out vec3 result)
+{
+ result = height * dist * N;
+}
+
/* output */
-void node_output_material(Closure surface, Closure volume, float displacement, out Closure result)
+void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
{
#ifdef VOLUMETRICS
result = volume;
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index f1f36351e79..a7f793b5b11 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -583,6 +583,12 @@ bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *f
void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb);
/* exported for image tools in blender, to quickly allocate 32 bits rect */
+void *imb_alloc_pixels(unsigned int x,
+ unsigned int y,
+ unsigned int channels,
+ size_t typesize,
+ const char *name);
+
bool imb_addrectImBuf(struct ImBuf *ibuf);
void imb_freerectImBuf(struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index b10ae4f6fe9..c4c4f4405a5 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -99,8 +99,8 @@ struct anim {
int curtype;
int curposition; /* index 0 = 1e, 1 = 2e, enz. */
int duration;
- short frs_sec;
- float frs_sec_base;
+ int frs_sec;
+ double frs_sec_base;
int x, y;
/* for number */
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 6e9bfa1fc4e..7fc4a65d8d7 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -265,15 +265,11 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf)
bool addzbufImBuf(ImBuf *ibuf)
{
- size_t size;
-
if (ibuf == NULL) return false;
IMB_freezbufImBuf(ibuf);
- size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(unsigned int);
-
- if ((ibuf->zbuf = MEM_mapallocN(size, __func__))) {
+ if ((ibuf->zbuf = imb_alloc_pixels(ibuf->x, ibuf->y, 1, sizeof(unsigned int), __func__))) {
ibuf->mall |= IB_zbuf;
ibuf->flags |= IB_zbuf;
return true;
@@ -284,15 +280,11 @@ bool addzbufImBuf(ImBuf *ibuf)
bool addzbuffloatImBuf(ImBuf *ibuf)
{
- size_t size;
-
if (ibuf == NULL) return false;
IMB_freezbuffloatImBuf(ibuf);
- size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(float);
-
- if ((ibuf->zbuf_float = MEM_mapallocN(size, __func__))) {
+ if ((ibuf->zbuf_float = imb_alloc_pixels(ibuf->x, ibuf->y, 1, sizeof(float), __func__))) {
ibuf->mall |= IB_zbuffloat;
ibuf->flags |= IB_zbuffloat;
return true;
@@ -361,19 +353,31 @@ bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf)
return true;
}
+void *imb_alloc_pixels(unsigned int x,
+ unsigned int y,
+ unsigned int channels,
+ size_t typesize,
+ const char *name)
+{
+ /* Protect against buffer overflow vulnerabilities from files specifying
+ * a width and height that overflow and alloc too little memory. */
+ if (!((uint64_t)x * (uint64_t)y < (SIZE_MAX / (channels * typesize)))) {
+ return NULL;
+ }
+
+ size_t size = (size_t)x * (size_t)y * (size_t)channels * typesize;
+ return MEM_mapallocN(size, name);
+}
+
bool imb_addrectfloatImBuf(ImBuf *ibuf)
{
- size_t size;
-
if (ibuf == NULL) return false;
if (ibuf->rect_float)
imb_freerectfloatImBuf(ibuf); /* frees mipmap too, hrm */
- size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(float[4]);
-
ibuf->channels = 4;
- if ((ibuf->rect_float = MEM_mapallocN(size, __func__))) {
+ if ((ibuf->rect_float = imb_alloc_pixels(ibuf->x, ibuf->y, 4, sizeof(float), __func__))) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
return true;
@@ -385,8 +389,6 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf)
/* question; why also add zbuf? */
bool imb_addrectImBuf(ImBuf *ibuf)
{
- size_t size;
-
if (ibuf == NULL) return false;
/* don't call imb_freerectImBuf, it frees mipmaps, this call is used only too give float buffers display */
@@ -394,9 +396,7 @@ bool imb_addrectImBuf(ImBuf *ibuf)
MEM_freeN(ibuf->rect);
ibuf->rect = NULL;
- size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(unsigned int);
-
- if ((ibuf->rect = MEM_mapallocN(size, __func__))) {
+ if ((ibuf->rect = imb_alloc_pixels(ibuf->x, ibuf->y, 4, sizeof(unsigned char), __func__))) {
ibuf->mall |= IB_rect;
ibuf->flags |= IB_rect;
if (ibuf->planes > 32) {
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 25b0c0d7b1a..5472cae3ef2 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -55,6 +55,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
+#include <limits.h>
#ifndef _WIN32
#include <dirent.h>
#else
@@ -1365,16 +1366,32 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
bool IMB_anim_get_fps(struct anim *anim,
short *frs_sec, float *frs_sec_base, bool no_av_base)
{
+ double frs_sec_base_double;
if (anim->frs_sec) {
- *frs_sec = anim->frs_sec;
- *frs_sec_base = anim->frs_sec_base;
+ if (anim->frs_sec > SHRT_MAX) {
+ /* We cannot store original rational in our short/float format,
+ * we need to approximate it as best as we can... */
+ *frs_sec = SHRT_MAX;
+ frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec;
+ }
+ else {
+ *frs_sec = anim->frs_sec;
+ frs_sec_base_double = anim->frs_sec_base;
+ }
#ifdef WITH_FFMPEG
if (no_av_base) {
- *frs_sec_base /= AV_TIME_BASE;
+ *frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE);
+ }
+ else {
+ *frs_sec_base = (float)frs_sec_base_double;
}
#else
UNUSED_VARS(no_av_base);
+ *frs_sec_base = (float)frs_sec_base_double;
#endif
+ BLI_assert(*frs_sec > 0);
+ BLI_assert(*frs_sec_base > 0.0f);
+
return true;
}
return false;
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index c5694148127..e63699ea5ba 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -124,7 +124,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c
{
struct ImBuf *ibuf = NULL;
BMPINFOHEADER bmi;
- int x, y, depth, ibuf_depth, skip, i, j;
+ int x, y, depth, ibuf_depth, skip;
const unsigned char *bmp;
unsigned char *rect;
unsigned short col;
@@ -179,13 +179,17 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c
}
else {
ibuf = IMB_allocImBuf(x, y, ibuf_depth, IB_rect);
+ if (!ibuf) {
+ return NULL;
+ }
+
rect = (unsigned char *) ibuf->rect;
if (depth <= 8) {
const int rowsize = (depth * x + 31) / 32 * 4;
const char (*palette)[4] = (void *)(mem + skip);
const int startmask = ((1 << depth) - 1) << 8;
- for (i = y; i > 0; i--) {
+ for (size_t i = y; i > 0; i--) {
int index;
int bitoffs = 8;
int bitmask = startmask;
@@ -194,7 +198,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c
if (top_to_bottom) {
rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
}
- for (j = x; j > 0; j--) {
+ for (size_t j = x; j > 0; j--) {
bitoffs -= depth;
bitmask >>= depth;
index = (bmp[0] & bitmask) >> bitoffs;
@@ -219,11 +223,11 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c
}
}
else if (depth == 16) {
- for (i = y; i > 0; i--) {
+ for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
}
- for (j = x; j > 0; j--) {
+ for (size_t j = x; j > 0; j--) {
col = bmp[0] + (bmp[1] << 8);
rect[0] = ((col >> 10) & 0x1f) << 3;
rect[1] = ((col >> 5) & 0x1f) << 3;
@@ -236,11 +240,11 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c
}
else if (depth == 24) {
const int x_pad = x % 4;
- for (i = y; i > 0; i--) {
+ for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
}
- for (j = x; j > 0; j--) {
+ for (size_t j = x; j > 0; j--) {
rect[0] = bmp[2];
rect[1] = bmp[1];
rect[2] = bmp[0];
@@ -253,11 +257,11 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c
}
}
else if (depth == 32) {
- for (i = y; i > 0; i--) {
+ for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
}
- for (j = x; j > 0; j--) {
+ for (size_t j = x; j > 0; j--) {
rect[0] = bmp[2];
rect[1] = bmp[1];
rect[2] = bmp[0];
@@ -299,7 +303,7 @@ static int putShortLSB(unsigned short us, FILE *ofile)
int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags)
{
BMPINFOHEADER infoheader;
- int bytesize, extrabytes, x, y, t, ptr;
+ size_t bytesize, extrabytes, ptr;
uchar *data;
FILE *ofile;
@@ -331,15 +335,15 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags)
putIntLSB(0, ofile);
/* Need to write out padded image data in bgr format */
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
+ for (size_t y = 0; y < ibuf->y; y++) {
+ for (size_t x = 0; x < ibuf->x; x++) {
ptr = (x + y * ibuf->x) * 4;
if (putc(data[ptr + 2], ofile) == EOF) return 0;
if (putc(data[ptr + 1], ofile) == EOF) return 0;
if (putc(data[ptr], ofile) == EOF) return 0;
}
/* add padding here */
- for (t = 0; t < extrabytes; t++) {
+ for (size_t t = 0; t < extrabytes; t++) {
if (putc(0, ofile) == EOF) return 0;
}
}
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
index 3e2206dc013..1d2ebf88a32 100644
--- a/source/blender/imbuf/intern/cineon/cineon_dpx.c
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -59,7 +59,7 @@ static struct ImBuf *imb_load_dpx_cineon(
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
- logImageSetVerbose((G.f & G_DEBUG) ? 1 : 0);
+ logImageSetVerbose((G.debug & G_DEBUG) ? 1 : 0);
image = logImageOpenFromMemory(mem, size);
@@ -107,7 +107,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
return 0;
}
- logImageSetVerbose((G.f & G_DEBUG) ? 1 : 0);
+ logImageSetVerbose((G.debug & G_DEBUG) ? 1 : 0);
depth = (ibuf->planes + 7) >> 3;
if (depth > 4 || depth < 3) {
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index fbce508af17..50d0e843890 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -318,6 +318,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
printf("Gamma: %f\n", cineon->gamma);
printf("Reference black: %f\n", cineon->referenceBlack);
printf("Reference white: %f\n", cineon->referenceWhite);
+ printf("Orientation: %d\n", header.imageHeader.orientation);
printf("----------------------------\n");
}
return cineon;
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 429a19936a5..d29518fc5bc 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -193,7 +193,8 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
dpx->srcFormat = format_DPX;
dpx->numElements = swap_ushort(header.imageHeader.elements_per_image, dpx->isMSB);
- if (dpx->numElements == 0) {
+ size_t max_elements = sizeof(header.imageHeader.element) / sizeof(header.imageHeader.element[0]);
+ if (dpx->numElements == 0 || dpx->numElements >= max_elements) {
if (verbose) printf("DPX: Wrong number of elements: %d\n", dpx->numElements);
logImageClose(dpx);
return NULL;
@@ -377,6 +378,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
printf("Gamma: %f\n", dpx->gamma);
printf("Reference black: %f\n", dpx->referenceBlack);
printf("Reference white: %f\n", dpx->referenceWhite);
+ printf("Orientation: %d\n", header.imageHeader.orientation);
printf("----------------------------\n");
}
return dpx;
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 600642f5e44..bb72f675cb8 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -38,6 +38,8 @@
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
+#include "IMB_imbuf.h"
+
#include "MEM_guardedalloc.h"
/*
@@ -162,7 +164,7 @@ void logImageGetSize(LogImageFile *logImage, int *width, int *height, int *depth
* Helper
*/
-unsigned int getRowLength(int width, LogImageElement logElement)
+size_t getRowLength(size_t width, LogImageElement logElement)
{
/* return the row length in bytes according to width and packing method */
switch (logElement.bitsPerSample) {
@@ -201,7 +203,7 @@ int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
float *elementData;
int returnValue;
- elementData = (float *)MEM_mallocN(logImage->width * logImage->height * logImage->depth * sizeof(float), __func__);
+ elementData = (float *)imb_alloc_pixels(logImage->width, logImage->height, logImage->depth, sizeof(float), __func__);
if (elementData == NULL)
return 1;
@@ -238,9 +240,8 @@ int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
static int logImageSetData8(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned char *row;
- int x, y;
row = (unsigned char *)MEM_mallocN(rowLength, __func__);
if (row == NULL) {
@@ -249,8 +250,8 @@ static int logImageSetData8(LogImageFile *logImage, LogImageElement logElement,
}
memset(row, 0, rowLength);
- for (y = 0; y < logImage->height; y++) {
- for (x = 0; x < logImage->width * logImage->depth; x++)
+ for (size_t y = 0; y < logImage->height; y++) {
+ for (size_t x = 0; x < logImage->width * logImage->depth; x++)
row[x] = (unsigned char)float_uint(data[y * logImage->width * logImage->depth + x], 255);
if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
@@ -265,10 +266,9 @@ static int logImageSetData8(LogImageFile *logImage, LogImageElement logElement,
static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned int pixel, index;
unsigned int *row;
- int x, y, offset;
row = (unsigned int *)MEM_mallocN(rowLength, __func__);
if (row == NULL) {
@@ -276,12 +276,12 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement,
return 1;
}
- for (y = 0; y < logImage->height; y++) {
- offset = 22;
+ for (size_t y = 0; y < logImage->height; y++) {
+ int offset = 22;
index = 0;
pixel = 0;
- for (x = 0; x < logImage->width * logImage->depth; x++) {
+ for (size_t x = 0; x < logImage->width * logImage->depth; x++) {
pixel |= (unsigned int)float_uint(data[y * logImage->width * logImage->depth + x], 1023) << offset;
offset -= 10;
if (offset < 0) {
@@ -308,9 +308,8 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement,
static int logImageSetData12(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned short *row;
- int x, y;
row = (unsigned short *)MEM_mallocN(rowLength, __func__);
if (row == NULL) {
@@ -318,8 +317,8 @@ static int logImageSetData12(LogImageFile *logImage, LogImageElement logElement,
return 1;
}
- for (y = 0; y < logImage->height; y++) {
- for (x = 0; x < logImage->width * logImage->depth; x++)
+ for (size_t y = 0; y < logImage->height; y++) {
+ for (size_t x = 0; x < logImage->width * logImage->depth; x++)
row[x] = swap_ushort(((unsigned short)float_uint(data[y * logImage->width * logImage->depth + x], 4095)) << 4, logImage->isMSB);
if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
@@ -334,9 +333,8 @@ static int logImageSetData12(LogImageFile *logImage, LogImageElement logElement,
static int logImageSetData16(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned short *row;
- int x, y;
row = (unsigned short *)MEM_mallocN(rowLength, __func__);
if (row == NULL) {
@@ -344,8 +342,8 @@ static int logImageSetData16(LogImageFile *logImage, LogImageElement logElement,
return 1;
}
- for (y = 0; y < logImage->height; y++) {
- for (x = 0; x < logImage->width * logImage->depth; x++)
+ for (size_t y = 0; y < logImage->height; y++) {
+ for (size_t x = 0; x < logImage->width * logImage->depth; x++)
row[x] = swap_ushort((unsigned short)float_uint(data[y * logImage->width * logImage->depth + x], 65535), logImage->isMSB);
if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
@@ -382,7 +380,7 @@ int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
/* descriptor_Depth and descriptor_Composite are not supported */
if (logImage->element[i].descriptor != descriptor_Depth && logImage->element[i].descriptor != descriptor_Composite) {
/* Allocate memory */
- elementData[i] = (float *)MEM_mallocN(logImage->width * logImage->height * logImage->element[i].depth * sizeof(float), __func__);
+ elementData[i] = imb_alloc_pixels(logImage->width, logImage->height, logImage->element[i].depth, sizeof(float), __func__);
if (elementData[i] == NULL) {
if (verbose) printf("DPX/Cineon: Cannot allocate memory for elementData[%d]\n.", i);
for (j = 0; j < i; j++)
@@ -530,7 +528,7 @@ int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB
}
}
- mergedData = (float *)MEM_mallocN(logImage->width * logImage->height * mergedElement.depth * sizeof(float), __func__);
+ mergedData = (float *)imb_alloc_pixels(logImage->width, logImage->height, mergedElement.depth, sizeof(float), __func__);
if (mergedData == NULL) {
if (verbose) printf("DPX/Cineon: Cannot allocate mergedData.\n");
for (i = 0; i < logImage->numElements; i++)
@@ -590,7 +588,6 @@ static int logImageElementGetData(LogImageFile *logImage, LogImageElement logEle
static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logElement, float *data)
{
unsigned int pixel;
- int x, y, offset;
/* seek at the right place */
if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) {
@@ -599,14 +596,14 @@ static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logEl
}
/* read 1 bit data padded to 32 bits */
- for (y = 0; y < logImage->height; y++) {
- for (x = 0; x < logImage->width * logElement.depth; x += 32) {
+ for (size_t y = 0; y < logImage->height; y++) {
+ for (size_t x = 0; x < logImage->width * logElement.depth; x += 32) {
if (logimage_read_uint(&pixel, logImage) != 0) {
if (verbose) printf("DPX/Cineon: EOF reached\n");
return 1;
}
pixel = swap_uint(pixel, logImage->isMSB);
- for (offset = 0; offset < 32 && x + offset < logImage->width; offset++)
+ for (int offset = 0; offset < 32 && x + offset < logImage->width; offset++)
data[y * logImage->width * logElement.depth + x + offset] = (float)((pixel >> offset) & 0x01);
}
}
@@ -615,19 +612,18 @@ static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logEl
static int logImageElementGetData8(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned char pixel;
- int x, y;
/* extract required pixels */
- for (y = 0; y < logImage->height; y++) {
+ for (size_t y = 0; y < logImage->height; y++) {
/* 8 bits are 32-bits padded so we need to seek at each row */
if (logimage_fseek(logImage, logElement.dataOffset + y * rowLength, SEEK_SET) != 0) {
- if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset + y * (int)rowLength);
+ if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", (int)(logElement.dataOffset + y * rowLength));
return 1;
}
- for (x = 0; x < logImage->width * logElement.depth; x++) {
+ for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
if (logimage_read_uchar(&pixel, logImage) != 0) {
if (verbose) printf("DPX/Cineon: EOF reached\n");
return 1;
@@ -641,7 +637,6 @@ static int logImageElementGetData8(LogImageFile *logImage, LogImageElement logEl
static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logElement, float *data)
{
unsigned int pixel;
- int x, y, offset;
/* seek to data */
if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) {
@@ -650,9 +645,9 @@ static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logE
}
if (logImage->depth == 1 && logImage->srcFormat == format_DPX) {
- for (y = 0; y < logImage->height; y++) {
- offset = 32;
- for (x = 0; x < logImage->width * logElement.depth; x++) {
+ for (size_t y = 0; y < logImage->height; y++) {
+ int offset = 32;
+ for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
/* we need to read the next long */
if (offset >= 30) {
if (logElement.packing == 1)
@@ -672,9 +667,9 @@ static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logE
}
}
else {
- for (y = 0; y < logImage->height; y++) {
- offset = -1;
- for (x = 0; x < logImage->width * logElement.depth; x++) {
+ for (size_t y = 0; y < logImage->height; y++) {
+ int offset = -1;
+ for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
/* we need to read the next long */
if (offset < 0) {
if (logElement.packing == 1)
@@ -699,23 +694,22 @@ static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logE
static int logImageElementGetData10Packed(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned int pixel, oldPixel;
- int offset, offset2, x, y;
/* converting bytes to pixels */
- for (y = 0; y < logImage->height; y++) {
+ for (size_t y = 0; y < logImage->height; y++) {
/* seek to data */
if (logimage_fseek(logImage, y * rowLength + logElement.dataOffset, SEEK_SET) != 0) {
- if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", y * rowLength + logElement.dataOffset);
+ if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", (unsigned int)(y * rowLength + logElement.dataOffset));
return 1;
}
oldPixel = 0;
- offset = 0;
- offset2 = 0;
+ int offset = 0;
+ int offset2 = 0;
- for (x = 0; x < logImage->width * logElement.depth; x++) {
+ for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
if (offset2 != 0) {
offset = 10 - offset2;
offset2 = 0;
@@ -778,23 +772,22 @@ static int logImageElementGetData12(LogImageFile *logImage, LogImageElement logE
static int logImageElementGetData12Packed(LogImageFile *logImage, LogImageElement logElement, float *data)
{
- unsigned int rowLength = getRowLength(logImage->width, logElement);
+ size_t rowLength = getRowLength(logImage->width, logElement);
unsigned int pixel, oldPixel;
- int offset, offset2, x, y;
/* converting bytes to pixels */
- for (y = 0; y < logImage->height; y++) {
+ for (size_t y = 0; y < logImage->height; y++) {
/* seek to data */
if (logimage_fseek(logImage, y * rowLength + logElement.dataOffset, SEEK_SET) != 0) {
- if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", y * rowLength + logElement.dataOffset);
+ if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", (unsigned int)(y * rowLength + logElement.dataOffset));
return 1;
}
oldPixel = 0;
- offset = 0;
- offset2 = 0;
+ int offset = 0;
+ int offset2 = 0;
- for (x = 0; x < logImage->width * logElement.depth; x++) {
+ for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
if (offset2 != 0) {
offset = 12 - offset2;
offset2 = 0;
@@ -1020,6 +1013,7 @@ static int convertRGBA_RGB(float *src, float *dst, LogImageFile *logImage,
float *dst_ptr = dst;
switch (logElement.transfer) {
+ case transfer_Unspecified:
case transfer_UserDefined:
case transfer_Linear:
case transfer_Logarithmic: {
@@ -1054,6 +1048,7 @@ static int convertRGBA_RGB(float *src, float *dst, LogImageFile *logImage,
}
default:
+ if (verbose) printf("DPX/Cineon: Unknown transfer %d.\n", logElement.transfer);
return 1;
}
}
@@ -1066,6 +1061,7 @@ static int convertRGB_RGBA(float *src, float *dst, LogImageFile *logImage,
float *dst_ptr = dst;
switch (logElement.transfer) {
+ case transfer_Unspecified:
case transfer_UserDefined:
case transfer_Linear:
case transfer_Logarithmic: {
@@ -1100,6 +1096,7 @@ static int convertRGB_RGBA(float *src, float *dst, LogImageFile *logImage,
}
default:
+ if (verbose) printf("DPX/Cineon: Unknown transfer %d.\n", logElement.transfer);
return 1;
}
}
@@ -1115,7 +1112,7 @@ static int convertRGBA_RGBA(float *src, float *dst, LogImageFile *logImage,
case transfer_UserDefined:
case transfer_Linear:
case transfer_Logarithmic: {
- memcpy(dst, src, 4 * logImage->width * logImage->height * sizeof(float));
+ memcpy(dst, src, 4 * (size_t)logImage->width * (size_t)logImage->height * sizeof(float));
return 0;
}
@@ -1430,11 +1427,11 @@ static int convertRGBAToLogElement(float *src, float *dst, LogImageFile *logImag
if (srcIsLinearRGB != 0) {
/* we need to convert src to sRGB */
- srgbSrc = (float *)MEM_mallocN(4 * logImage->width * logImage->height * sizeof(float), __func__);
+ srgbSrc = (float *)imb_alloc_pixels(logImage->width, logImage->height, 4, sizeof(float), __func__);
if (srgbSrc == NULL)
return 1;
- memcpy(srgbSrc, src, 4 * logImage->width * logImage->height * sizeof(float));
+ memcpy(srgbSrc, src, 4 * (size_t)logImage->width * (size_t)logImage->height * sizeof(float));
srgbSrc_ptr = srgbSrc;
/* convert data from Linear RGB to sRGB via lut */
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index e39df1ea096..b6f4fff73f6 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -196,7 +196,7 @@ LogImageFile *logImageCreate(const char *filename, int cineon, int width, int he
void logImageClose(LogImageFile *logImage);
/* Data handling */
-unsigned int getRowLength(int width, LogImageElement logElement);
+size_t getRowLength(size_t width, LogImageElement logElement);
int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB);
int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB);
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index 6c0849358a5..55727ed6697 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -260,9 +260,8 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
const uchar *mem_end = mem + size;
MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data;
IMAGE image;
- int x, y, z, tablen;
int bpp, rle, cur, badorder;
- ImBuf *ibuf;
+ ImBuf *ibuf = NULL;
uchar dirty_flag = 0;
if (size < HEADER_SIZE) {
@@ -304,7 +303,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
if (rle) {
- tablen = ysize * zsize * sizeof(int);
+ size_t tablen = (size_t)ysize * (size_t)zsize * sizeof(int);
MFILE_SEEK(inf, HEADER_SIZE);
uint *starttab = MEM_mallocN(tablen, "iris starttab");
@@ -321,8 +320,8 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
/* check data order */
cur = 0;
badorder = 0;
- for (y = 0; y < ysize; y++) {
- for (z = 0; z < zsize; z++) {
+ for (size_t y = 0; y < ysize; y++) {
+ for (size_t z = 0; z < zsize; z++) {
if (starttab[y + z * ysize] < cur) {
badorder = 1;
break;
@@ -336,14 +335,17 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
if (bpp == 1) {
ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
+ if (!ibuf) {
+ goto fail_rle;
+ }
if (ibuf->planes > 32) ibuf->planes = 32;
base = ibuf->rect;
zbase = (uint *)ibuf->zbuf;
if (badorder) {
- for (z = 0; z < zsize; z++) {
+ for (size_t z = 0; z < zsize; z++) {
lptr = base;
- for (y = 0; y < ysize; y++) {
+ for (size_t y = 0; y < ysize; y++) {
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
@@ -358,12 +360,12 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
else {
lptr = base;
zptr = zbase;
- for (y = 0; y < ysize; y++) {
+ for (size_t y = 0; y < ysize; y++) {
uint *lptr_next = lptr + xsize;
uint *zptr_next = zptr + xsize;
- for (z = 0; z < zsize; z++) {
+ for (size_t z = 0; z < zsize; z++) {
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
@@ -386,13 +388,16 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
else { /* bpp == 2 */
ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_rect) | IB_rectfloat);
-
+ if (!ibuf) {
+ goto fail_rle;
+ }
+
fbase = ibuf->rect_float;
if (badorder) {
- for (z = 0; z < zsize; z++) {
+ for (size_t z = 0; z < zsize; z++) {
fptr = fbase;
- for (y = 0; y < ysize; y++) {
+ for (size_t y = 0; y < ysize; y++) {
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
@@ -408,9 +413,9 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
fptr = fbase;
float *fptr_next = fptr + (xsize * 4);
- for (y = 0; y < ysize; y++) {
+ for (size_t y = 0; y < ysize; y++) {
- for (z = 0; z < zsize; z++) {
+ for (size_t z = 0; z < zsize; z++) {
MFILE_SEEK(inf, starttab[y + z * ysize]);
rledat = MFILE_DATA(inf);
MFILE_STEP(inf, lengthtab[y + z * ysize]);
@@ -426,6 +431,10 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
fail_rle:
MEM_freeN(starttab);
MEM_freeN(lengthtab);
+
+ if (!ibuf) {
+ return NULL;
+ }
}
else {
@@ -435,6 +444,9 @@ fail_rle:
if (bpp == 1) {
ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
+ if (!ibuf) {
+ goto fail_uncompressed;
+ }
if (ibuf->planes > 32) ibuf->planes = 32;
base = ibuf->rect;
@@ -443,12 +455,12 @@ fail_rle:
MFILE_SEEK(inf, HEADER_SIZE);
rledat = MFILE_DATA(inf);
- for (z = 0; z < zsize; z++) {
+ for (size_t z = 0; z < zsize; z++) {
if (z < 4) lptr = base;
else if (z < 8) lptr = zbase;
- for (y = 0; y < ysize; y++) {
+ for (size_t y = 0; y < ysize; y++) {
const uchar *rledat_next = rledat + xsize;
const int z_ofs = 3 - z;
MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
@@ -462,17 +474,20 @@ fail_rle:
else { /* bpp == 2 */
ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_rect) | IB_rectfloat);
+ if (!ibuf) {
+ goto fail_uncompressed;
+ }
fbase = ibuf->rect_float;
MFILE_SEEK(inf, HEADER_SIZE);
rledat = MFILE_DATA(inf);
- for (z = 0; z < zsize; z++) {
+ for (size_t z = 0; z < zsize; z++) {
fptr = fbase;
- for (y = 0; y < ysize; y++) {
+ for (size_t y = 0; y < ysize; y++) {
const uchar *rledat_next = rledat + xsize * 2;
const int z_ofs = 3 - z;
MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
@@ -485,7 +500,9 @@ fail_rle:
}
#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
fail_uncompressed:
- (void)0;
+ if (!ibuf) {
+ return NULL;
+ }
}
if (bpp == 1) {
@@ -493,7 +510,7 @@ fail_uncompressed:
if (image.zsize == 1) {
rect = (uchar *) ibuf->rect;
- for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
rect[0] = 255;
rect[1] = rect[2] = rect[3];
rect += 4;
@@ -502,7 +519,7 @@ fail_uncompressed:
else if (image.zsize == 2) {
/* grayscale with alpha */
rect = (uchar *) ibuf->rect;
- for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
rect[0] = rect[2];
rect[1] = rect[2] = rect[3];
rect += 4;
@@ -511,7 +528,7 @@ fail_uncompressed:
else if (image.zsize == 3) {
/* add alpha */
rect = (uchar *) ibuf->rect;
- for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
rect[0] = 255;
rect += 4;
}
@@ -522,7 +539,7 @@ fail_uncompressed:
if (image.zsize == 1) {
fbase = ibuf->rect_float;
- for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
fbase[0] = 1;
fbase[1] = fbase[2] = fbase[3];
fbase += 4;
@@ -531,7 +548,7 @@ fail_uncompressed:
else if (image.zsize == 2) {
/* grayscale with alpha */
fbase = ibuf->rect_float;
- for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
fbase[0] = fbase[2];
fbase[1] = fbase[2] = fbase[3];
fbase += 4;
@@ -540,7 +557,7 @@ fail_uncompressed:
else if (image.zsize == 3) {
/* add alpha */
fbase = ibuf->rect_float;
- for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
fbase[0] = 1;
fbase += 4;
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index ca534e3e2a8..539b9fa45b4 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1028,13 +1028,13 @@ void IMB_exr_write_channels(void *handle)
for (size_t i = 0; i < num_pixels; ++i, ++cur) {
*cur = rect[i * echan->xstride];
}
- half *rect_to_write = current_rect_half + (data->height - 1) * data->width;
+ half *rect_to_write = current_rect_half + (data->height - 1L) * data->width;
frameBuffer.insert(echan->name, Slice(Imf::HALF, (char *)rect_to_write,
sizeof(half), -data->width * sizeof(half)));
current_rect_half += num_pixels;
}
else {
- float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ float *rect = echan->rect + echan->xstride * (data->height - 1L) * data->width;
frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
}
@@ -1059,11 +1059,11 @@ void IMB_exr_write_channels(void *handle)
/* temporary function, used for FSA and Save Buffers */
/* called once per tile * view */
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname, bool empty)
{
+ /* Can write empty channels for incomplete renders. */
ExrHandle *data = (ExrHandle *)handle;
FrameBuffer frameBuffer;
- ExrChannel *echan;
std::string view(viewname);
const int view_id = imb_exr_get_multiView_id(*data->multiView, view);
@@ -1071,28 +1071,32 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, c
exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
exr_printf("---------------------------------------------------------------------\n");
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ if (!empty) {
+ ExrChannel *echan;
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ /* eventually we can make the parts' channels to include
+ only the current view TODO */
+ if (strcmp(viewname, echan->m->view.c_str()) != 0)
+ continue;
- /* eventually we can make the parts' channels to include
- only the current view TODO */
- if (strcmp(viewname, echan->m->view.c_str()) != 0)
- continue;
-
- exr_printf("%d %-6s %-22s \"%s\"\n",
- echan->m->part_number,
- echan->m->view.c_str(),
- echan->m->name.c_str(),
- echan->m->internal_name.c_str()
- );
-
- float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
- frameBuffer.insert(echan->m->internal_name,
- Slice(Imf::FLOAT,
- (char *)rect,
- echan->xstride * sizeof(float),
- echan->ystride * sizeof(float)
- )
- );
+ exr_printf("%d %-6s %-22s \"%s\"\n",
+ echan->m->part_number,
+ echan->m->view.c_str(),
+ echan->m->name.c_str(),
+ echan->m->internal_name.c_str()
+ );
+
+ float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ frameBuffer.insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ echan->ystride * sizeof(float)
+ )
+ );
+ }
}
TiledOutputPart out (*data->mpofile, view_id);
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index d9517d13cc4..d9338c888a7 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -67,7 +67,7 @@ float *IMB_exr_channel_rect(void *handle, const char *layname, const char *pass
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname);
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname, bool empty);
void IMB_exr_clear_channels(void *handle);
void IMB_exr_multilayer_convert(
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 05fddcb5fa5..301e827d739 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -47,7 +47,7 @@ float *IMB_exr_channel_rect (void * /*handle*/, const char * /*layname*/
void IMB_exr_read_channels (void * /*handle*/) { }
void IMB_exr_write_channels (void * /*handle*/) { }
-void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/) { }
+void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/, bool /*empty*/) { }
void IMB_exr_clear_channels (void * /*handle*/) { }
void IMB_exr_multilayer_convert(
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index dded0f7aecf..857f72e10eb 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -526,7 +526,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
unsigned char *from, *to;
unsigned short *from16;
float *to_float;
- int i, bytesperpixel;
+ unsigned int channels;
if (imb_is_a_png(mem) == 0) return(NULL);
@@ -571,7 +571,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
&color_type, NULL, NULL, NULL);
- bytesperpixel = png_get_channels(png_ptr, info_ptr);
+ channels = png_get_channels(png_ptr, info_ptr);
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
@@ -580,10 +580,10 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
case PNG_COLOR_TYPE_PALETTE:
png_set_palette_to_rgb(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
- bytesperpixel = 4;
+ channels = 4;
}
else {
- bytesperpixel = 3;
+ channels = 3;
}
break;
case PNG_COLOR_TYPE_GRAY:
@@ -593,7 +593,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
bit_depth = 8;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
/* PNG_COLOR_TYPE_GRAY may also have alpha 'values', like with palette. */
- bytesperpixel = 2;
+ channels = 2;
}
}
break;
@@ -602,7 +602,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
longjmp(png_jmpbuf(png_ptr), 1);
}
- ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0);
+ ibuf = IMB_allocImBuf(width, height, 8 * channels, 0);
if (ibuf) {
ibuf->ftype = IMB_FTYPE_PNG;
@@ -630,23 +630,23 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
imb_addrectfloatImBuf(ibuf);
png_set_swap(png_ptr);
- pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(png_uint_16), "pixels");
- if (pixels16 == NULL) {
+ pixels16 = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(png_uint_16), "pixels");
+ if (pixels16 == NULL || ibuf->rect_float == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* allocate memory for an array of row-pointers */
- row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_uint_16p), "row_pointers");
+ row_pointers = (png_bytepp) MEM_mallocN((size_t)ibuf->y * sizeof(png_uint_16p), "row_pointers");
if (row_pointers == NULL) {
printf("Cannot allocate row-pointers array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* set the individual row-pointers to point at the correct offsets */
- for (i = 0; i < ibuf->y; i++) {
+ for (size_t i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((png_uint_16 *)pixels16 + (i * ibuf->x) * bytesperpixel);
+ ((png_uint_16 *)pixels16 + (i * ibuf->x) * channels);
}
png_read_image(png_ptr, row_pointers);
@@ -656,9 +656,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
to_float = ibuf->rect_float;
from16 = pixels16;
- switch (bytesperpixel) {
+ switch (channels) {
case 4:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = from16[0] / 65535.0;
to_float[1] = from16[1] / 65535.0;
to_float[2] = from16[2] / 65535.0;
@@ -667,7 +667,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
}
break;
case 3:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = from16[0] / 65535.0;
to_float[1] = from16[1] / 65535.0;
to_float[2] = from16[2] / 65535.0;
@@ -676,14 +676,14 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
}
break;
case 2:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
to_float[3] = from16[1] / 65535.0;
to_float += 4; from16 += 2;
}
break;
case 1:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
to_float[3] = 1.0;
to_float += 4; from16++;
@@ -694,23 +694,23 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
else {
imb_addrectImBuf(ibuf);
- pixels = MEM_mallocN(((size_t)ibuf->x) * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
- if (pixels == NULL) {
+ pixels = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(unsigned char), "pixels");
+ if (pixels == NULL || ibuf->rect == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* allocate memory for an array of row-pointers */
- row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
+ row_pointers = (png_bytepp) MEM_mallocN((size_t)ibuf->y * sizeof(png_bytep), "row_pointers");
if (row_pointers == NULL) {
printf("Cannot allocate row-pointers array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* set the individual row-pointers to point at the correct offsets */
- for (i = 0; i < ibuf->y; i++) {
+ for (int i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * channels * sizeof(unsigned char));
}
png_read_image(png_ptr, row_pointers);
@@ -720,9 +720,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
to = (unsigned char *) ibuf->rect;
from = pixels;
- switch (bytesperpixel) {
+ switch (channels) {
case 4:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
@@ -731,7 +731,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
}
break;
case 3:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
@@ -740,14 +740,14 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
}
break;
case 2:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = to[1] = to[2] = from[0];
to[3] = from[1];
to += 4; from += 2;
}
break;
case 1:
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = to[1] = to[2] = from[0];
to[3] = 0xff;
to += 4; from++;
@@ -759,7 +759,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
if (flags & IB_metadata) {
png_text *text_chunks;
int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
- for (i = 0; i < count; i++) {
+ for (int i = 0; i < count; i++) {
IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
ibuf->flags |= IB_metadata;
}
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index a21468e474c..8d822a314f5 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -71,7 +71,7 @@ typedef float fCOLOR[3];
/* read routines */
static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, int xmax, const unsigned char *mem_eof)
{
- int i, rshift = 0, len = xmax;
+ size_t i, rshift = 0, len = xmax;
while (len > 0) {
if (UNLIKELY(mem_eof - mem < 4)) {
return NULL;
@@ -99,8 +99,6 @@ static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, i
static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int xmax, const unsigned char *mem_eof)
{
- int i, j, code, val;
-
if (UNLIKELY(mem_eof - mem < 4)) {
return NULL;
}
@@ -109,32 +107,32 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int
return oldreadcolrs(scan, mem, xmax, mem_eof);
}
- i = *mem++;
- if (i != 2) {
+ int val = *mem++;
+ if (val != 2) {
return oldreadcolrs(scan, mem - 1, xmax, mem_eof);
}
scan[0][GRN] = *mem++;
scan[0][BLU] = *mem++;
- i = *mem++;
+ val = *mem++;
if (scan[0][GRN] != 2 || scan[0][BLU] & 128) {
scan[0][RED] = 2;
- scan[0][EXP] = i;
+ scan[0][EXP] = val;
return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof);
}
- if (UNLIKELY(((scan[0][BLU] << 8) | i) != xmax)) {
+ if (UNLIKELY(((scan[0][BLU] << 8) | val) != xmax)) {
return NULL;
}
- for (i = 0; i < 4; i++) {
+ for (size_t i = 0; i < 4; i++) {
if (UNLIKELY(mem_eof - mem < 2)) {
return NULL;
}
- for (j = 0; j < xmax; ) {
- code = *mem++;
+ for (size_t j = 0; j < xmax; ) {
+ int code = *mem++;
if (code > 128) {
code &= 127;
if (UNLIKELY(code + j > xmax)) {
@@ -215,7 +213,6 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char
float *rect_float;
int found = 0;
int width = 0, height = 0;
- int x, y;
const unsigned char *ptr, *mem_eof = mem + size;
char oriY[80], oriX[80];
@@ -223,6 +220,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
/* find empty line, next line is resolution info */
+ size_t x;
for (x = 1; x < size; x++) {
if ((mem[x - 1] == '\n') && (mem[x] == '\n')) {
found = 1;
@@ -259,7 +257,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char
sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__);
rect_float = ibuf->rect_float;
- for (y = 0; y < height; y++) {
+ for (size_t y = 0; y < height; y++) {
ptr = freadcolrs(sline, ptr, width, mem_eof);
if (ptr == NULL) {
printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n");
@@ -293,7 +291,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char
/* ImBuf write */
static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufscan, float *fpscan)
{
- int x, i, j, beg, c2, cnt = 0;
+ int beg, c2, cnt = 0;
fCOLOR fcol;
RGBE rgbe, *rgbe_scan;
@@ -304,8 +302,7 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs
rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan");
/* convert scanline */
- j = 0;
- for (i = 0; i < width; i++) {
+ for (size_t i = 0, j = 0; i < width; i++) {
if (fpscan) {
fcol[RED] = fpscan[j];
fcol[GRN] = (channels >= 2) ? fpscan[j + 1] : fpscan[j];
@@ -322,7 +319,7 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs
}
if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */
- x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width;
+ int x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width;
MEM_freeN(rgbe_scan);
return x;
}
@@ -332,8 +329,8 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs
putc((unsigned char)(width >> 8), file);
putc((unsigned char)(width & 255), file);
/* put components separately */
- for (i = 0; i < 4; i++) {
- for (j = 0; j < width; j += cnt) { /* find next run */
+ for (size_t i = 0; i < 4; i++) {
+ for (size_t j = 0; j < width; j += cnt) { /* find next run */
for (beg = j; beg < width; beg += cnt) {
for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) && (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]); cnt++) ;
if (cnt >= MINRUN) break; /* long enough */
@@ -386,7 +383,7 @@ int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags)
{
FILE *file = BLI_fopen(name, "wb");
float *fp = NULL;
- int y, width = ibuf->x, height = ibuf->y;
+ size_t width = ibuf->x, height = ibuf->y;
unsigned char *cp = NULL;
(void)flags; /* unused */
@@ -402,7 +399,7 @@ int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags)
if (ibuf->rect_float)
fp = ibuf->rect_float + ibuf->channels * (height - 1) * width;
- for (y = height - 1; y >= 0; y--) {
+ for (size_t y = 0; y < height; y++) {
if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) {
fclose(file);
printf("HDR write error\n");
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 98aa7c5353b..afd28bb570b 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -376,7 +376,7 @@ static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image)
*/
static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
{
- ImBuf *tmpibuf;
+ ImBuf *tmpibuf = NULL;
int success = 0;
short bitspersample, spp, config;
size_t scanline;
@@ -412,16 +412,25 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (bitspersample == 32) {
ib_flag = IB_rectfloat;
fbuf = (float *)_TIFFmalloc(scanline);
+ if (!fbuf) {
+ goto cleanup;
+ }
}
else if (bitspersample == 16) {
ib_flag = IB_rectfloat;
sbuf = (unsigned short *)_TIFFmalloc(scanline);
+ if (!sbuf) {
+ goto cleanup;
+ }
}
else {
ib_flag = IB_rect;
}
tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ib_flag);
+ if (!tmpibuf) {
+ goto cleanup;
+ }
/* simple RGBA image */
if (!(bitspersample == 32 || bitspersample == 16)) {
@@ -430,7 +439,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
/* contiguous channels: RGBRGBRGB */
else if (config == PLANARCONFIG_CONTIG) {
for (row = 0; row < ibuf->y; row++) {
- int ib_offset = ibuf->x * ibuf->y * 4 - ibuf->x * 4 * (row + 1);
+ size_t ib_offset = (size_t)ibuf->x * 4 * ((size_t)ibuf->y - ((size_t)row + 1));
if (bitspersample == 32) {
success |= TIFFReadScanline(image, fbuf, row, 0);
@@ -450,7 +459,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
* but only fill in from the TIFF scanline where necessary. */
for (chan = 0; chan < 4; chan++) {
for (row = 0; row < ibuf->y; row++) {
- int ib_offset = ibuf->x * ibuf->y * 4 - ibuf->x * 4 * (row + 1);
+ size_t ib_offset = (size_t)ibuf->x * 4 * ((size_t)ibuf->y - ((size_t)row + 1));
if (bitspersample == 32) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
@@ -475,11 +484,6 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
}
}
}
-
- if (bitspersample == 32)
- _TIFFfree(fbuf);
- else if (bitspersample == 16)
- _TIFFfree(sbuf);
if (success) {
/* Code seems to be not needed for 16 bits tif, on PPC G5 OSX (ton) */
@@ -498,6 +502,12 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
tmpibuf->mall &= ~ib_flag;
}
+cleanup:
+ if (bitspersample == 32)
+ _TIFFfree(fbuf);
+ else if (bitspersample == 16)
+ _TIFFfree(sbuf);
+
IMB_freeImBuf(tmpibuf);
return success;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 4e1161148ea..fd8cd8b2855 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -211,13 +211,18 @@ typedef struct ID {
int tag;
int us;
int icon_id;
+ int recalc;
+ int pad;
IDProperty *properties;
IDOverrideStatic *override_static; /* Reference linked ID which this one overrides. */
- void *py_instance;
+ /* Only set for datablocks which are coming from copy-on-write, points to
+ * the original version of it.
+ */
+ void *orig_id;
- void *pad1;
+ void *py_instance;
} ID;
/**
@@ -373,6 +378,12 @@ typedef enum ID_Type {
#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL)
+#define ID_IS_STATIC_OVERRIDE(_id) (((ID *)(_id))->override_static != NULL && \
+ ((ID *)(_id))->override_static->reference != NULL)
+
+#define ID_IS_STATIC_OVERRIDE_TEMPLATE(_id) (((ID *)(_id))->override_static != NULL && \
+ ((ID *)(_id))->override_static->reference == NULL)
+
#ifdef GS
# undef GS
#endif
@@ -437,22 +448,32 @@ enum {
/* RESET_AFTER_USE tag existing data before linking so we know what is new. */
LIB_TAG_PRE_EXISTING = 1 << 11,
- /* RESET_AFTER_USE, used by update code (depsgraph). */
- LIB_TAG_ID_RECALC = 1 << 12,
- LIB_TAG_ID_RECALC_DATA = 1 << 13,
- LIB_TAG_ANIM_NO_RECALC = 1 << 14,
- LIB_TAG_ID_RECALC_ALL = (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA),
-
/* The datablock is a copy-on-write version. */
- LIB_TAG_COPY_ON_WRITE = 1 << 15,
- LIB_TAG_COPY_ON_WRITE_EVAL = 1 << 16,
+ LIB_TAG_COPY_ON_WRITE = 1 << 12,
+ LIB_TAG_COPY_ON_WRITE_EVAL = 1 << 13,
/* RESET_NEVER tag datablock for freeing etc. behavior (usually set when copying real one into temp/runtime one). */
- LIB_TAG_NO_MAIN = 1 << 17, /* Datablock is not listed in Main database. */
- LIB_TAG_NO_USER_REFCOUNT = 1 << 18, /* Datablock does not refcount usages of other IDs. */
+ LIB_TAG_NO_MAIN = 1 << 14, /* Datablock is not listed in Main database. */
+ LIB_TAG_NO_USER_REFCOUNT = 1 << 15, /* Datablock does not refcount usages of other IDs. */
/* Datablock was not allocated by standard system (BKE_libblock_alloc), do not free its memory
* (usual type-specific freeing is called though). */
- LIB_TAG_NOT_ALLOCATED = 1 << 19,
+ LIB_TAG_NOT_ALLOCATED = 1 << 16,
+};
+
+enum {
+ /* RESET_AFTER_USE, used by update code (depsgraph). */
+ ID_RECALC_NONE = 0,
+ /* Generic recalc flag, when nothing else matches. */
+ ID_RECALC = 1 << 0,
+ /* Per-component update flags. */
+ ID_RECALC_ANIMATION = 1 << 1,
+ ID_RECALC_DRAW = 1 << 2,
+ ID_RECALC_DRAW_CACHE = 1 << 3,
+ ID_RECALC_GEOMETRY = 1 << 4,
+ ID_RECALC_TRANSFORM = 1 << 5,
+ ID_RECALC_COLLECTIONS = 1 << 6,
+ /* Special flag to check if SOMETHING was changed. */
+ ID_RECALC_ALL = (~(int)0),
};
/* To filter ID types (filter_id) */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 261e0a5410f..48fe82b3e1a 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -87,9 +87,7 @@ typedef struct BevList {
int charidx;
int *segbevcount;
float *seglen;
-
- /* over-alloc */
- BevPoint bevpoints[0];
+ BevPoint *bevpoints;
} BevList;
/**
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index c677383cb6e..806c1ca76fc 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -65,7 +65,7 @@ typedef struct LayerCollection {
/* TODO(sergey): Get rid of this once we've got CoW in DEG, */
short flag_evaluated;
short pad[2];
- ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects and collection->filter_objects */
+ ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects */
ListBase overrides;
ListBase layer_collections; /* synced with collection->collections */
struct IDProperty *properties; /* overrides */
@@ -102,12 +102,10 @@ typedef struct ViewLayer {
typedef struct SceneCollection {
struct SceneCollection *next, *prev;
char name[64]; /* MAX_NAME */
- char filter[64]; /* MAX_NAME */
int active_object_index; /* for UI */
char type;
char pad[3];
ListBase objects; /* (Object *)LinkData->data */
- ListBase filter_objects; /* (Object *)LinkData->data */
ListBase scene_collections; /* nested collections */
} SceneCollection;
@@ -123,9 +121,10 @@ enum {
/* LayerCollection->flag */
enum {
- COLLECTION_VISIBLE = (1 << 0),
+ COLLECTION_VIEWPORT = (1 << 0), /* Only used for group collections. */
COLLECTION_SELECTABLE = (1 << 1),
COLLECTION_DISABLED = (1 << 2),
+ COLLECTION_RENDER = (1 << 3), /* Only used for group collections. */
};
/* ViewLayer->flag */
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
index 75705f7dd37..649df714457 100644
--- a/source/blender/makesdna/DNA_lightprobe_types.h
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -55,7 +55,9 @@ typedef struct LightProbe {
float clipsta, clipend;
float vis_bias, vis_bleedbias; /* VSM visibility biases */
- float vis_blur, pad2;
+ float vis_blur;
+
+ float intensity; /* Intensity multiplier */
int grid_resolution_x; /* Irradiance grid resolution */
int grid_resolution_y;
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 59d30d175a5..5df7e49c2f3 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -249,6 +249,7 @@ typedef struct ArrayModifierData {
int flags;
/* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */
int count;
+ float uv_offset[2];
} ArrayModifierData;
/* ArrayModifierData->fit_type */
@@ -867,8 +868,8 @@ typedef struct SimpleDeformModifierData {
char mode; /* deform function */
char axis; /* lock axis (for taper and strech) */
+ char deform_axis; /* axis to perform the deform on (default is X, but can be overridden by origin */
char flag;
- char pad;
} SimpleDeformModifierData;
@@ -888,6 +889,7 @@ enum {
enum {
MOD_SIMPLEDEFORM_LOCK_AXIS_X = (1 << 0),
MOD_SIMPLEDEFORM_LOCK_AXIS_Y = (1 << 1),
+ MOD_SIMPLEDEFORM_LOCK_AXIS_Z = (1 << 2),
};
typedef struct ShapeKeyModifierData {
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 78c623f6408..7c3ef5e72be 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -75,11 +75,19 @@ typedef struct bFaceMap {
} bFaceMap;
/* Object Runtime display data */
+struct ObjectEngineData;
+typedef void (*ObjectEngineDataInitCb)(struct ObjectEngineData *engine_data);
+typedef void (*ObjectEngineDataFreeCb)(struct ObjectEngineData *engine_data);
+
+#
+#
typedef struct ObjectEngineData {
struct ObjectEngineData *next, *prev;
struct DrawEngineType *engine_type;
- void *storage;
- void (*free)(void *storage);
+ /* Only nested data, NOT the engine data itself. */
+ ObjectEngineDataFreeCb free;
+ /* Accumulated recalc flags, which corresponds to ID->recalc flags. */
+ int recalc;
} ObjectEngineData;
#define MAX_VGROUP_NAME 64
@@ -154,6 +162,7 @@ typedef struct Object {
bAnimVizSettings avs; /* settings for visualization of object-transform animation */
bMotionPath *mpath; /* motion path cache for this object */
+ void *pad1;
ListBase constraintChannels DNA_DEPRECATED; // XXX deprecated... old animation system
ListBase effect DNA_DEPRECATED; // XXX deprecated... keep for readfile
@@ -203,11 +212,11 @@ typedef struct Object {
short nlaflag; /* used for DopeSheet filtering settings (expanded/collapsed) */
short scaflag; /* ui state for game logic */
char scavisflag; /* more display settings for game logic */
- char depsflag;
+ char pad;
/* did last modifier stack generation need mapping support? */
char lastNeedMapping; /* bool */
- char pad;
+ char duplicator_visibility_flag;
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
@@ -276,8 +285,6 @@ typedef struct Object {
int gameflag;
int gameflag2;
- struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */
-
char restrictflag; /* for restricting view, select, render etc. accessible in outliner */
char pad3;
short softflag; /* softbody settings */
@@ -288,6 +295,7 @@ typedef struct Object {
ListBase hooks DNA_DEPRECATED; // XXX deprecated... old animation system
ListBase particlesystem; /* particle systems */
+ struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */
struct PartDeflect *pd; /* particle deflector/attractor/collision data */
struct SoftBody *soft; /* if exists, saved in file */
struct Group *dup_group; /* object duplicator for group */
@@ -300,6 +308,7 @@ typedef struct Object {
struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */
struct DerivedMesh *derivedDeform, *derivedFinal;
+ void *pad7;
uint64_t lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */
uint64_t customdata_mask; /* (extra) custom data layer mask to use for creating derivedmesh, set by depsgraph */
unsigned int state; /* bit masks of game controllers that are active */
@@ -317,6 +326,7 @@ typedef struct Object {
float ima_ofs[2]; /* offset for image empties */
ImageUser *iuser; /* must be non-null when oject is an empty image */
+ void *pad4;
ListBase lodlevels; /* contains data for levels of detail */
LodLevel *currentlod;
@@ -326,7 +336,7 @@ typedef struct Object {
struct IDProperty *base_collection_properties; /* used by depsgraph, flushed from base */
ListBase drawdata; /* runtime, ObjectEngineData */
- int pad1;
+ int pad6;
int select_color;
/* Mesh structure createrd during object evaluaiton.
@@ -627,17 +637,6 @@ enum {
OB_BODY_TYPE_CHARACTER = 8,
};
-/* ob->depsflag */
-enum {
- OB_DEPS_EXTRA_OB_RECALC = 1 << 0,
- OB_DEPS_EXTRA_DATA_RECALC = 1 << 1,
-};
-
-/* ob->deg_update_flag */
-enum {
- DEG_RUNTIME_DATA_UPDATE = 1 << 0,
-};
-
/* ob->scavisflag */
enum {
OB_VIS_SENS = 1 << 0,
@@ -706,6 +705,12 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
+/* ob->duplicator_visibility_flag */
+enum {
+ OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
+ OB_DUPLI_FLAG_RENDER = 1 << 1,
+};
+
/* ob->mode */
typedef enum eObjectMode {
OB_MODE_OBJECT = 0,
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index 81575beaac8..8e48bbdde1a 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -102,8 +102,9 @@ enum {
#define TSE_KEYMAP_ITEM 35 /* NO ID */
#define TSE_ID_BASE 36 /* NO ID */
#define TSE_GP_LAYER 37 /* NO ID */
-#define TSE_LAYER_COLLECTION 38 /* NO ID */
-#define TSE_SCENE_COLLECTION 39 /* NO ID */
+#define TSE_LAYER_COLLECTION 38
+#define TSE_SCENE_COLLECTION 39
+#define TSE_LAYER_COLLECTION_BASE 40
/* Check whether given TreeStoreElem should have a real ID in its ->id member. */
@@ -111,8 +112,7 @@ enum {
(!ELEM((_tse)->type, TSE_NLA, TSE_NLA_TRACK, TSE_DRIVER_BASE, \
TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, \
TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, \
- TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER, \
- TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION))
+ TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER))
#endif
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index d25391ca95d..671ad1bc954 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -180,7 +180,8 @@ typedef struct SceneRenderLayer {
unsigned int lay_zmask DNA_DEPRECATED; /* Converted to LayerCollection cycles holdout override. */
unsigned int lay_exclude DNA_DEPRECATED;
int layflag DNA_DEPRECATED; /* Converted to ViewLayer layflag and flag. */
-
+
+ /* pass_xor has to be after passflag */
int passflag DNA_DEPRECATED; /* pass_xor has to be after passflag */
int pass_xor DNA_DEPRECATED; /* Converted to ViewLayer passflag and flag. */
@@ -192,7 +193,7 @@ typedef struct SceneRenderLayer {
struct FreestyleConfig freestyleConfig DNA_DEPRECATED; /* Converted to ViewLayer freestyleConfig. */
} SceneRenderLayer;
-/* srl->layflag */
+/* SceneRenderLayer.layflag */
#define SCE_LAY_SOLID 1
#define SCE_LAY_ZTRA 2
#define SCE_LAY_HALO 4
@@ -209,7 +210,7 @@ typedef struct SceneRenderLayer {
#define SCE_LAY_ZMASK 0x40000
#define SCE_LAY_NEG_ZMASK 0x80000
-/* srl->passflag */
+/* SceneRenderLayer.passflag */
typedef enum eScenePassType {
SCE_PASS_COMBINED = (1 << 0),
SCE_PASS_Z = (1 << 1),
@@ -279,7 +280,6 @@ typedef enum eScenePassType {
#define RE_PASSNAME_SUBSURFACE_INDIRECT "SubsurfaceInd"
#define RE_PASSNAME_SUBSURFACE_COLOR "SubsurfaceCol"
-/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
/* View - MultiView */
typedef struct SceneRenderView {
@@ -294,16 +294,16 @@ typedef struct SceneRenderView {
} SceneRenderView;
-/* srv->viewflag */
+/* SceneRenderView.viewflag */
#define SCE_VIEW_DISABLE (1<<0)
-/* scene.render.views_format */
+/* RenderData.views_format */
enum {
SCE_VIEWS_FORMAT_STEREO_3D = 0,
SCE_VIEWS_FORMAT_MULTIVIEW = 1,
};
-/* ImageFormatData.views_output */
+/* ImageFormatData.views_format (also used for Sequence.views_format) */
enum {
R_IMF_VIEWS_INDIVIDUAL = 0,
R_IMF_VIEWS_STEREO_3D = 1,
@@ -503,7 +503,7 @@ typedef struct BakeData {
char cage[64]; /* MAX_NAME */
} BakeData;
-/* (char) normal_swizzle */
+/* BakeData.normal_swizzle (char) */
typedef enum eBakeNormalSwizzle {
R_BAKE_POSX = 0,
R_BAKE_POSY = 1,
@@ -513,13 +513,13 @@ typedef enum eBakeNormalSwizzle {
R_BAKE_NEGZ = 5,
} eBakeNormalSwizzle;
-/* (char) save_mode */
+/* BakeData.save_mode (char) */
typedef enum eBakeSaveMode {
R_BAKE_SAVE_INTERNAL = 0,
R_BAKE_SAVE_EXTERNAL = 1,
} eBakeSaveMode;
-/* bake->pass_filter */
+/* BakeData.pass_filter */
typedef enum eBakePassFilter {
R_BAKE_PASS_FILTER_NONE = 0,
R_BAKE_PASS_FILTER_AO = (1 << 0),
@@ -801,6 +801,7 @@ typedef struct GameDome {
struct Text *warptext;
} GameDome;
+/* GameDome.mode */
#define DOME_FISHEYE 1
#define DOME_TRUNCATED_FRONT 2
#define DOME_TRUNCATED_REAR 3
@@ -816,6 +817,7 @@ typedef struct GameFraming {
char type, pad1, pad2, pad3;
} GameFraming;
+/* GameFraming.type */
#define SCE_GAMEFRAMING_BARS 0
#define SCE_GAMEFRAMING_EXTEND 1
#define SCE_GAMEFRAMING_SCALE 2
@@ -839,6 +841,7 @@ typedef struct RecastData {
short pad2;
} RecastData;
+/* RecastData.partitioning */
#define RC_PARTITION_WATERSHED 0
#define RC_PARTITION_MONOTONE 1
#define RC_PARTITION_LAYERS 2
@@ -885,12 +888,15 @@ typedef struct GameData {
/* Scene LoD */
short lodflag, pad2;
int scehysteresis, pad5;
+
} GameData;
+/* GameData.stereoflag */
#define STEREO_NOSTEREO 1
#define STEREO_ENABLED 2
#define STEREO_DOME 3
+/* GameData.stereomode */
//#define STEREO_NOSTEREO 1
#define STEREO_QUADBUFFERED 2
#define STEREO_ABOVEBELOW 3
@@ -901,7 +907,7 @@ typedef struct GameData {
//#define STEREO_DOME 8
#define STEREO_3DTVTOPBOTTOM 9
-/* physicsEngine */
+/* GameData.physicsEngine */
#define WOPHY_NONE 0
#define WOPHY_BULLET 5
@@ -910,13 +916,13 @@ typedef struct GameData {
#define OBSTSIMULATION_TOI_rays 1
#define OBSTSIMULATION_TOI_cells 2
-/* Raster storage */
+/* GameData.raster_storage */
#define RAS_STORE_AUTO 0
-#define RAS_STORE_IMMEDIATE 1
+/* #define RAS_STORE_IMMEDIATE 1 */ /* DEPRECATED */
#define RAS_STORE_VA 2
#define RAS_STORE_VBO 3
-/* vsync */
+/* GameData.vsync */
#define VSYNC_ON 0
#define VSYNC_OFF 1
#define VSYNC_ADAPTIVE 2
@@ -960,13 +966,16 @@ enum {
#define SCE_LOD_USE_HYST (1 << 0)
/* UV Paint */
+/* ToolSettings.uv_sculpt_settings */
#define UV_SCULPT_LOCK_BORDERS 1
#define UV_SCULPT_ALL_ISLANDS 2
+/* ToolSettings.uv_sculpt_tool */
#define UV_SCULPT_TOOL_PINCH 1
#define UV_SCULPT_TOOL_RELAX 2
#define UV_SCULPT_TOOL_GRAB 3
+/* ToolSettings.uv_relax_method */
#define UV_SCULPT_TOOL_RELAX_LAPLACIAN 1
#define UV_SCULPT_TOOL_RELAX_HC 2
@@ -976,6 +985,7 @@ enum {
#define STEREO_RIGHT_SUFFIX "_R"
#define STEREO_LEFT_SUFFIX "_L"
+/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */
typedef enum eStereoViews {
STEREO_LEFT_ID = 0,
STEREO_RIGHT_ID = 1,
@@ -986,7 +996,7 @@ typedef enum eStereoViews {
/* *************************************************************** */
/* Markers */
-typedef struct TimeMarker {
+typedef struct TimeMarker {
struct TimeMarker *next, *prev;
int frame;
char name[64];
@@ -1064,7 +1074,7 @@ typedef struct ParticleEditSettings {
short totaddkey;
short brushtype;
- ParticleBrushData brush[7]; /* 7 = PE_TOT_BRUSH */
+ ParticleBrushData brush[7];
void *paintcursor; /* runtime */
float emitterdist, rt;
@@ -1136,7 +1146,7 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* Brush types */
+/* GP_BrushEdit_Settings.brushtype */
typedef enum eGP_EditBrush_Types {
GP_EDITBRUSH_TYPE_SMOOTH = 0,
GP_EDITBRUSH_TYPE_THICKNESS = 1,
@@ -1154,7 +1164,7 @@ typedef enum eGP_EditBrush_Types {
TOT_GP_EDITBRUSH_TYPES
} eGP_EditBrush_Types;
-/* Lock axis options */
+/* GP_BrushEdit_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_NONE = 0,
GP_LOCKAXIS_X = 1,
@@ -1192,7 +1202,7 @@ typedef struct GP_BrushEdit_Settings {
int brushtype; /* eGP_EditBrush_Types */
int flag; /* eGP_BrushEdit_SettingsFlag */
- int lock_axis; /* lock drawing to one axis */
+ int lock_axis; /* eGP_Lockaxis_Types lock drawing to one axis */
float alpha; /* alpha factor for selection color */
} GP_BrushEdit_Settings;
@@ -1331,6 +1341,7 @@ typedef struct UnifiedPaintSettings {
struct ColorSpace *colorspace;
} UnifiedPaintSettings;
+/* UnifiedPaintSettings.flag */
typedef enum {
UNIFIED_PAINT_SIZE = (1 << 0),
UNIFIED_PAINT_ALPHA = (1 << 1),
@@ -1667,17 +1678,15 @@ typedef struct Scene {
/* Grease Pencil */
struct bGPdata *gpd;
+ /* Movie Tracking */
+ struct MovieClip *clip; /* active movie clip */
+
/* Physics simulation settings */
struct PhysicsSettings physics_settings;
- void *pad6;
-
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
- /* Movie Tracking */
- struct MovieClip *clip; /* active movie clip */
-
/* Color Management */
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
@@ -1703,14 +1712,14 @@ typedef struct Scene {
/* **************** RENDERDATA ********************* */
-/* flag */
+/* RenderData.flag */
/* use preview range */
#define SCER_PRV_RANGE (1<<0)
#define SCER_LOCK_FRAME_SELECTION (1<<1)
/* show/use subframes (for checking motion blur) */
#define SCER_SHOW_SUBFRAME (1<<3)
-/* mode (int now) */
+/* RenderData.mode */
#define R_OSA 0x0001
#define R_SHADOW 0x0002
#define R_GAMMA 0x0004
@@ -1723,7 +1732,8 @@ typedef struct Scene {
#define R_BORDER 0x0200
#define R_PANORAMA 0x0400 /* deprecated as scene option, still used in renderer */
#define R_CROP 0x0800
-/*#define R_COSMO 0x1000 deprecated */
+ /* Disable camera switching: runtime (DURIAN_CAMERA_SWITCH) */
+#define R_NO_CAMERA_SWITCH 0x1000
#define R_ODDFIELD 0x2000
#define R_MBLUR 0x4000
/* unified was here */
@@ -1746,7 +1756,7 @@ typedef struct Scene {
#define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */
#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */
-/* seq_flag */
+/* RenderData.seq_flag */
enum {
// R_SEQ_GL_PREV = (1 << 1), // UNUSED, we just use setting from seq_prev_type now.
// R_SEQ_GL_REND = (1 << 2), // UNUSED, opengl render has its own operator now.
@@ -1754,15 +1764,14 @@ enum {
R_SEQ_CAMERA_DOF = (1 << 4),
};
-/* displaymode */
-
+/* RenderData.displaymode */
#define R_OUTPUT_SCREEN 0
#define R_OUTPUT_AREA 1
#define R_OUTPUT_WINDOW 2
#define R_OUTPUT_NONE 3
/*#define R_OUTPUT_FORKED 4*/
-/* filtertype */
+/* RenderData.filtertype */
#define R_FILTER_BOX 0
#define R_FILTER_TENT 1
#define R_FILTER_QUAD 2
@@ -1772,7 +1781,7 @@ enum {
#define R_FILTER_MITCH 6
#define R_FILTER_FAST_GAUSS 7 /* note, this is only used for nodes at the moment */
-/* raytrace structure */
+/* RenderData.raytrace_structure */
#define R_RAYSTRUCTURE_AUTO 0
#define R_RAYSTRUCTURE_OCTREE 1
#define R_RAYSTRUCTURE_BLIBVH 2 /* removed */
@@ -1780,11 +1789,11 @@ enum {
#define R_RAYSTRUCTURE_SIMD_SVBVH 4 /* needs SIMD */
#define R_RAYSTRUCTURE_SIMD_QBVH 5 /* needs SIMD */
-/* raytrace_options */
+/* RenderData.raytrace_options */
#define R_RAYTRACE_USE_LOCAL_COORDS 0x0001
#define R_RAYTRACE_USE_INSTANCES 0x0002
-/* scemode (int now) */
+/* RenderData.scemode (int now) */
#define R_DOSEQ 0x0001
#define R_BG_RENDER 0x0002
/* passepartout is camera option now, keep this for backward compatibility */
@@ -1809,7 +1818,7 @@ enum {
#define R_EXR_CACHE_FILE 0x100000
#define R_MULTIVIEW 0x200000
-/* r->stamp */
+/* RenderData.stamp */
#define R_STAMP_TIME 0x0001
#define R_STAMP_FRAME 0x0002
#define R_STAMP_DATE 0x0004
@@ -1830,19 +1839,19 @@ enum {
R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \
R_STAMP_HIDE_LABELS)
-/* alphamode */
+/* RenderData.alphamode */
#define R_ADDSKY 0
#define R_ALPHAPREMUL 1
/*#define R_ALPHAKEY 2*/ /* deprecated, shouldn't be used */
-/* color_mgt_flag */
+/* RenderData.color_mgt_flag */
enum {
R_COLOR_MANAGEMENT = (1 << 0), /* deprecated, should only be used in versioning code only */
/*R_COLOR_MANAGEMENT_PREDIVIDE = (1 << 1)*/ /* deprecated, shouldn't be used */
};
#ifdef DNA_DEPRECATED
-/* subimtype, flag options for imtype */
+/* RenderData.subimtype flag options for imtype */
enum {
R_OPENEXR_HALF = 1, /*deprecated*/
R_OPENEXR_ZBUF = 2, /*deprecated*/
@@ -1859,7 +1868,7 @@ enum {
#endif
/* bake_mode: same as RE_BAKE_xxx defines */
-/* bake_flag: */
+/* RenderData.bake_flag */
#define R_BAKE_CLEAR 1
#define R_BAKE_OSA 2
#define R_BAKE_TO_ACTIVE 4
@@ -1872,22 +1881,22 @@ enum {
#define R_BAKE_SPLIT_MAT 512
#define R_BAKE_AUTO_NAME 1024
-/* bake_normal_space */
+/* RenderData.bake_normal_space */
#define R_BAKE_SPACE_CAMERA 0
#define R_BAKE_SPACE_WORLD 1
#define R_BAKE_SPACE_OBJECT 2
#define R_BAKE_SPACE_TANGENT 3
-/* simplify_flag */
+/* RenderData.simplify_flag */
#define R_SIMPLE_NO_TRIANGULATE 1
-/* line_thickness_mode */
+/* RenderData.line_thickness_mode */
#define R_LINE_THICKNESS_ABSOLUTE 1
#define R_LINE_THICKNESS_RELATIVE 2
/* sequencer seq_prev_type seq_rend_type */
-/* scene->r.engine (scene.c) */
+/* RenderData.engine (scene.c) */
extern const char *RE_engine_id_BLENDER_RENDER;
extern const char *RE_engine_id_BLENDER_GAME;
extern const char *RE_engine_id_BLENDER_CLAY;
@@ -1949,9 +1958,9 @@ extern const char *RE_engine_id_CYCLES;
#define TIME2FRA(a) ((((double) scene->r.frs_sec) * (double)(a)) / (double)scene->r.frs_sec_base)
#define FPS (((double) scene->r.frs_sec) / (double)scene->r.frs_sec_base)
-/* base->legacy_flag is in DNA_object_types.h */
+/* Base.flag is in DNA_object_types.h */
-/* toolsettings->snap_flag */
+/* ToolSettings.snap_flag */
#define SCE_SNAP 1
#define SCE_SNAP_ROTATE 2
#define SCE_SNAP_PEEL_OBJECT 4
@@ -1959,12 +1968,12 @@ extern const char *RE_engine_id_CYCLES;
#define SCE_SNAP_NO_SELF 16
#define SCE_SNAP_ABS_GRID 32
-/* toolsettings->snap_target */
+/* ToolSettings.snap_target */
#define SCE_SNAP_TARGET_CLOSEST 0
#define SCE_SNAP_TARGET_CENTER 1
#define SCE_SNAP_TARGET_MEDIAN 2
#define SCE_SNAP_TARGET_ACTIVE 3
-/* toolsettings->snap_mode */
+/* ToolSettings.snap_mode */
#define SCE_SNAP_MODE_INCREMENT 0
#define SCE_SNAP_MODE_VERTEX 1
#define SCE_SNAP_MODE_EDGE 2
@@ -1975,24 +1984,24 @@ extern const char *RE_engine_id_CYCLES;
#define SCE_SNAP_MODE_NODE_XY 7
#define SCE_SNAP_MODE_GRID 8
-/* toolsettings->selectmode */
+/* ToolSettings.selectmode */
#define SCE_SELECT_VERTEX 1 /* for mesh */
#define SCE_SELECT_EDGE 2
#define SCE_SELECT_FACE 4
-/* toolsettings->statvis->type */
+/* MeshStatVis.type */
#define SCE_STATVIS_OVERHANG 0
#define SCE_STATVIS_THICKNESS 1
#define SCE_STATVIS_INTERSECT 2
#define SCE_STATVIS_DISTORT 3
#define SCE_STATVIS_SHARP 4
-/* toolsettings->particle.selectmode for particles */
+/* ParticleEditSettings.selectmode for particles */
#define SCE_SELECT_PATH 1
#define SCE_SELECT_POINT 2
#define SCE_SELECT_END 4
-/* toolsettings->prop_mode (proportional falloff) */
+/* ToolSettings.prop_mode (proportional falloff) */
#define PROP_SMOOTH 0
#define PROP_SPHERE 1
#define PROP_ROOT 2
@@ -2003,21 +2012,21 @@ extern const char *RE_engine_id_CYCLES;
#define PROP_INVSQUARE 7
#define PROP_MODE_MAX 8
-/* toolsettings->proportional */
+/* ToolSettings.proportional */
#define PROP_EDIT_OFF 0
#define PROP_EDIT_ON 1
#define PROP_EDIT_CONNECTED 2
#define PROP_EDIT_PROJECTED 3
-/* toolsettings->weightuser */
+/* ToolSettings.weightuser */
enum {
OB_DRAW_GROUPUSER_NONE = 0,
OB_DRAW_GROUPUSER_ACTIVE = 1,
OB_DRAW_GROUPUSER_ALL = 2
};
-/* toolsettings->vgroupsubset */
/* object_vgroup.c */
+/* ToolSettings.vgroupsubset */
typedef enum eVGroupSelect {
WT_VGROUP_ALL = 0,
WT_VGROUP_ACTIVE = 1,
@@ -2034,26 +2043,26 @@ typedef enum eVGroupSelect {
(1 << WT_VGROUP_ALL))
-/* sce->flag */
+/* Scene.flag */
#define SCE_DS_SELECTED (1<<0)
#define SCE_DS_COLLAPSED (1<<1)
#define SCE_NLA_EDIT_ON (1<<2)
#define SCE_FRAME_DROP (1<<3)
#define SCE_KEYS_NO_SELONLY (1<<4)
-
/* return flag BKE_scene_base_iter_next functions */
/* #define F_ERROR -1 */ /* UNUSED */
#define F_START 0
#define F_SCENE 1
#define F_DUPLI 3
-/* audio->flag */
+/* AudioData.flag */
#define AUDIO_MUTE (1<<0)
#define AUDIO_SYNC (1<<1)
#define AUDIO_SCRUB (1<<2)
#define AUDIO_VOLUME_ANIMATED (1<<3)
+/* FFMpegCodecData.flags */
enum {
#ifdef DNA_DEPRECATED
FFMPEG_MULTIPLEX_AUDIO = 1, /* deprecated, you can choose none as audiocodec now */
@@ -2117,12 +2126,16 @@ typedef enum eSculptFlags {
/* If set, dynamic-topology detail size will be constant in object space */
SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13),
SCULPT_DYNTOPO_DETAIL_BRUSH = (1 << 14),
+
+ /* Don't display mask in viewport, but still use it for strokes. */
+ SCULPT_HIDE_MASK = (1 << 15),
} eSculptFlags;
-typedef enum eImageePaintMode {
+/* ImagePaintSettings.mode */
+typedef enum eImagePaintMode {
IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */
IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */
-} eImageePaintMode;
+} eImagePaintMode;
/* ImagePaintSettings.flag */
#define IMAGEPAINT_DRAWING 1
@@ -2130,6 +2143,7 @@ typedef enum eImageePaintMode {
// #define IMAGEPAINT_DRAW_TOOL_DRAWING 4 // deprecated
/* projection painting only */
+/* ImagePaintSettings.flag */
#define IMAGEPAINT_PROJECT_XRAY (1 << 4)
#define IMAGEPAINT_PROJECT_BACKFACE (1 << 5)
#define IMAGEPAINT_PROJECT_FLAT (1 << 6)
@@ -2137,29 +2151,29 @@ typedef enum eImageePaintMode {
#define IMAGEPAINT_PROJECT_LAYER_STENCIL (1 << 8)
#define IMAGEPAINT_PROJECT_LAYER_STENCIL_INV (1 << 9)
-
+/* ImagePaintSettings.missing_data */
#define IMAGEPAINT_MISSING_UVS (1 << 0)
#define IMAGEPAINT_MISSING_MATERIAL (1 << 1)
#define IMAGEPAINT_MISSING_TEX (1 << 2)
#define IMAGEPAINT_MISSING_STENCIL (1 << 3)
-/* toolsettings->uvcalc_flag */
+/* ToolSettings.uvcalc_flag */
#define UVCALC_FILLHOLES 1
#define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */
#define UVCALC_TRANSFORM_CORRECT 4 /* adjust UV's while transforming to avoid distortion */
#define UVCALC_USESUBSURF 8 /* Use mesh data after subsurf to compute UVs*/
-/* toolsettings->uv_flag */
+/* ToolSettings.uv_flag */
#define UV_SYNC_SELECTION 1
#define UV_SHOW_SAME_IMAGE 2
-/* toolsettings->uv_selectmode */
+/* ToolSettings.uv_selectmode */
#define UV_SELECT_VERTEX 1
#define UV_SELECT_EDGE 2
#define UV_SELECT_FACE 4
#define UV_SELECT_ISLAND 8
-/* toolsettings->edge_mode */
+/* ToolSettings.edge_mode */
#define EDGE_MODE_SELECT 0
#define EDGE_MODE_TAG_SEAM 1
#define EDGE_MODE_TAG_SHARP 2
@@ -2167,7 +2181,7 @@ typedef enum eImageePaintMode {
#define EDGE_MODE_TAG_BEVEL 4
#define EDGE_MODE_TAG_FREESTYLE 5
-/* toolsettings->gpencil_flags */
+/* ToolSettings.gpencil_flags */
typedef enum eGPencil_Flags {
/* "Continuous Drawing" - The drawing operator enters a mode where multiple strokes can be drawn */
GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0),
@@ -2177,13 +2191,13 @@ typedef enum eGPencil_Flags {
GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2)
} eGPencil_Flags;
-/* toolsettings->gpencil_src */
+/* ToolSettings.gpencil_src */
typedef enum eGPencil_Source_3D {
GP_TOOL_SOURCE_SCENE = 0,
GP_TOOL_SOURCE_OBJECT = 1
} eGPencil_Source_3d;
-/* toolsettings->gpencil_*_align - Stroke Placement mode flags */
+/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
typedef enum eGPencil_Placement_Flags {
/* New strokes are added in viewport/data space (i.e. not screen space) */
GP_PROJECT_VIEWSPACE = (1 << 0),
@@ -2199,7 +2213,7 @@ typedef enum eGPencil_Placement_Flags {
GP_PROJECT_DEPTH_STROKE_ENDPOINTS = (1 << 4),
} eGPencil_Placement_Flags;
-/* toolsettings->particle flag */
+/* ToolSettings.particle flag */
#define PE_KEEP_LENGTHS 1
#define PE_LOCK_FIRST 2
#define PE_DEFLECT_EMITTER 4
@@ -2209,7 +2223,7 @@ typedef enum eGPencil_Placement_Flags {
#define PE_FADE_TIME 128
#define PE_AUTO_VELOCITY 256
-/* toolsetting->particle brushtype */
+/* ParticleEditSettings.brushtype */
#define PE_BRUSH_NONE -1
#define PE_BRUSH_COMB 0
#define PE_BRUSH_CUT 1
@@ -2219,18 +2233,15 @@ typedef enum eGPencil_Placement_Flags {
#define PE_BRUSH_SMOOTH 5
#define PE_BRUSH_WEIGHT 6
-/* this must equal ParticleEditSettings.brush array size */
-#define PE_TOT_BRUSH 6
-
-/* ParticleBrushData->flag */
+/* ParticleBrushData.flag */
#define PE_BRUSH_DATA_PUFF_VOLUME 1
-/* tooksettings->particle edittype */
+/* ParticleBrushData.edittype */
#define PE_TYPE_PARTICLES 0
#define PE_TYPE_SOFTBODY 1
#define PE_TYPE_CLOTH 2
-/* toolsettings->skgen_options */
+/* ToolSettings.skgen_options */
#define SKGEN_FILTER_INTERNAL (1 << 0)
#define SKGEN_FILTER_EXTERNAL (1 << 1)
#define SKGEN_SYMMETRY (1 << 2)
@@ -2252,40 +2263,40 @@ typedef enum eGPencil_Placement_Flags {
#define SKGEN_SUB_CORRELATION 2
#define SKGEN_SUB_TOTAL 3
-/* toolsettings->skgen_postpro */
+/* ToolSettings.skgen_postpro */
#define SKGEN_SMOOTH 0
#define SKGEN_AVERAGE 1
#define SKGEN_SHARPEN 2
-/* toolsettings->bone_sketching */
+/* ToolSettings.bone_sketching */
#define BONE_SKETCHING 1
#define BONE_SKETCHING_QUICK 2
#define BONE_SKETCHING_ADJUST 4
-/* toolsettings->bone_sketching_convert */
+/* ToolSettings.bone_sketching_convert */
#define SK_CONVERT_CUT_FIXED 0
#define SK_CONVERT_CUT_LENGTH 1
#define SK_CONVERT_CUT_ADAPTATIVE 2
#define SK_CONVERT_RETARGET 3
-/* toolsettings->skgen_retarget_options */
+/* ToolSettings.skgen_retarget_options */
#define SK_RETARGET_AUTONAME 1
-/* toolsettings->skgen_retarget_roll */
+/* ToolSettings.skgen_retarget_roll */
#define SK_RETARGET_ROLL_NONE 0
#define SK_RETARGET_ROLL_VIEW 1
#define SK_RETARGET_ROLL_JOINT 2
-/* physics_settings->flag */
+/* PhysicsSettings.flag */
#define PHYS_GLOBAL_GRAVITY 1
/* UnitSettings */
-/* UnitSettings->system */
+/* UnitSettings.system */
#define USER_UNIT_NONE 0
#define USER_UNIT_METRIC 1
#define USER_UNIT_IMPERIAL 2
-/* UnitSettings->flag */
+/* UnitSettings.flag */
#define USER_UNIT_OPT_SPLIT 1
#define USER_UNIT_ROT_RADIANS 2
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 97792dbf0ef..fff3ec10292 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -45,6 +45,8 @@ struct PanelType;
struct Scene;
struct uiLayout;
struct wmTimer;
+struct wmTooltipState;
+
typedef struct bScreen {
ID id;
@@ -78,6 +80,8 @@ typedef struct bScreen {
struct wmTimer *animtimer; /* if set, screen has timer handler added in window */
void *context; /* context callback */
+ struct wmTooltipState *tool_tip; /* runtime */
+
PreviewImage *preview;
} bScreen;
@@ -294,15 +298,15 @@ typedef struct ARegion {
/* area->flag */
enum {
HEADER_NO_PULLDOWN = (1 << 0),
- AREA_FLAG_DRAWJOINTO = (1 << 1),
- AREA_FLAG_DRAWJOINFROM = (1 << 2),
+// AREA_FLAG_DEPRECATED_1 = (1 << 1),
+// AREA_FLAG_DEPRECATED_2 = (1 << 2),
#ifdef DNA_DEPRECATED_ALLOW
AREA_TEMP_INFO = (1 << 3), /* versioned to make slot reusable */
#endif
/* update size of regions within the area */
AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3),
- AREA_FLAG_DRAWSPLIT_H = (1 << 4),
- AREA_FLAG_DRAWSPLIT_V = (1 << 5),
+// AREA_FLAG_DEPRECATED_4 = (1 << 4),
+// AREA_FLAG_DEPRECATED_5 = (1 << 5),
/* used to check if we should switch back to prevspace (of a different type) */
AREA_FLAG_TEMP_TYPE = (1 << 6),
/* for temporary fullscreens (file browser, image editor render) that are opened above user set fullscreens */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 27e108b82ab..40beeccf7b6 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -266,6 +266,9 @@ typedef struct SpaceOops {
struct TreeStoreElem search_tse;
short flag, outlinevis, storeflag, search_flags;
+ int filter;
+ char filter_state;
+ char pad[3];
/* pointers to treestore elements, grouped by (id, type, nr) in hashtable for faster searching */
void *treehash;
@@ -281,24 +284,68 @@ typedef enum eSpaceOutliner_Flag {
SO_SKIP_SORT_ALPHA = (1 << 4),
} eSpaceOutliner_Flag;
+/* SpaceOops->filter */
+typedef enum eSpaceOutliner_Filter {
+ SO_FILTER_SEARCH = (1 << 0),
+ SO_FILTER_ENABLE = (1 << 1),
+ SO_FILTER_NO_OBJECT = (1 << 2),
+ SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
+ SO_FILTER_NO_CHILDREN = (1 << 4),
+
+ SO_FILTER_OB_TYPE = (1 << 5),
+ SO_FILTER_NO_OB_MESH = (1 << 6),
+ SO_FILTER_NO_OB_ARMATURE = (1 << 7),
+ SO_FILTER_NO_OB_EMPTY = (1 << 8),
+ SO_FILTER_NO_OB_LAMP = (1 << 9),
+ SO_FILTER_NO_OB_CAMERA = (1 << 10),
+ SO_FILTER_NO_OB_OTHERS = (1 << 11),
+
+ SO_FILTER_OB_STATE = (1 << 12),
+ SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_SELECTED= (1 << 14), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */
+ SO_FILTER_NO_COLLECTION = (1 << 16),
+} eSpaceOutliner_Filter;
+
+#define SO_FILTER_NO_OB_ALL (SO_FILTER_NO_OB_MESH | \
+ SO_FILTER_NO_OB_ARMATURE | \
+ SO_FILTER_NO_OB_EMPTY | \
+ SO_FILTER_NO_OB_LAMP | \
+ SO_FILTER_NO_OB_CAMERA | \
+ SO_FILTER_NO_OB_OTHERS)
+
+#define SO_FILTER_ANY (SO_FILTER_NO_OBJECT | \
+ SO_FILTER_NO_OB_CONTENT | \
+ SO_FILTER_NO_CHILDREN | \
+ SO_FILTER_OB_TYPE | \
+ SO_FILTER_OB_STATE | \
+ SO_FILTER_NO_COLLECTION)
+
+/* SpaceOops->filter_state */
+typedef enum eSpaceOutliner_StateFilter {
+ SO_FILTER_OB_VISIBLE = 0,
+ SO_FILTER_OB_SELECTED = 1,
+ SO_FILTER_OB_ACTIVE = 2,
+} eSpaceOutliner_StateFilter;
+
/* SpaceOops->outlinevis */
typedef enum eSpaceOutliner_Mode {
- SO_ALL_SCENES = 0,
- SO_CUR_SCENE = 1,
- SO_VISIBLE = 2,
- SO_SELECTED = 3,
- SO_ACTIVE = 4,
- SO_SAME_TYPE = 5,
+ SO_SCENES = 0,
+ /* SO_CUR_SCENE = 1, */ /* deprecated! */
+ /* SO_VISIBLE = 2, */ /* deprecated! */
+ /* SO_SELECTED = 3, */ /* deprecated! */
+ /* SO_ACTIVE = 4, */ /* deprecated! */
+ /* SO_SAME_TYPE = 5, */ /* deprecated! */
SO_GROUPS = 6,
SO_LIBRARIES = 7,
/* SO_VERSE_SESSION = 8, */ /* deprecated! */
/* SO_VERSE_MS = 9, */ /* deprecated! */
SO_SEQUENCE = 10,
SO_DATABLOCKS = 11,
- SO_USERDEF = 12,
+ /* SO_USERDEF = 12, */ /* deprecated! */
/* SO_KEYMAP = 13, */ /* deprecated! */
SO_ID_ORPHANS = 14,
- SO_ACT_LAYER = 15,
+ SO_VIEW_LAYER = 15,
SO_COLLECTIONS = 16,
} eSpaceOutliner_Mode;
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index c7969cd30e7..0a9b8c320b5 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -51,6 +51,7 @@ typedef struct Text {
ID id;
char *name;
+ void *compiled;
int flags, nlines;
@@ -59,10 +60,10 @@ typedef struct Text {
int curc, selc;
char *undo_buf;
+ void *pad;
int undo_pos, undo_len;
-
+
double mtime;
- void *compiled;
} Text;
#define TXT_TABSIZE 4
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 81f605b093a..38a1c3ae01c 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -472,7 +472,10 @@ typedef struct UserDef {
short wheellinescroll;
int uiflag; /* eUserpref_UI_Flag */
int uiflag2; /* eUserpref_UI_Flag2 */
- int language;
+ /* Experimental flag for app-templates to make changes to behavior
+ * which are outside the scope of typical preferences. */
+ short app_flag;
+ short language;
short userpref, viewzoom;
int mixbufsize;
@@ -503,13 +506,15 @@ typedef struct UserDef {
char keyconfigstr[64];
short undosteps;
- short undomemory;
+ short pad1;
+ int undomemory;
+ int pad3;
short gp_manhattendist, gp_euclideandist, gp_eraser;
short gp_settings; /* eGP_UserdefSettings */
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
short manipulator_flag, manipulator_size;
- int pad3;
+ int pad6;
short textimeout, texcollectrate;
short wmdrawmethod; /* eWM_DrawMethod */
short dragthreshold;
@@ -678,15 +683,17 @@ typedef enum eUserpref_UI_Flag {
USER_DRAWVIEWINFO = (1 << 4),
USER_PLAINMENUS = (1 << 5),
USER_LOCK_CURSOR_ADJUST = (1 << 6),
- USER_UIFLAG_DEPRECATED_7 = (1 << 7), /* cleared */
+ /* Avoid accidentally adjusting the layout
+ * (exact behavior may change based on whats considered reasonable to lock down). */
+ USER_UIFLAG_DEPRECATED_7 = (1 << 7),
USER_ALLWINCODECS = (1 << 8),
USER_MENUOPENAUTO = (1 << 9),
- USER_ZBUF_CURSOR = (1 << 10),
+ USER_DEPTH_CURSOR = (1 << 10),
USER_AUTOPERSP = (1 << 11),
USER_LOCKAROUND = (1 << 12),
USER_GLOBALUNDO = (1 << 13),
USER_ORBIT_SELECTION = (1 << 14),
- USER_ZBUF_ORBIT = (1 << 15),
+ USER_DEPTH_NAVIGATE = (1 << 15),
USER_HIDE_DOT = (1 << 16),
USER_SHOW_ROTVIEWICON = (1 << 17),
USER_SHOW_VIEWPORTNAME = (1 << 18),
@@ -711,7 +718,13 @@ typedef enum eUserpref_UI_Flag2 {
USER_REGION_OVERLAP = (1 << 1),
USER_TRACKPAD_NATURAL = (1 << 2),
} eUserpref_UI_Flag2;
-
+
+/* UserDef.app_flag */
+typedef enum eUserpref_APP_Flag {
+ USER_APP_LOCK_UI_LAYOUT = (1 << 0),
+ USER_APP_VIEW3D_HIDE_CURSOR = (1 << 1),
+} eUserpref_APP_Flag;
+
/* Auto-Keying mode.
* UserDef.autokey_mode */
typedef enum eAutokey_Mode {
@@ -818,8 +831,9 @@ typedef enum eGP_UserdefSettings {
} eGP_UserdefSettings;
enum {
- USER_MANIPULATOR_DRAW = (1 << 0),
- USER_MANIPULATOR_SHADED = (1 << 1),
+ USER_MANIPULATOR_DRAW = (1 << 0),
+ USER_MANIPULATOR_DRAW_NAVIGATE = (1 << 1),
+ USER_MANIPULATOR_SHADED = (1 << 8),
};
/* Color Picker Types.
@@ -833,7 +847,7 @@ typedef enum eColorPicker_Types {
} eColorPicker_Types;
/* timecode display styles
- * UserDef.timecode_style */
+ * UserDef.timecode_style */
typedef enum eTimecodeStyles {
/* as little info as is necessary to show relevant info
* with '+' to denote the frames
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 3792873db31..4332959bd9a 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -231,6 +231,9 @@ typedef struct wmWindow {
ListBase global_areas;
struct Stereo3dFormat *stereo3d_format; /* properties for stereoscopic displays */
+
+ /* custom drawing callbacks */
+ ListBase drawcalls;
} wmWindow;
#ifdef ime_data
@@ -410,13 +413,15 @@ enum {
/* low level flag so exec() operators can tell if they were invoked, use with care.
* typically this shouldn't make any difference, but it rare cases its needed (see smooth-view) */
OP_IS_INVOKE = (1 << 0),
+ /* So we can detect if an operators exec() call is activated from an interactive repeat. */
+ OP_IS_REPEAT = (1 << 1),
/* When the cursor is grabbed */
- OP_IS_MODAL_GRAB_CURSOR = (1 << 1),
+ OP_IS_MODAL_GRAB_CURSOR = (1 << 2),
/* allow modal operators to have the region under the cursor for their context
* (the regiontype is maintained to prevent errors) */
- OP_IS_MODAL_CURSOR_REGION = (1 << 2),
+ OP_IS_MODAL_CURSOR_REGION = (1 << 3),
};
#endif /* __DNA_WINDOWMANAGER_TYPES_H__ */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index ac932a8daaf..199bb75d099 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -173,7 +173,9 @@ void DNA_sdna_free(SDNA *sdna)
MEM_freeN(sdna->structs);
#ifdef WITH_DNA_GHASH
- BLI_ghash_free(sdna->structs_map, NULL, NULL);
+ if (sdna->structs_map) {
+ BLI_ghash_free(sdna->structs_map, NULL, NULL);
+ }
#endif
MEM_freeN(sdna);
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index a99541385d0..816a472559f 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -944,6 +944,7 @@ float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, i
void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value);
char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value);
+void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len);
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_string_get_default(PointerRNA *ptr, PropertyRNA *prop, char *value);
char *RNA_property_string_get_default_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen);
@@ -1251,27 +1252,44 @@ typedef enum eRNACompareMode {
RNA_EQ_COMPARE,
} eRNACompareMode;
-bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNACompareMode mode);
-bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNACompareMode mode);
+bool RNA_property_equals(struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, struct PropertyRNA *prop, eRNACompareMode mode);
+bool RNA_struct_equals(struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, eRNACompareMode mode);
/* Override. */
-bool RNA_struct_override_matches(struct PointerRNA *local, struct PointerRNA *reference,
- struct IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden);
+/* flags for RNA_struct_override_matches. */
+typedef enum eRNAOverrideMatch {
+ /* Do not compare properties that are not overridable. */
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0,
+ /* Do not compare properties that are already overridden. */
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1,
+
+ /* Create new property override if needed and possible. */
+ RNA_OVERRIDE_COMPARE_CREATE = 1 << 16,
+ /* Restore property's value(s) to reference ones if needed and possible. */
+ RNA_OVERRIDE_COMPARE_RESTORE = 1 << 17,
+} eRNAOverrideMatch;
+
+typedef enum eRNAOverrideMatchResult {
+ /* Some new property overrides were created to take into account differences between local and reference. */
+ RNA_OVERRIDE_MATCH_RESULT_CREATED = 1 << 0,
+ /* Some properties were reset to reference values. */
+ RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 1,
+} eRNAOverrideMatchResult;
+
+bool RNA_struct_override_matches(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, const char *root_path,
+ struct IDOverrideStatic *override, const eRNAOverrideMatch flags,
+ eRNAOverrideMatchResult *r_report_flags);
bool RNA_struct_override_store(
- struct PointerRNA *local, struct PointerRNA *reference, PointerRNA *storage, struct IDOverrideStatic *override);
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ struct IDOverrideStatic *override);
-void RNA_property_override_apply(
- struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, struct PropertyRNA *prop,
- struct IDOverrideStaticProperty *op);
void RNA_struct_override_apply(
- struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
struct IDOverrideStatic *override);
-bool RNA_struct_auto_override(
- struct PointerRNA *local, struct PointerRNA *reference, struct IDOverrideStatic *override, const char *root_path);
-
struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop);
struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 47aebbc13e7..e0824281656 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -158,7 +158,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 3, 7, 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 3, 9, 11, 13, 14, 15, 30 */
typedef enum PropertyFlag {
/* editable means the property is editable in the user
* interface, properties are editable by default except
@@ -213,6 +213,13 @@ typedef enum PropertyFlag {
* but setting NULL on a mesh object is not possible. So, if its not NULL, setting NULL cant be done! */
PROP_NEVER_UNLINK = (1 << 25),
+ /* Pointers to data that is not owned by the struct.
+ * Typical example: Bone.parent, Bone.child, etc., and nearly all ID pointers.
+ * This is crucial information for processes that walk the whole data of an ID e.g. (like static override).
+ * Note that all ID pointers are enforced to this by default, this probably will need to be rechecked
+ * (see ugly infamous NodeTrees of mat/tex/scene/etc.). */
+ PROP_PTR_NO_OWNERSHIP = (1 << 7),
+
/* flag contains multiple enums.
* note: not to be confused with prop->enumbitflags
* this exposes the flag as multiple options in python and the UI.
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 19f66109665..9745ca39872 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -2995,6 +2995,28 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
}
break;
}
+ case PROP_POINTER:
+ {
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
+
+ /* XXX This systematically enforces that flag on ID pointers... we'll probably have to revisit. :/ */
+ StructRNA *type = rna_find_struct((const char *)pprop->type);
+ if (type && (type->flag & STRUCT_ID)) {
+ prop->flag |= PROP_PTR_NO_OWNERSHIP;
+ }
+ break;
+ }
+ case PROP_COLLECTION:
+ {
+ CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
+
+ /* XXX This systematically enforces that flag on ID pointers... we'll probably have to revisit. :/ */
+ StructRNA *type = rna_find_struct((const char *)cprop->item_type);
+ if (type && (type->flag & STRUCT_ID)) {
+ prop->flag |= PROP_PTR_NO_OWNERSHIP;
+ }
+ break;
+ }
default:
break;
}
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 44df8916796..549c1a8b30d 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -318,7 +318,7 @@ static ID *rna_ID_override_create(ID *id, Main *bmain)
return NULL;
}
- return BKE_override_static_create_from(bmain, id);
+ return BKE_override_static_create_from_id(bmain, id);
}
static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
@@ -772,6 +772,27 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
}
+static int rna_ID_is_updated_get(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+ /* TODO(sergey): Do we need to limit some of flags here? */
+ return ((id->recalc & ID_RECALC_ALL) != 0);
+}
+
+static int rna_ID_is_updated_data_get(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+ if (GS(id->name) != ID_OB) {
+ return 0;
+ }
+ Object *object = (Object *)id;
+ ID *data = object->data;
+ if (data == NULL) {
+ return 0;
+ }
+ return ((data->recalc & ID_RECALC_ALL) != 0);
+}
+
static PointerRNA rna_ID_override_reference_get(PointerRNA *ptr)
{
ID *id = (ID *)ptr->data;
@@ -1023,13 +1044,13 @@ static void rna_def_ID(BlenderRNA *brna)
"(initial state is undefined)");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_ID_is_updated_get", NULL);
RNA_def_property_ui_text(prop, "Is Updated", "Data-block is tagged for recalculation");
prop = RNA_def_property(srna, "is_updated_data", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC_DATA);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_ID_is_updated_data_get", NULL);
RNA_def_property_ui_text(prop, "Is Updated Data", "Data-block data is tagged for recalculation");
prop = RNA_def_property(srna, "is_library_indirect", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 345c3d23dbe..b8dbc69f352 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -42,6 +42,10 @@
#include "BLI_ghash.h"
#include "BLI_math.h"
+#ifdef DEBUG_OVERRIDE_TIMEIT
+# include "PIL_time_utildefines.h"
+#endif
+
#include "BLF_api.h"
#include "BLT_translation.h"
@@ -425,7 +429,7 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_double_array
};
-IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
+static void *rna_idproperty_check_ex(PropertyRNA **prop, PointerRNA *ptr, const bool return_rnaprop)
{
/* This is quite a hack, but avoids some complexity in the API. we
* pass IDProperty structs as PropertyRNA pointers to the outside.
@@ -448,7 +452,7 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
return idprop;
}
else
- return NULL;
+ return return_rnaprop ? *prop : NULL;
}
{
@@ -463,6 +467,19 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
}
}
+/* This function only returns an IDProperty,
+ * or NULL (in case IDProp could not be found, or prop is a real RNA property). */
+IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
+{
+ return rna_idproperty_check_ex(prop, ptr, false);
+}
+
+/* This function always return the valid, real data pointer, be it a regular RNA property one, or an IDProperty one. */
+PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
+{
+ return rna_idproperty_check_ex(prop, ptr, true);
+}
+
static PropertyRNA *rna_ensure_property(PropertyRNA *prop)
{
/* the quick version if we don't need the idproperty */
@@ -775,7 +792,7 @@ FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier)
}
return NULL;
- /* funcitonal but slow */
+ /* functional but slow */
#else
PointerRNA tptr;
PropertyRNA *iterprop;
@@ -3026,6 +3043,42 @@ void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *val
}
}
+void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len)
+{
+ StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
+ IDProperty *idprop;
+
+ BLI_assert(RNA_property_type(prop) == PROP_STRING);
+ BLI_assert(RNA_property_subtype(prop) == PROP_BYTESTRING);
+
+ if ((idprop = rna_idproperty_check(&prop, ptr))) {
+ IDP_ResizeArray(idprop, len);
+ memcpy(idprop->data.pointer, value, (size_t)len);
+
+ rna_idproperty_touch(idprop);
+ }
+ else if (sprop->set) {
+ /* XXX, should take length argument (currently not used). */
+ sprop->set(ptr, value); /* set function needs to clamp its self */
+ }
+ else if (sprop->set_ex) {
+ /* XXX, should take length argument (currently not used). */
+ sprop->set_ex(ptr, prop, value); /* set function needs to clamp its self */
+ }
+ else if (prop->flag & PROP_EDITABLE) {
+ IDProperty *group;
+
+ group = RNA_struct_idprops(ptr, 1);
+ if (group) {
+ IDPropertyTemplate val = {0};
+ val.string.str = value;
+ val.string.len = len;
+ val.string.subtype = IDP_STRING_SUB_BYTE;
+ IDP_AddToGroup(group, IDP_New(IDP_STRING, &val, prop->identifier));
+ }
+ }
+}
+
void RNA_property_string_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop, char *value)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -5767,13 +5820,10 @@ char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
{
- if (ptr->type == NULL) {
+ if (ptr->type == NULL || ptr->id.data == NULL) {
return BLI_strdup("None");
}
else if (RNA_struct_is_ID(ptr->type)) {
- if (ptr->id.data == NULL) {
- return BLI_strdup("None");
- }
return RNA_path_full_ID_py(ptr->id.data);
}
else {
@@ -6986,7 +7036,8 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
}
static bool rna_property_override_operation_apply(
- PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
IDOverrideStaticPropertyOperation *opop);
bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
@@ -6995,12 +7046,23 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
return false;
}
+ PropertyRNA *prop_dst = prop;
+ PropertyRNA *prop_src = prop;
+
+ /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */
+ prop_dst = rna_ensure_property_realdata(&prop_dst, ptr);
+ prop_src = rna_ensure_property_realdata(&prop_src, fromptr);
+
+ if (ELEM(NULL, prop_dst, prop_src)) {
+ false;
+ }
+
IDOverrideStaticPropertyOperation opop = {
.operation = IDOVERRIDESTATIC_OP_REPLACE,
.subitem_reference_index = index,
.subitem_local_index = index
};
- return rna_property_override_operation_apply(ptr, fromptr, NULL, prop, &opop);
+ return rna_property_override_operation_apply(ptr, fromptr, NULL, prop_dst, prop_src, NULL, &opop);
}
/* use RNA_warning macro which includes __func__ suffix */
@@ -7026,36 +7088,36 @@ void _RNA_warning(const char *format, ...)
}
static int rna_property_override_diff(
- PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode,
- IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags);
+ PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path,
+ eRNACompareMode mode, IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags);
-bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode)
+bool RNA_property_equals(PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
{
BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
- return (rna_property_override_diff(a, b, prop, mode, NULL, NULL, NULL, 0) != 0);
+ return (rna_property_override_diff(ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0);
}
-bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode)
+bool RNA_struct_equals(PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
{
CollectionPropertyIterator iter;
PropertyRNA *iterprop;
bool equals = true;
- if (a == NULL && b == NULL)
+ if (ptr_a == NULL && ptr_b == NULL)
return true;
- else if (a == NULL || b == NULL)
+ else if (ptr_a == NULL || ptr_b == NULL)
return false;
- else if (a->type != b->type)
+ else if (ptr_a->type != ptr_b->type)
return false;
- iterprop = RNA_struct_iterator_property(a->type);
+ iterprop = RNA_struct_iterator_property(ptr_a->type);
- RNA_property_collection_begin(a, iterprop, &iter);
+ RNA_property_collection_begin(ptr_a, iterprop, &iter);
for (; iter.valid; RNA_property_collection_next(&iter)) {
PropertyRNA *prop = iter.ptr.data;
- if (!RNA_property_equals(a, b, prop, mode)) {
+ if (!RNA_property_equals(ptr_a, ptr_b, prop, mode)) {
equals = false;
break;
}
@@ -7066,84 +7128,133 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode)
}
/* Low-level functions, also used by non-override RNA API like copy or equality check. */
-#include "PIL_time_utildefines.h"
+
+/** Generic RNA property diff function.
+ *
+ * \note about \a prop and \a prop_a/prop_b parameters: the former is exptected to be an 'un-resolved' one,
+ * while the two laters are expected to be fully resolved ones (i.e. to be the IDProps when they should be, etc.).
+ * When \a prop is given, \a prop_a and \a prop_b should always be NULL, and vice-versa.
+ * This is necessary, because we cannot perform 'set/unset' checks on resolved properties
+ * (unset IDProps would merely be NULL then).
+ */
static int rna_property_override_diff(
- PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop_a, eRNACompareMode mode,
- IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
+ PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path,
+ eRNACompareMode mode, IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags)
{
- int len_a, len_b;
-
- PropertyRNA *prop_b = prop_a;
-
- if (prop_a->magic != RNA_MAGIC) {
- /* In case of IDProperty, we have to find the *real* idprop of ptr,
- * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
- /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
- prop_a = (PropertyRNA *)rna_idproperty_find(ptr_a, ((IDProperty *)prop_a)->name);
- prop_b = (PropertyRNA *)rna_idproperty_find(ptr_b, ((IDProperty *)prop_b)->name);
-
- if (ELEM(NULL, prop_a, prop_b)) {
- return 1;
- }
+ if (prop != NULL) {
+ BLI_assert(prop_a == NULL && prop_b == NULL);
+ prop_a = prop;
+ prop_b = prop;
}
- BLI_assert(prop_a->override_diff == prop_b->override_diff && prop_a->override_diff != NULL);
+ if (ELEM(NULL, prop_a, prop_b)) {
+ return (prop_a == prop_b) ? 0 : 1;
+ }
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
/* uninitialized properties are assumed to match anything */
- if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b))
+ if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) {
return 0;
+ }
}
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
/* unset properties never match set properties */
- if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b))
+ if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) {
return 1;
+ }
}
- /* get the length of the array to work with */
- len_a = RNA_property_array_length(ptr_a, prop_a);
- len_b = RNA_property_array_length(ptr_b, prop_b);
+ if (prop != NULL) {
+ /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */
+ prop_a = rna_ensure_property_realdata(&prop_a, ptr_a);
+ prop_b = rna_ensure_property_realdata(&prop_b, ptr_b);
+
+ if (ELEM(NULL, prop_a, prop_b)) {
+ return (prop_a == prop_b) ? 0 : 1;
+ }
+ }
+
+ /* Check if we are working with arrays. */
+ const bool is_array_a = RNA_property_array_check(prop_a);
+ const bool is_array_b = RNA_property_array_check(prop_b);
+
+ if (is_array_a != is_array_b) {
+ /* Should probably never happen actually... */
+ BLI_assert(0);
+ return is_array_a ? 1 : -1;
+ }
+
+ /* Get the length of the array to work with. */
+ const int len_a = RNA_property_array_length(ptr_a, prop_a);
+ const int len_b = RNA_property_array_length(ptr_b, prop_b);
if (len_a != len_b) {
/* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
return len_a > len_b ? 1 : -1;
}
- return prop_a->override_diff(
- ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, mode, override, rna_path, flags, r_override_changed);
+ if (is_array_a && len_a == 0) {
+ /* Empty arrays, will happen in some case with dynamic ones. */
+ return 0;
+ }
+
+ RNAPropOverrideDiff override_diff = NULL;
+ /* Special case for IDProps, we use default callback then. */
+ if (prop_a->magic != RNA_MAGIC) {
+ override_diff = rna_property_override_diff_default;
+ if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) {
+ override_diff = NULL;
+ }
+ }
+ else if (prop_b->magic != RNA_MAGIC) {
+ override_diff = rna_property_override_diff_default;
+ if (prop_a->override_diff != override_diff) {
+ override_diff = NULL;
+ }
+ }
+ else if (prop_a->override_diff == prop_b->override_diff) {
+ override_diff = prop_a->override_diff;
+ }
+
+ if (override_diff == NULL) {
+#ifndef NDEBUG
+ printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
+ rna_path ? rna_path : (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier),
+ prop_a->magic == RNA_MAGIC, prop_b->magic == RNA_MAGIC);
+#endif
+ BLI_assert(0);
+ return 1;
+ }
+
+ bool override_changed = false;
+ int diff_flags = flags;
+ if ((RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC) == 0) {
+ diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
+ }
+ const int diff = override_diff(
+ ptr_a, ptr_b, prop_a, prop_b, len_a, len_b,
+ mode, override, rna_path, diff_flags, &override_changed);
+ if (override_changed && r_report_flags) {
+ *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
+ }
+
+ return diff;
}
/* Modify local data-block to make it ready for override application (only needed for diff operations, where we use
* the local data-block's data as second operand). */
static bool rna_property_override_operation_store(
- PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
IDOverrideStaticProperty *op)
{
int len_local, len_reference, len_storage = 0;
- PropertyRNA *prop_reference = prop_local;
- PropertyRNA *prop_storage = prop_local;
bool changed = false;
- if (!ptr_storage) {
+ if (ptr_storage == NULL) {
return changed;
}
- if (prop_local->magic != RNA_MAGIC) {
- /* In case of IDProperty, we have to find the *real* idprop of ptr,
- * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
- /* XXX TODO this is ugly, we already get correct prop in upcalling code, should just pass them to this func! */
- prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
- prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
- if (ptr_storage) {
- prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
- }
-
- /* its possible the custom-prop doesn't exist on this data-block */
- if (prop_local == NULL) {
- return changed;
- }
- }
-
/* get the length of the array to work with */
len_local = RNA_property_array_length(ptr_local, prop_local);
len_reference = RNA_property_array_length(ptr_reference, prop_reference);
@@ -7178,12 +7289,11 @@ static bool rna_property_override_operation_store(
}
static bool rna_property_override_operation_apply(
- PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
IDOverrideStaticPropertyOperation *opop)
{
int len_local, len_reference, len_storage = 0;
- PropertyRNA *prop_reference = prop_local;
- PropertyRNA *prop_storage = prop_local;
const short override_op = opop->operation;
@@ -7197,25 +7307,41 @@ static bool rna_property_override_operation_apply(
return false;
}
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) {
+ /* We cannot apply 'diff' override operations without some refference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
+
+ RNAPropOverrideApply override_apply = NULL;
+ /* Special case for IDProps, we use default callback then. */
if (prop_local->magic != RNA_MAGIC) {
- /* In case of IDProperty, we have to find the *real* idprop of ptr,
- * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
- /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
- prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
- prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
- if (ptr_storage) {
- prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
+ override_apply = rna_property_override_apply_default;
+ if (prop_reference->magic == RNA_MAGIC && prop_reference->override_apply != override_apply) {
+ override_apply = NULL;
}
-
- /* its possible the custom-prop doesn't exist on this data-block */
- if (prop_local == NULL) {
- return false;
+ }
+ else if (prop_reference->magic != RNA_MAGIC) {
+ override_apply = rna_property_override_apply_default;
+ if (prop_local->override_apply != override_apply) {
+ override_apply = NULL;
}
}
+ else if (prop_local->override_apply == prop_reference->override_apply) {
+ override_apply = prop_local->override_apply;
+ }
- if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) {
- /* We cannot apply 'diff' override operations without some refference storage.
- * This should typically only happen at read time of .blend file... */
+ if (ptr_storage && prop_storage->magic == RNA_MAGIC && prop_storage->override_apply != override_apply) {
+ override_apply = NULL;
+ }
+
+ if (override_apply == NULL) {
+#ifndef NDEBUG
+ printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n",
+ prop_local->magic != RNA_MAGIC ? ((IDProperty *)prop_local)->name : prop_local->identifier,
+ prop_local->magic == RNA_MAGIC, prop_reference->magic == RNA_MAGIC);
+#endif
+ BLI_assert(0);
return false;
}
@@ -7231,71 +7357,167 @@ static bool rna_property_override_operation_apply(
return false;
}
- BLI_assert(prop_local->override_apply == prop_reference->override_apply &&
- (!ptr_storage || prop_local->override_apply == prop_storage->override_apply) &&
- prop_local->override_apply != NULL);
-
/* get and set the default values as appropriate for the various types */
- return prop_local->override_apply(
+ return override_apply(
ptr_local, ptr_reference, ptr_storage,
prop_local, prop_reference, prop_storage,
len_local, len_reference, len_storage,
opop);
}
-
/**
* Check whether reference and local overriden data match (are the same),
- * with respect to given restrictive sets of properties. */
+ * with respect to given restrictive sets of properties.
+ * If requested, will generate needed new property overrides, and/or restore values from reference.
+ *
+ * \param r_report_flags If given, will be set with flags matching actions taken by the function on \a ptr_local.
+ *
+ * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
+ */
bool RNA_struct_override_matches(
- PointerRNA *local, PointerRNA *reference,
- IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden)
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path,
+ IDOverrideStatic *override, const eRNAOverrideMatch flags,
+ eRNAOverrideMatchResult *r_report_flags)
{
CollectionPropertyIterator iter;
PropertyRNA *iterprop;
- bool equals = true;
+ bool matching = true;
- BLI_assert(local->type == reference->type);
+ BLI_assert(ptr_local->type == ptr_reference->type);
+ BLI_assert(ptr_local->id.data && ptr_reference->id.data);
- iterprop = RNA_struct_iterator_property(local->type);
+ const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
+ const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
+ const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
+ const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
- RNA_property_collection_begin(local, iterprop, &iter);
- for (; iter.valid; RNA_property_collection_next(&iter)) {
- PropertyRNA *prop = iter.ptr.data;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ static float _sum_time = 0.0f;
+ static float _num_time = 0.0f;
+ double _timeit_time;
+ if (!root_path) {
+ _timeit_time = PIL_check_seconds_timer();
+ }
+#endif
+
+ iterprop = RNA_struct_iterator_property(ptr_local->type);
+
+ for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop_local = iter.ptr.data;
+ PropertyRNA *prop_reference = iter.ptr.data;
- if (ignore_non_overridable && !(prop->flag & PROP_OVERRIDABLE_STATIC)) {
+ /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */
+ prop_local = rna_ensure_property_realdata(&prop_local, ptr_local);
+ prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference);
+
+ if (ELEM(NULL, prop_local, prop_reference)) {
continue;
}
- if (ignore_overridden) {
- /* XXX TODO this will have to be refined to handle collections insertions, and array items */
- char *rna_path = RNA_path_from_ID_to_property(local, prop);
- if (BKE_override_static_property_find(override, rna_path) != NULL) {
- MEM_SAFE_FREE(rna_path);
- continue;
- }
- MEM_SAFE_FREE(rna_path);
+ if (ignore_non_overridable && !(prop_local->flag & PROP_OVERRIDABLE_STATIC)) {
+ continue;
}
- int flag = 0;
- if (ignore_non_overridable) {
- flag |= RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE;
+ if (RNA_property_animated(ptr_local, prop_local)) {
+ /* We cannot do anything here really, animation is some kind of dynamic overrides that has
+ * precedence over static one... */
+ continue;
}
- if (ignore_overridden) {
- flag |= RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN;
+
+ /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+ char *rna_path;
+ if (root_path) {
+ /* Inlined building, much much more efficient. */
+ if (prop_local->magic == RNA_MAGIC) {
+ rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop_local));
+ }
+ else {
+ rna_path = BLI_sprintfN("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local));
+ }
}
- if (rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, NULL, NULL, flag) != 0) {
- equals = false;
- break;
+ else {
+ rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local);
}
+ if (rna_path == NULL) {
+ continue;
+ }
+
+ if (ignore_overridden && BKE_override_static_property_find(override, rna_path) != NULL) {
+ MEM_SAFE_FREE(rna_path);
+ continue;
+ }
+
+ eRNAOverrideMatchResult report_flags = 0;
+ const int diff = rna_property_override_diff(
+ ptr_local, ptr_reference, NULL, prop_local, prop_reference, rna_path,
+ RNA_EQ_STRICT, override, flags, &report_flags);
+
+ matching = matching && diff == 0;
+ if (r_report_flags) {
+ *r_report_flags |= report_flags;
+ }
+
+ if (diff != 0) {
+ /* XXX TODO: refine this for per-item overriding of arrays... */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+ IDOverrideStaticPropertyOperation *opop = op ? op->operations.first : NULL;
+
+ if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
+ /* We are allowed to restore to reference's values. */
+ if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDESTATIC_OP_NOOP) {
+ /* We should restore that property to its reference value */
+ if (RNA_property_editable(ptr_local, prop_local)) {
+ IDOverrideStaticPropertyOperation opop_tmp = {
+ .operation = IDOVERRIDESTATIC_OP_REPLACE,
+ .subitem_reference_index = -1,
+ .subitem_local_index = -1
+ };
+ rna_property_override_operation_apply(ptr_local, ptr_reference, NULL,
+ prop_local, prop_reference, NULL, &opop_tmp);
+ if (r_report_flags) {
+ *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
+ }
+ }
+ else {
+ /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
+ /* BLI_assert(!"We have differences between reference and overriding data on non-editable property."); */
+ matching = false;
+ }
+ }
+ }
+ else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(NULL, op, opop)) {
+ /* This property is not overridden, and differs from reference, so we have no match. */
+ matching = false;
+ if (!(do_create || do_restore)) {
+ /* Since we have no 'changing' action allowed, we can break here. */
+ MEM_SAFE_FREE(rna_path);
+ break;
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(rna_path);
}
RNA_property_collection_end(&iter);
- return equals;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ if (!root_path) {
+ const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time);
+ _sum_time += _delta_time;
+ _num_time++;
+ printf("ID: %s\n", ((ID *)ptr_local->id.data)->name);
+ printf("time end (%s): %.6f\n", __func__, _delta_time);
+ printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time);
+ }
+#endif
+
+ return matching;
}
+
/** Store needed second operands into \a storage data-block for differential override operations. */
-bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, PointerRNA *storage, IDOverrideStatic *override)
+bool RNA_struct_override_store(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideStatic *override)
{
bool changed = false;
@@ -7304,21 +7526,23 @@ bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, Pointer
#endif
for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
/* Simplified for now! */
- PointerRNA src_data, dst_data;
- PropertyRNA *src_prop, *dst_prop;
+ PointerRNA data_reference, data_local;
+ PropertyRNA *prop_reference, *prop_local;
- if (RNA_path_resolve_property(reference, op->rna_path, &src_data, &src_prop) &&
- RNA_path_resolve_property(local, op->rna_path, &dst_data, &dst_prop))
+ if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
+ RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference))
{
- PointerRNA storage_data;
- PropertyRNA *storage_prop = NULL;
+ PointerRNA data_storage;
+ PropertyRNA *prop_storage = NULL;
/* It is totally OK if this does not success, only a subset of override operations actually need storage. */
- if (storage && (storage->id.data != NULL)) {
- RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
+ if (ptr_storage && (ptr_storage->id.data != NULL)) {
+ RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
}
- if (rna_property_override_operation_store(&dst_data, &src_data, &storage_data, src_prop, op)) {
+ if (rna_property_override_operation_store(&data_local, &data_reference, &data_storage,
+ prop_reference, prop_local, prop_storage, op))
+ {
changed = true;
}
}
@@ -7330,46 +7554,50 @@ bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, Pointer
return changed;
}
-/** Apply given \a op override property operations on \a dst, using \a src as source. */
-void RNA_property_override_apply(
- PointerRNA *dst, PointerRNA *src, PointerRNA *storage, PropertyRNA *prop, IDOverrideStaticProperty *op)
+static void rna_property_override_apply_ex(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideStaticProperty *op)
{
for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
- if (!rna_property_override_operation_apply(dst, src, storage, prop, opop)) {
+ if (!rna_property_override_operation_apply(ptr_local, ptr_reference, ptr_storage,
+ prop_local, prop_reference, prop_storage, opop))
+ {
BLI_assert(0);
}
}
}
/** Apply given \a override operations on \a dst, using \a src as source. */
-void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *storage, IDOverrideStatic *override)
+void RNA_struct_override_apply(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideStatic *override)
{
#ifdef DEBUG_OVERRIDE_TIMEIT
TIMEIT_START_AVERAGED(RNA_struct_override_apply);
#endif
for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
/* Simplified for now! */
- PointerRNA src_data, dst_data;
- PropertyRNA *src_prop, *dst_prop;
+ PointerRNA data_reference, data_local;
+ PropertyRNA *prop_reference, *prop_local;
- if (RNA_path_resolve_property(src, op->rna_path, &src_data, &src_prop) &&
- RNA_path_resolve_property(dst, op->rna_path, &dst_data, &dst_prop))
+ if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
+ RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference))
{
- PointerRNA storage_data;
- PropertyRNA *storage_prop = NULL;
+ PointerRNA data_storage;
+ PropertyRNA *prop_storage = NULL;
/* It is totally OK if this does not success, only a subset of override operations actually need storage. */
- if (storage && (storage->id.data != NULL)) {
- RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
+ if (ptr_storage && (ptr_storage->id.data != NULL)) {
+ RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
}
- /* Note that src and dst props are the same, unless they are IDProperties... */
- RNA_property_override_apply(&dst_data, &src_data, storage_prop ? &storage_data : NULL, src_prop, op);
+ rna_property_override_apply_ex(
+ &data_local, &data_reference, prop_storage ? &data_storage : NULL,
+ prop_local, prop_reference, prop_storage, op);
}
#ifndef NDEBUG
else {
printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n",
- ((ID *)src->id.data)->name, op->rna_path);
+ ((ID *)ptr_reference->id.data)->name, op->rna_path);
}
#endif
}
@@ -7378,75 +7606,6 @@ void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *sto
#endif
}
-/** Automatically define override rules by comparing \a local and \a reference RNA structs. */
-bool RNA_struct_auto_override(PointerRNA *local, PointerRNA *reference, IDOverrideStatic *override, const char *root_path)
-{
- CollectionPropertyIterator iter;
- PropertyRNA *iterprop;
- bool changed = false;
-
- BLI_assert(local->type == reference->type);
- BLI_assert(local->id.data && reference->id.data);
-
- if ((((ID *)local->id.data)->flag & LIB_OVERRIDE_STATIC_AUTO) == 0) {
- return changed;
- }
-
-#ifdef DEBUG_OVERRIDE_TIMEIT
- static float _sum_time = 0.0f;
- static float _num_time = 0.0f;
- double _timeit_time;
- if (!root_path) {
- _timeit_time = PIL_check_seconds_timer();
- }
-#endif
-
- iterprop = RNA_struct_iterator_property(local->type);
-
- for (RNA_property_collection_begin(local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) {
- PropertyRNA *prop = iter.ptr.data;
-
- if (!(prop->flag & PROP_OVERRIDABLE_STATIC)) {
- continue;
- }
- if (RNA_property_animated(local, prop)) {
- continue;
- }
-
- /* XXX TODO this will have to be refined to handle collections insertions, and array items */
- char *rna_path;
- if (root_path) {
- /* Inlined building, much much more efficient. */
- rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop));
- }
- else {
- rna_path = RNA_path_from_ID_to_property(local, prop);
- }
- if (rna_path == NULL) {
- continue;
- }
-
- rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, rna_path, &changed,
- RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
-
- MEM_SAFE_FREE(rna_path);
- }
- RNA_property_collection_end(&iter);
-
-#ifdef DEBUG_OVERRIDE_TIMEIT
- if (!root_path) {
- const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time);
- _sum_time += _delta_time;
- _num_time++;
- printf("ID: %s\n", ((ID *)local->id.data)->name);
- printf("time end (%s): %.6f\n", __func__, _delta_time);
- printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time);
- }
-#endif
-
- return changed;
-}
-
IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
{
ID *id = ptr->id.data;
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 1ec0fd92a67..bbcb583ab39 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -726,6 +726,7 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Bone");
RNA_def_property_pointer_sdna(prop, NULL, "parent");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_ui_text(prop, "Parent", "Parent bone (in same Armature)");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
@@ -733,6 +734,7 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "childbase", NULL);
RNA_def_property_struct_type(prop, "Bone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 3861f4d19b9..5336a63fb76 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -128,7 +128,7 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = {
#include "RNA_access.h"
-#include "BKE_texture.h"
+#include "BKE_colorband.h"
#include "BKE_brush.h"
#include "BKE_icons.h"
#include "BKE_paint.h"
@@ -474,7 +474,7 @@ static void rna_Brush_use_gradient_set(PointerRNA *ptr, int value)
else br->flag &= ~BRUSH_USE_GRADIENT;
if ((br->flag & BRUSH_USE_GRADIENT) && br->gradient == NULL)
- br->gradient = add_colorband(true);
+ br->gradient = BKE_colorband_add(true);
}
static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value)
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index ad2586635c9..d9b7a58de04 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -52,12 +52,12 @@
#include "MEM_guardedalloc.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_sequencer.h"
-#include "BKE_texture.h"
#include "BKE_linestyle.h"
#include "DEG_depsgraph.h"
@@ -362,12 +362,12 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
static void rna_ColorRamp_eval(struct ColorBand *coba, float position, float color[4])
{
- do_colorband(coba, position, color);
+ BKE_colorband_evaluate(coba, position, color);
}
static CBData *rna_ColorRampElement_new(struct ColorBand *coba, ReportList *reports, float position)
{
- CBData *element = colorband_element_add(coba, position);
+ CBData *element = BKE_colorband_element_add(coba, position);
if (element == NULL)
BKE_reportf(reports, RPT_ERROR, "Unable to add element to colorband (limit %d)", MAXCOLORBAND);
@@ -379,7 +379,7 @@ static void rna_ColorRampElement_remove(struct ColorBand *coba, ReportList *repo
{
CBData *element = element_ptr->data;
int index = (int)(element - coba->data);
- if (colorband_element_remove(coba, index) == false) {
+ if (BKE_colorband_element_remove(coba, index) == false) {
BKE_report(reports, RPT_ERROR, "Element not found in element collection or last element");
return;
}
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 3df114282fd..bcd805b0f3a 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -132,7 +132,11 @@ static PointerRNA rna_Context_scene_get(PointerRNA *ptr)
static PointerRNA rna_Context_view_layer_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
- return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, CTX_data_view_layer(C));
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA scene_ptr;
+
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+ return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, CTX_data_view_layer(C));
}
static PointerRNA rna_Context_view_render_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 7d520ec6abd..e6e1c714008 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -61,7 +61,7 @@ static PointerRNA rna_DepsgraphIter_object_get(PointerRNA *ptr)
static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
Object *instance_object = NULL;
if (deg_iter->dupli_object_current != NULL) {
instance_object = deg_iter->dupli_object_current->ob;
@@ -72,7 +72,7 @@ static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr)
static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
Object *dupli_parent = NULL;
if (deg_iter->dupli_object_current != NULL) {
dupli_parent = deg_iter->dupli_parent;
@@ -83,7 +83,7 @@ static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr)
static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent_id)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id,
sizeof(deg_iter->dupli_object_current->persistent_id));
}
@@ -91,7 +91,7 @@ static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent
static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
memcpy(orco, deg_iter->dupli_object_current->orco,
sizeof(deg_iter->dupli_object_current->orco));
}
@@ -99,14 +99,14 @@ static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco)
static unsigned int rna_DepsgraphIter_random_id_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
return deg_iter->dupli_object_current->random_id;
}
static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
memcpy(uv, deg_iter->dupli_object_current->uv,
sizeof(deg_iter->dupli_object_current->uv));
}
@@ -114,31 +114,44 @@ static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv)
static int rna_DepsgraphIter_is_instance_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
return (deg_iter->dupli_object_current != NULL);
}
/* **************** Depsgraph **************** */
-static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename)
+static void rna_Depsgraph_debug_relations_graphviz(Depsgraph *depsgraph,
+ const char *filename)
{
FILE *f = fopen(filename, "w");
if (f == NULL) {
return;
}
- DEG_debug_graphviz(graph, f, "Depsgraph", false);
+ DEG_debug_relations_graphviz(depsgraph, f, "Depsgraph");
fclose(f);
}
-static void rna_Depsgraph_debug_tag_update(Depsgraph *graph)
+static void rna_Depsgraph_debug_stats_gnuplot(Depsgraph *depsgraph,
+ const char *filename,
+ const char *output_filename)
{
- DEG_graph_tag_relations_update(graph);
+ FILE *f = fopen(filename, "w");
+ if (f == NULL) {
+ return;
+ }
+ DEG_debug_stats_gnuplot(depsgraph, f, "Timing Statistics", output_filename);
+ fclose(f);
}
-static void rna_Depsgraph_debug_stats(Depsgraph *graph, char *result)
+static void rna_Depsgraph_debug_tag_update(Depsgraph *depsgraph)
+{
+ DEG_graph_tag_relations_update(depsgraph);
+}
+
+static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result)
{
size_t outer, ops, rels;
- DEG_stats_simple(graph, &outer, &ops, &rels);
+ DEG_stats_simple(depsgraph, &outer, &ops, &rels);
BLI_snprintf(result, STATS_MAX_SIZE,
"Approx %lu Operations, %lu Relations, %lu Outer Nodes",
ops, rels, outer);
@@ -149,10 +162,13 @@ static void rna_Depsgraph_debug_stats(Depsgraph *graph, char *result)
static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
- DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__);
+ DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__);
data->graph = (Depsgraph *)ptr->data;
- data->flag = DEG_ITER_OBJECT_FLAG_SET;
+ data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
+ data->mode = DEG_ITER_OBJECT_MODE_RENDER;
((BLI_Iterator *)iter->internal.custom)->valid = true;
DEG_iterator_objects_begin(iter->internal.custom, data);
@@ -186,10 +202,14 @@ static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter)
static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
- DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__);
+ DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__);
data->graph = (Depsgraph *)ptr->data;
- data->flag = DEG_ITER_OBJECT_FLAG_ALL;
+ data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI;
+ data->mode = DEG_ITER_OBJECT_MODE_RENDER;
((BLI_Iterator *)iter->internal.custom)->valid = true;
DEG_iterator_objects_begin(iter->internal.custom, data);
@@ -292,10 +312,18 @@ static void rna_def_depsgraph(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Depsgraph", NULL);
RNA_def_struct_ui_text(srna, "Dependency Graph", "");
- func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz");
+ func = RNA_def_function(srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz");
+ parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
+ "File in which to store graphviz debug output");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "debug_stats_gnuplot", "rna_Depsgraph_debug_stats_gnuplot");
parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
"File in which to store graphviz debug output");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string_file_path(func, "output_filename", NULL, FILE_MAX, "Output File Name",
+ "File name where gnuplot script will save the result");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "debug_tag_update", "rna_Depsgraph_debug_tag_update");
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 074db855c17..271ead13197 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -137,7 +137,7 @@ static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA
if (ob->type == OB_MESH && !psys) {
/* add particle system */
- part = psys_new_settings("ParticleSettings", bmain);
+ part = BKE_particlesettings_add(bmain, "ParticleSettings");
psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
part->type = PART_FLUID;
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 7dffab4eefb..e987c01134f 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -399,6 +399,7 @@ extern StructRNA RNA_PropertyGroup;
#endif
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr);
+struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop, struct PointerRNA *ptr);
/* Override default callbacks. */
/* Default override callbacks for all types. */
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index fd0b655e41e..88efff30481 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -121,12 +121,6 @@ typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *pro
typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
/* Handling override operations, and also comparison. */
-enum {
- /* Do not compare properties that are not overridable. */
- RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0,
- /* Do not compare properties that are already overridden. */
- RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1,
-};
/**
* If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b,
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 877d6b250c0..131378b5c49 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -97,16 +97,6 @@ static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value)
BKE_collection_rename(scene, sc, value);
}
-static void rna_SceneCollection_filter_set(PointerRNA *ptr, const char *value)
-{
- Scene *scene = (Scene *)ptr->id.data;
- SceneCollection *sc = (SceneCollection *)ptr->data;
- BLI_strncpy_utf8(sc->filter, value, sizeof(sc->filter));
-
- TODO_LAYER_SYNC_FILTER;
- (void)scene;
-}
-
static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -350,12 +340,10 @@ RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(hair_brightness_randomness)
/* ViewLayer settings. */
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_use_bent_normals)
-RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_denoise)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_bounce)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_factor)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_quality)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_distance)
-RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gtao_samples)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(dof_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bokeh_max_size)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bokeh_threshold)
@@ -387,7 +375,6 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(sss_separate_albedo)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_refraction)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres)
-RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_ray_count)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_quality)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_max_roughness)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_thickness)
@@ -397,6 +384,7 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(shadow_method)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(shadow_size)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(shadow_high_bitdepth)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_samples)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_render_samples)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_diffuse_bounces)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_cubemap_resolution)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_visibility_resolution)
@@ -703,48 +691,6 @@ static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *ptr)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
}
-static void rna_LayerCollection_enable_set(
- ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports, int value)
-{
- ViewLayer *view_layer;
- if (GS(id->name) == ID_SCE) {
- Scene *scene = (Scene *)id;
- view_layer = BKE_view_layer_find_from_collection(&scene->id, layer_collection);
- }
- else {
- BLI_assert(GS(id->name) == ID_GR);
- Group *group = (Group *)id;
- view_layer = group->view_layer;
- }
-
- if (layer_collection->flag & COLLECTION_DISABLED) {
- if (value == 1) {
- BKE_collection_enable(view_layer, layer_collection);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is already disabled",
- layer_collection->scene_collection->name);
- return;
- }
- }
- else {
- if (value == 0) {
- BKE_collection_disable(view_layer, layer_collection);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is already enabled",
- layer_collection->scene_collection->name);
- }
- }
-
- Scene *scene = CTX_data_scene(C);
- DEG_relations_tag_update(bmain);
- /* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
-}
-
static Group *rna_LayerCollection_create_group(
ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports)
{
@@ -912,7 +858,12 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po
static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C)
{
Depsgraph *graph = CTX_data_depsgraph(C);
- DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL)
+ DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_MODE_VIEWPORT,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
{
/* Don't do anything, we just need to run the iterator to flush
* the base info to the objects. */
@@ -1028,15 +979,14 @@ static void rna_def_scene_collections(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_SceneCollection_new");
RNA_def_function_ui_description(func, "Add a collection to scene");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
- parm = RNA_def_string(func, "name", "SceneCollection", 0, "", "New name for the collection (not unique)");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "name", NULL, 0, "", "New name for the collection (not unique)");
parm = RNA_def_pointer(func, "result", "SceneCollection", "", "Newly created collection");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_SceneCollection_remove");
- RNA_def_function_ui_description(func, "Remove a collection layer");
+ RNA_def_function_ui_description(func, "Remove a collection and move its objects to the master collection");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "layer", "SceneCollection", "", "Collection to remove");
+ parm = RNA_def_pointer(func, "collection", "SceneCollection", "", "Collection to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
@@ -1096,11 +1046,6 @@ static void rna_def_scene_collection(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Type of collection");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set");
- RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)");
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
-
prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "scene_collections", NULL);
RNA_def_property_struct_type(prop, "SceneCollection");
@@ -1114,12 +1059,6 @@ static void rna_def_scene_collection(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Objects", "All the objects directly added to this collection (not including sub-collection objects)");
rna_def_collection_objects(brna, prop);
- prop = RNA_def_property(srna, "filters_objects", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "filter_objects", NULL);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Filter Objects", "All the objects dynamically added to this collection via the filter");
-
/* Functions */
func = RNA_def_function(srna, "move_above", "rna_SceneCollection_move_above");
RNA_def_function_ui_description(func, "Move collection after another");
@@ -1261,12 +1200,19 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_samples_get",
"rna_LayerEngineSettings_Eevee_taa_samples_set", NULL);
- RNA_def_property_ui_text(prop, "Viewport Samples", "Number of temporal samples, unlimited if 0, "
- "disabled if 1");
+ RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0");
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
+ prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_render_samples_get",
+ "rna_LayerEngineSettings_Eevee_taa_render_samples_set", NULL);
+ RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
+
/* Screen Space Subsurface Scattering */
prop = RNA_def_property(srna, "sss_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_sss_enable_get",
@@ -1337,14 +1283,6 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
- prop = RNA_def_property(srna, "ssr_ray_count", PROP_INT, PROP_NONE);
- RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_ray_count_get",
- "rna_LayerEngineSettings_Eevee_ssr_ray_count_set", NULL);
- RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per pixels");
- RNA_def_property_range(prop, 1, 4);
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
-
prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_thickness_get",
"rna_LayerEngineSettings_Eevee_ssr_thickness_set", NULL);
@@ -1472,13 +1410,6 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
- prop = RNA_def_property(srna, "gtao_denoise", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_denoise_get",
- "rna_LayerEngineSettings_Eevee_gtao_denoise_set");
- RNA_def_property_ui_text(prop, "Denoise", "Use denoising to filter the resulting occlusion and bent normal but exhibit 2x2 pixel blocks");
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
-
prop = RNA_def_property(srna, "gtao_bounce", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_bounce_get",
"rna_LayerEngineSettings_Eevee_gtao_bounce_set");
@@ -1510,14 +1441,6 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
- prop = RNA_def_property(srna, "gtao_samples", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_samples_get",
- "rna_LayerEngineSettings_Eevee_gtao_samples_set", NULL);
- RNA_def_property_ui_text(prop, "Samples", "Number of samples to take to compute occlusion");
- RNA_def_property_range(prop, 2, 32);
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
-
/* Depth of Field */
prop = RNA_def_property(srna, "dof_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_dof_enable_get",
@@ -2065,11 +1988,6 @@ static void rna_def_layer_collection(BlenderRNA *brna)
parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "enable_set", "rna_LayerCollection_enable_set");
- RNA_def_function_ui_description(func, "Enable or disable a collection");
- parm = RNA_def_boolean(func, "value", 1, "Enable", "");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
-
func = RNA_def_function(srna, "create_group", "rna_LayerCollection_create_group");
RNA_def_function_ui_description(func, "Enable or disable a collection");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
@@ -2077,26 +1995,32 @@ static void rna_def_layer_collection(BlenderRNA *brna)
RNA_def_function_return(func, parm);
/* Flags */
- prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Enabled", "Enable or disable collection from depsgraph");
+ prop = RNA_def_property(srna, "selectable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_SELECTABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
+ RNA_def_property_ui_text(prop, "Selectable", "Restrict selection");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update");
- prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE);
+ prop = RNA_def_property(srna, "visible_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_VIEWPORT);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
- RNA_def_property_ui_text(prop, "Hide", "Restrict visiblity");
+ RNA_def_property_ui_text(prop, "Viewport Visibility", "");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update");
- prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_SELECTABLE);
+ prop = RNA_def_property(srna, "visible_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RENDER);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
- RNA_def_property_ui_text(prop, "Hide Selectable", "Restrict selection");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
+ RNA_def_property_ui_text(prop, "Render Visibility", "Control");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update");
- /* TODO_LAYER_OVERRIDE */
+ prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_ui_text(prop, "Enabled", "Enable or disable collection");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update");
}
static void rna_def_layer_collections(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c
index 61dc835022b..6586b456960 100644
--- a/source/blender/makesrna/intern/rna_lightprobe.c
+++ b/source/blender/makesrna/intern/rna_lightprobe.c
@@ -179,6 +179,13 @@ static void rna_def_lightprobe(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibilty blur");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+ prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "intensity");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 3.0f, 1.0, 3);
+ RNA_def_property_ui_text(prop, "Intensity", "Modify the intensity of the lighting captured by this probe");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
/* Data preview */
prop = RNA_def_property(srna, "show_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_DATA);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index f15006fa0ed..57292b7adc3 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -454,7 +454,7 @@ static World *rna_Main_worlds_new(Main *bmain, const char *name)
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
- World *world = add_world(bmain, safe_name);
+ World *world = BKE_world_add(bmain, safe_name);
id_us_min(&world->id);
return world;
}
@@ -529,7 +529,7 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name)
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
- bAction *act = add_empty_action(bmain, safe_name);
+ bAction *act = BKE_action_add(bmain, safe_name);
id_fake_user_clear(&act->id);
return act;
}
@@ -539,7 +539,7 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
- ParticleSettings *part = psys_new_settings(safe_name, bmain);
+ ParticleSettings *part = BKE_particlesettings_add(bmain, safe_name);
id_us_min(&part->id);
return part;
}
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index a2845b3a2f8..440af0d0e8e 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -85,6 +85,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = {
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -323,7 +324,7 @@ static void rna_Material_use_diffuse_ramp_set(PointerRNA *ptr, int value)
else ma->mode &= ~MA_RAMP_COL;
if ((ma->mode & MA_RAMP_COL) && ma->ramp_col == NULL)
- ma->ramp_col = add_colorband(false);
+ ma->ramp_col = BKE_colorband_add(false);
}
static void rna_Material_use_specular_ramp_set(PointerRNA *ptr, int value)
@@ -334,7 +335,7 @@ static void rna_Material_use_specular_ramp_set(PointerRNA *ptr, int value)
else ma->mode &= ~MA_RAMP_SPEC;
if ((ma->mode & MA_RAMP_SPEC) && ma->ramp_spec == NULL)
- ma->ramp_spec = add_colorband(false);
+ ma->ramp_spec = BKE_colorband_add(false);
}
static void rna_Material_use_nodes_update(bContext *C, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 62360ea34a3..79a9d072ad2 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -1667,7 +1667,7 @@ static int rna_MeshPolygonStringPropertyLayer_data_length(PointerRNA *ptr)
return me->totpoly;
}
-/* XXX, we dont have propper byte string support yet, so for now use the (bytes + 1)
+/* XXX, we dont have proper byte string support yet, so for now use the (bytes + 1)
* bmesh API exposes correct python/bytestring access */
void rna_MeshStringProperty_s_get(PointerRNA *ptr, char *value)
{
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index c443b68b209..e721a04bd2a 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -2124,6 +2124,20 @@ static void rna_def_modifier_array(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, "rna_ArrayModifier_end_cap_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "U Offset", "Amount to offset array UVs on the U axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "offset_v", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[1]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "V Offset", "Amount to offset array UVs on the V axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_edgesplit(BlenderRNA *brna)
@@ -3222,6 +3236,11 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SimpleDeformModifier_vgroup_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "deform_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
+ RNA_def_property_ui_text(prop, "Axis", "Deform around local axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "origin", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Origin", "Offset the origin and orientation of the deformation");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -3251,12 +3270,17 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_X);
- RNA_def_property_ui_text(prop, "Lock X Axis", "Do not allow deformation along the X axis");
+ RNA_def_property_ui_text(prop, "X", "Do not allow deformation along the X axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "lock_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Y);
- RNA_def_property_ui_text(prop, "Lock Y Axis", "Do not allow deformation along the Y axis");
+ RNA_def_property_ui_text(prop, "Y", "Do not allow deformation along the Y axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Z);
+ RNA_def_property_ui_text(prop, "Z", "Do not allow deformation along the Z axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index ab8370f77e7..2b2c6998eb4 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5286,14 +5286,14 @@ static void def_cmp_luma_matte(StructRNA *srna)
prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "t1");
RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL);
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3);
RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "t2");
RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL);
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3);
RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -5396,14 +5396,14 @@ static void def_cmp_channel_matte(StructRNA *srna)
prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "t1");
RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL);
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3);
RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "t2");
RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL);
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3);
RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index a153590f4ac..f2b2e95d21e 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -229,6 +229,27 @@ static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
DEG_id_type_tag(bmain, ID_OB);
}
+static int rna_Object_is_visible_get(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ /* The duplicators final visibility is not evaluated by depsgraph, so it's
+ * in ob->base_flag & VISIBLED. Instead we need to take into account whether
+ * we are rendering or not, and the ob->duplicator_visibility_flag.
+ * However for this assessor we don't know if we are rendering, so we just
+ * ignore the duplicator visibility
+ */
+ return BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE);
+}
+
+static void rna_Object_collection_properties_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Object *ob = ptr->data;
+
+ if (ob->base_collection_properties != NULL) {
+ rna_iterator_listbase_begin(iter, &ob->base_collection_properties->data.group, NULL);
+ }
+}
+
static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16])
{
Object *ob = ptr->id.data;
@@ -2777,32 +2798,36 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rigid Body Constraint", "Constraint constraining rigid bodies");
/* restrict */
- prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEW);
- RNA_def_property_ui_text(prop, "Restrict View", "Restrict visibility in the viewport");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update");
-
- prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_SELECT);
- RNA_def_property_ui_text(prop, "Restrict Select", "Restrict selection in the viewport");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_RENDER);
RNA_def_property_ui_text(prop, "Restrict Render", "Restrict renderability");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update");
- /* Keep it in sync with BKE_object_is_visible. */
+ prop = RNA_def_property(srna, "show_duplicator_for_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_RENDER);
+ RNA_def_property_ui_text(prop, "Render Duplicator", "Make duplicator visible when rendering");
+
+ prop = RNA_def_property(srna, "show_duplicator_for_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_VIEWPORT);
+ RNA_def_property_ui_text(prop, "Show Duplicator", "Make duplicator visible in the viewport");
+
prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "base_flag", BASE_VISIBLED);
+ RNA_def_property_boolean_funcs(prop, "rna_Object_is_visible_get", NULL);
RNA_def_property_ui_text(prop, "Visible", "Visible to camera rays, set only on objects evaluated by depsgraph");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "collection_properties", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "base_collection_properties->data.group", NULL);
+ RNA_def_property_collection_funcs(prop,
+ "rna_Object_collection_properties_begin",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
RNA_def_property_struct_type(prop, "LayerCollectionSettings");
RNA_def_property_ui_text(prop, "Collection Settings",
"Engine specific render settings to be overridden by collections");
@@ -2827,16 +2852,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Slow Parent Offset", "Delay in the parent relationship");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
-
- /* depsgraph hack */
- prop = RNA_def_property(srna, "use_extra_recalc_object", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "depsflag", OB_DEPS_EXTRA_OB_RECALC);
- RNA_def_property_ui_text(prop, "Extra Object Update", "Refresh this object again on frame changes, dependency graph hack");
-
- prop = RNA_def_property(srna, "use_extra_recalc_data", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "depsflag", OB_DEPS_EXTRA_DATA_RECALC);
- RNA_def_property_ui_text(prop, "Extra Data Update", "Refresh this object's data again on frame changes, dependency graph hack");
-
+
/* duplicates */
prop = RNA_def_property(srna, "dupli_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "transflag");
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 031b0bdec99..9265c7b62cf 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1265,7 +1265,8 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_size");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1.0f, 3);
RNA_def_property_ui_text(prop, "Size", "Size of the turbulence");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1289,7 +1290,8 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "distance_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "maxdist");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1.0f, 3);
RNA_def_property_ui_text(prop, "Maximum Distance", "Maximum distance for the field to work");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 67eaa22fbe4..12e56b8e926 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -2292,11 +2292,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Size", "Show particle size");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_render_emitter", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_EMITTER);
- RNA_def_property_ui_text(prop, "Emitter", "Render emitter Object also");
- RNA_def_property_update(prop, 0, "rna_Particle_redo");
-
prop = RNA_def_property(srna, "show_health", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH);
RNA_def_property_ui_text(prop, "Health", "Draw boid health");
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index baf7f5e6aa3..f50be85c446 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -823,16 +823,19 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "Bone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bone", "Bone associated with this PoseBone");
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Parent", "Parent of this pose bone");
prop = RNA_def_property(srna, "child", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Child", "Child of this pose bone");
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 24d56ef2a19..38149734bc2 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -337,7 +337,7 @@ static void rna_Struct_property_tags_begin(CollectionPropertyIterator *iter, Poi
/* here ptr->data should always be the same as iter->parent.type */
StructRNA *srna = (StructRNA *)ptr->data;
const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna);
- unsigned int tag_count = RNA_enum_items_count(tag_defines);
+ unsigned int tag_count = tag_defines ? RNA_enum_items_count(tag_defines) : 0;
rna_iterator_array_begin(iter, (void *)tag_defines, sizeof(EnumPropertyItem), tag_count, 0, NULL);
}
@@ -1094,10 +1094,12 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
/* Default override (and compare) callbacks. */
/* Used for both Pointer and Collection properties. */
-static int rna_property_override_equals_propptr(
- PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode,
- IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
+static int rna_property_override_diff_propptr(
+ PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, const bool no_ownership,
+ IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed)
{
+ const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
+
bool is_id = false;
bool is_type_null = false;
@@ -1119,46 +1121,38 @@ static int rna_property_override_equals_propptr(
if (is_id) {
BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data);
+ BLI_assert(no_ownership); /* For now, once we deal with nodetrees we'll want to get rid of that one. */
}
if (override) {
- if (rna_path) {
- if (is_type_null || is_id) {
- /* In case this is an ID (or one of the pointers is NULL), do not compare structs!
- * This is a quite safe path to infinite loop.
- * Instead, just compare pointers themselves (we assume sub-ID structs cannot loop). */
- const int comp = (propptr_a->data != propptr_b->data);
-
- if (comp != 0 && rna_path) {
- bool created = false;
- IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+ if (no_ownership /* || is_id */ || is_type_null) {
+ /* In case this pointer prop does not own its data (or one is NULL), do not compare structs!
+ * This is a quite safe path to infinite loop, among other nasty issues.
+ * Instead, just compare pointers themselves. */
+ const int comp = (propptr_a->data != propptr_b->data);
- if (op != NULL && created) { /* If not yet overridden... */
- BKE_override_static_property_operation_get(
- op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
- if (r_override_changed) {
- *r_override_changed = created;
- }
- }
- }
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
- return comp;
- }
- else {
- const bool changed = RNA_struct_auto_override(propptr_a, propptr_b, override, rna_path);
- if (r_override_changed) {
- *r_override_changed = *r_override_changed || changed;
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
}
- /* XXX Simplification here, if no override was added we assume they are equal,
- * this may not be good behavior, time will say. */
- return !changed;
}
+
+ return comp;
}
else {
- return !RNA_struct_override_matches(
- propptr_a, propptr_b, override,
- flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE,
- flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
+ eRNAOverrideMatchResult report_flags = 0;
+ const bool match = RNA_struct_override_matches(propptr_a, propptr_b, rna_path, override, flags, &report_flags);
+ if (r_override_changed && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) != 0) {
+ *r_override_changed = true;
+ }
+ return !match;
}
}
else {
@@ -1183,6 +1177,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
{
BLI_assert(len_a == len_b);
+ /* Note: at this point, we are sure that when len_a is zero, we are not handling an (empty) array. */
+
+ const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
+
switch (RNA_property_type(prop_a)) {
case PROP_BOOLEAN:
{
@@ -1198,7 +1196,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
/* XXX TODO this will have to be refined to handle array items */
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1225,7 +1223,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const int value_b = RNA_property_boolean_get(ptr_b, prop_b);
const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1256,7 +1254,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
/* XXX TODO this will have to be refined to handle array items */
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1283,7 +1281,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const int value_b = RNA_property_int_get(ptr_b, prop_b);
const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1315,7 +1313,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const int comp = memcmp(array_a, array_b, sizeof(float) * len_a);
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
/* XXX TODO this will have to be refined to handle array items */
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1343,7 +1341,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const float value_b = RNA_property_float_get(ptr_b, prop_b);
const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1367,7 +1365,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
const int value_b = RNA_property_enum_get(ptr_b, prop_b);
const int comp = value_a != value_b;
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1391,7 +1389,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
const int comp = strcmp(value_a, value_b);
- if (comp != 0 && rna_path) {
+ if (do_create && comp != 0) {
bool created = false;
IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
@@ -1419,9 +1417,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
else {
PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
- return rna_property_override_equals_propptr(
- &propptr_a, &propptr_b, mode,
- override, rna_path, r_override_changed, flags);
+ const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
+ return rna_property_override_diff_propptr(
+ &propptr_a, &propptr_b, mode, no_ownership,
+ override, rna_path, flags, r_override_changed);
}
break;
}
@@ -1468,9 +1467,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
}
if (equals) {
- const int eq = rna_property_override_equals_propptr(
- &iter_a.ptr, &iter_b.ptr, mode,
- override, extended_rna_path, r_override_changed, flags);
+ const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
+ const int eq = rna_property_override_diff_propptr(
+ &iter_a.ptr, &iter_b.ptr, mode, no_ownership,
+ override, extended_rna_path, flags, r_override_changed);
equals = equals && eq;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 785f805a33e..5518b296e22 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5676,14 +5676,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "frs_sec");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 1, 120);
+ RNA_def_property_range(prop, 1, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 1, 120, 1, -1);
RNA_def_property_ui_text(prop, "FPS", "Framerate, expressed in frames per second");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update");
prop = RNA_def_property(srna, "fps_base", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "frs_sec_base");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.1f, 120.0f);
+ RNA_def_property_range(prop, 1e-5f, 1e6f);
+ RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1);
RNA_def_property_ui_text(prop, "FPS Base", "Framerate base");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update");
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index ddcf525c3c8..cc447f2a028 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -297,6 +297,22 @@ static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, PointerRNA *UNUSED(p
}
}
+static void rna_Sculpt_ShowMask_update(bContext *C, PointerRNA *UNUSED(ptr))
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *object = OBACT(view_layer);
+ if (object == NULL || object->sculpt == NULL) {
+ return;
+ }
+ Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = scene->toolsettings->sculpt;
+ object->sculpt->show_mask = ((sd->flags & SCULPT_HIDE_MASK) == 0);
+ if (object->sculpt->pbvh != NULL) {
+ pbvh_show_mask_set(object->sculpt->pbvh, object->sculpt->show_mask);
+ }
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, object);
+}
+
static char *rna_Sculpt_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.sculpt");
@@ -613,6 +629,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowDiffuseColor_update");
+ prop = RNA_def_property(srna, "show_mask", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", SCULPT_HIDE_MASK);
+ RNA_def_property_ui_text(prop, "Show Mask", "Show mask as overlay on object");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowMask_update");
+
prop = RNA_def_property(srna, "detail_size", PROP_FLOAT, PROP_PIXEL);
RNA_def_property_ui_range(prop, 0.5, 40.0, 10, 2);
RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)");
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 8c2a09f1186..ac13f9d8294 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -52,9 +52,9 @@
#ifdef RNA_RUNTIME
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_particle.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -395,7 +395,7 @@ static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value)
sds->use_coba = value;
if (value && sds->coba == NULL) {
- sds->coba = add_colorband(false);
+ sds->coba = BKE_colorband_add(false);
}
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 82283019fc8..e748299a635 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2103,23 +2103,23 @@ static void rna_def_space_outliner(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem display_mode_items[] = {
- {SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display data-blocks in all scenes"},
- {SO_CUR_SCENE, "CURRENT_SCENE", 0, "Current Scene", "Display data-blocks in current scene"},
- {SO_VISIBLE, "VISIBLE_LAYERS", 0, "Visible Layers", "Display data-blocks in visible layers"},
- {SO_SELECTED, "SELECTED", 0, "Selected", "Display data-blocks of selected, visible objects"},
- {SO_ACTIVE, "ACTIVE", 0, "Active", "Display data-blocks of active object"},
- {SO_SAME_TYPE, "SAME_TYPES", 0, "Same Types",
- "Display data-blocks of all objects of same type as selected object"},
+ {SO_VIEW_LAYER, "VIEW_LAYER", 0, "View Layer", "Display the collections of the active view layer"},
+ {SO_COLLECTIONS, "COLLECTIONS", 0, "Collections", "Display all collections based on the "
+ "master collection hierarchy"},
+ {SO_SCENES, "SCENES", 0, "Scenes", "Display composition related data in all scenes"},
{SO_GROUPS, "GROUPS", 0, "Groups", "Display groups and their data-blocks"},
{SO_SEQUENCE, "SEQUENCE", 0, "Sequence", "Display sequence data-blocks"},
{SO_LIBRARIES, "LIBRARIES", 0, "Blender File", "Display data of current file and linked libraries"},
{SO_DATABLOCKS, "DATABLOCKS", 0, "Data-Blocks", "Display all raw data-blocks"},
- {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"},
{SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data",
"Display data-blocks which are unused and/or will be lost when the file is reloaded"},
- {SO_ACT_LAYER, "ACT_LAYER", 0, "Active View Layer", "Display the collections of the active view layer"},
- {SO_COLLECTIONS, "MASTER_COLLECTION", 0, "Master Collection Tree", "Display all collections based on the "
- "master collection hierarchy"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem filter_state_items[] = {
+ {SO_FILTER_OB_VISIBLE, "VISIBLE", ICON_RESTRICT_VIEW_OFF, "Visible", "Show visible objects"},
+ {SO_FILTER_OB_SELECTED, "SELECTED", ICON_RESTRICT_SELECT_OFF, "Selected", "Show selected objects"},
+ {SO_FILTER_OB_ACTIVE, "ACTIVE", ICON_LAYER_ACTIVE, "Active", "Show only the active object"},
{0, NULL, 0, NULL, NULL}
};
@@ -2142,22 +2142,119 @@ static void rna_def_space_outliner(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_filter_case_sensitive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_CASE_SENSITIVE);
RNA_def_property_ui_text(prop, "Case Sensitive Matches Only", "Only use case sensitive matches of search string");
+ RNA_def_property_ui_icon(prop, ICON_SYNTAX_OFF, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_filter_complete", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_COMPLETE);
RNA_def_property_ui_text(prop, "Complete Matches Only", "Only use complete matches of search string");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_DATA_FONT, 0);
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_ui_icon(prop, ICON_SORTALPHA, 0);
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");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Filters. */
+ prop = RNA_def_property(srna, "use_filter_search", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_SEARCH);
+ RNA_def_property_ui_text(prop, "Search Name", "Filter searched elements");
+ RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filters", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_ENABLE);
+ RNA_def_property_ui_text(prop, "Use Filters", "Use filters");
+ RNA_def_property_ui_icon(prop, ICON_FILTER, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OBJECT);
+ RNA_def_property_ui_text(prop, "Filter Objects", "Show objects");
+ RNA_def_property_ui_icon(prop, ICON_OBJECT_DATA, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_content", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CONTENT);
+ RNA_def_property_ui_text(prop, "Filter Objects Contents", "Show what is inside the objects elements");
+ RNA_def_property_ui_icon(prop, ICON_MODIFIER, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_children", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_CHILDREN);
+ RNA_def_property_ui_text(prop, "Filter Objects Children", "Show children");
+ RNA_def_property_ui_icon(prop, ICON_PLUS, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION);
+ RNA_def_property_ui_text(prop, "Filter Collections", "Show collections");
+ RNA_def_property_ui_icon(prop, ICON_COLLAPSEMENU, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Filters object state. */
+ prop = RNA_def_property(srna, "use_filter_object_state", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_OB_STATE);
+ RNA_def_property_ui_text(prop, "Filter Object State", "Filter objects based on their state (visible, ...)."
+ "This can be slow");
+ RNA_def_property_ui_icon(prop, ICON_LAYER_USED, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "filter_state", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "filter_state");
+ RNA_def_property_enum_items(prop, filter_state_items);
+ RNA_def_property_ui_text(prop, "State Filter", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Filters object type. */
+ prop = RNA_def_property(srna, "use_filter_object_type", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_OB_TYPE);
+ RNA_def_property_ui_text(prop, "Filter Object Type", "Show specific objects types");
+ RNA_def_property_ui_icon(prop, ICON_MESH_CUBE, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_MESH);
+ RNA_def_property_ui_text(prop, "Show Meshes", "Show mesh objects");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_MESH, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_armature", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_ARMATURE);
+ RNA_def_property_ui_text(prop, "Show Armatures", "Show armature objects");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_ARMATURE, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_empty", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_EMPTY);
+ RNA_def_property_ui_text(prop, "Show Empties", "Show empty objects");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_EMPTY, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_lamp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_LAMP);
+ RNA_def_property_ui_text(prop, "Show Lamps", "Show lamps objects");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_LAMP, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CAMERA);
+ RNA_def_property_ui_text(prop, "Show Cameras", "Show camera objects");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_CAMERA, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_others", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_OTHERS);
+ RNA_def_property_ui_text(prop, "Show Other Objects", "Show curves, lattices, light probes, fonts, ...");
+ RNA_def_property_ui_icon(prop, ICON_ZOOMIN, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
}
static void rna_def_space_view3d(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 43fe7bd3f76..42e3e2c83fb 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -112,6 +112,7 @@ static const EnumPropertyItem blend_type_items[] = {
#include "RNA_access.h"
+#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_texture.h"
@@ -407,7 +408,7 @@ static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, int value)
else tex->flag &= ~TEX_COLORBAND;
if ((tex->flag & TEX_COLORBAND) && tex->coba == NULL)
- tex->coba = add_colorband(false);
+ tex->coba = BKE_colorband_add(false);
}
static void rna_Texture_use_nodes_update(bContext *C, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index d23017429c1..ccc118edfb6 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -48,6 +48,9 @@
#ifdef RNA_RUNTIME
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
#include "BKE_node.h"
#include "DEG_depsgraph.h"
@@ -56,71 +59,6 @@
#include "WM_api.h"
-static MovieTrackingObject *tracking_object_from_track(MovieClip *clip,
- MovieTrackingTrack *track)
-{
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = &tracking->tracks;
- /* TODO: it's a bit difficult to find list track came from knowing just
- * movie clip ID and MovieTracking structure, so keep this naive
- * search for a while */
- if (BLI_findindex(tracksbase, track) == -1) {
- MovieTrackingObject *object = tracking->objects.first;
- while (object) {
- if (BLI_findindex(&object->tracks, track) != -1) {
- return object;
- }
- object = object->next;
- }
- }
- return NULL;
-}
-
-static ListBase *tracking_tracksbase_from_track(MovieClip *clip,
- MovieTrackingTrack *track)
-{
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object = tracking_object_from_track(clip, track);
- if (object != NULL) {
- return &object->tracks;
- }
- return &tracking->tracks;
-}
-
-static MovieTrackingObject *tracking_object_from_plane_track(
- MovieClip *clip,
- MovieTrackingPlaneTrack *plane_track)
-{
- MovieTracking *tracking = &clip->tracking;
- ListBase *plane_tracks_base = &tracking->plane_tracks;
- /* TODO: it's a bit difficult to find list track came from knowing just
- * movie clip ID and MovieTracking structure, so keep this naive
- * search for a while */
- if (BLI_findindex(plane_tracks_base, plane_track) == -1) {
- MovieTrackingObject *object = tracking->objects.first;
- while (object) {
- if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
- return object;
- }
- object = object->next;
- }
- }
- return NULL;
-}
-
-static ListBase *tracking_tracksbase_from_plane_track(
- MovieClip *clip,
- MovieTrackingPlaneTrack *plane_track)
-{
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object = tracking_object_from_plane_track(clip,
- plane_track);
- if (object != NULL) {
- return &object->plane_tracks;
- }
- return &tracking->plane_tracks;
-}
-
static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
{
return BLI_sprintfN("tracking");
@@ -150,19 +88,12 @@ static char *rna_trackingTrack_path(PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data;
- MovieTrackingObject *object = tracking_object_from_track(clip, track);
- char track_name_esc[sizeof(track->name) * 2];
- BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc));
- if (object == NULL) {
- return BLI_sprintfN("tracking.tracks[\"%s\"]", track_name_esc);
- }
- else {
- char object_name_esc[sizeof(object->name) * 2];
- BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
- return BLI_sprintfN("tracking.objects[\"%s\"].tracks[\"%s\"]",
- object_name_esc,
- track_name_esc);
- }
+ /* Escaped object name, escaped track name, rest of the path. */
+ char rna_path[MAX_NAME * 4 + 64];
+ BKE_tracking_get_rna_path_for_track(&clip->tracking,
+ track,
+ rna_path, sizeof(rna_path));
+ return BLI_strdup(rna_path);
}
static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -256,9 +187,26 @@ static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data;
- ListBase *tracksbase = tracking_tracksbase_from_track(clip, track);
+ ListBase *tracksbase =
+ BKE_tracking_find_tracks_list_for_track(&clip->tracking, track);
+ /* Store old name, for the animation fix later. */
+ char old_name[sizeof(track->name)];
+ BLI_strncpy(old_name, track->name, sizeof(track->name));
+ /* Update the name, */
BLI_strncpy(track->name, value, sizeof(track->name));
BKE_tracking_track_unique_name(tracksbase, track);
+ /* Fix animation paths. */
+ AnimData *adt = BKE_animdata_from_id(&clip->id);
+ if (adt != NULL) {
+ char rna_path[MAX_NAME * 2 + 64];
+ BKE_tracking_get_rna_path_prefix_for_track(&clip->tracking,
+ track,
+ rna_path, sizeof(rna_path));
+ BKE_animdata_fix_paths_rename(&clip->id, adt, NULL,
+ rna_path,
+ old_name, track->name,
+ 0, 0, 1);
+ }
}
static int rna_trackingTrack_select_get(PointerRNA *ptr)
@@ -327,28 +275,40 @@ static char *rna_trackingPlaneTrack_path(PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
- char track_name_esc[sizeof(plane_track->name) * 2];
- MovieTrackingObject *object = tracking_object_from_plane_track(clip, plane_track);
- BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc));
- if (object == NULL) {
- return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", track_name_esc);
- }
- else {
- char object_name_esc[sizeof(object->name) * 2];
- BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
- return BLI_sprintfN("tracking.objects[\"%s\"].plane_tracks[\"%s\"]",
- object_name_esc,
- track_name_esc);
- }
+ /* Escaped object name, escaped track name, rest of the path. */
+ char rna_path[MAX_NAME * 4 + 64];
+ BKE_tracking_get_rna_path_for_plane_track(&clip->tracking,
+ plane_track,
+ rna_path, sizeof(rna_path));
+ return BLI_strdup(rna_path);
}
static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
- ListBase *plane_tracks_base = tracking_tracksbase_from_plane_track(clip, plane_track);
+ ListBase *plane_tracks_base =
+ BKE_tracking_find_tracks_list_for_plane_track(&clip->tracking,
+ plane_track);
+ /* Store old name, for the animation fix later. */
+ char old_name[sizeof(plane_track->name)];
+ BLI_strncpy(old_name, plane_track->name, sizeof(plane_track->name));
+ /* Update the name, */
BLI_strncpy(plane_track->name, value, sizeof(plane_track->name));
BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
+ /* Fix animation paths. */
+ AnimData *adt = BKE_animdata_from_id(&clip->id);
+ if (adt != NULL) {
+ char rna_path[MAX_NAME * 2 + 64];
+ BKE_tracking_get_rna_path_prefix_for_plane_track(&clip->tracking,
+ plane_track,
+ rna_path,
+ sizeof(rna_path));
+ BKE_animdata_fix_paths_rename(&clip->id, adt, NULL,
+ rna_path,
+ old_name, plane_track->name,
+ 0, 0, 1);
+ }
}
static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr))
@@ -1651,6 +1611,7 @@ static void rna_def_trackingPlaneTrack(BlenderRNA *brna)
/* auto keyframing */
prop = RNA_def_property(srna, "use_auto_keying", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_TRACK_AUTOKEY);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Auto Keyframe", "Automatic keyframe insertion when moving plane corners");
RNA_def_property_ui_icon(prop, ICON_REC, 0);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 51bdc0ea9ff..fbc16f01116 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -454,6 +454,12 @@ void RNA_api_ui_layout(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
+ static const EnumPropertyItem id_template_filter_items[] = {
+ {UI_TEMPLATE_ID_FILTER_ALL, "ALL", 0, "All", ""},
+ {UI_TEMPLATE_ID_FILTER_AVAILABLE, "AVAILABLE", 0, "Available", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static float node_socket_color_default[] = { 0.0f, 0.0f, 0.0f, 1.0f };
/* simple layout specifiers */
@@ -549,7 +555,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in buttons, no text");
RNA_def_boolean(func, "event", false, "", "Use button to input key events");
RNA_def_boolean(func, "full_event", false, "", "Use button to input full events including modifiers");
- RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text");
+ RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, not just the icon/text");
RNA_def_int(func, "index", -1, -2, INT_MAX, "",
"The index of this button, when set a single member of an array can be accessed, "
"when set to -1 all array members are used", -2, INT_MAX); /* RNA_NO_INDEX == -1 */
@@ -582,7 +588,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function(srna, "operator_menu_hold", "rna_uiItemOMenuHold") :
RNA_def_function(srna, "operator", "rna_uiItemO");
api_ui_item_op_common(func);
- RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text");
+ RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, not just the icon/text");
RNA_def_boolean(func, "depress", false, "", "Draw pressed in");
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
@@ -685,7 +691,9 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block");
RNA_def_string(func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block");
RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
-
+ RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
+ "", "Optionally limit the items which can be selected");
+
func = RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
@@ -694,7 +702,9 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
-
+ RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
+ "", "Optionally limit the items which can be selected");
+
func = RNA_def_function(srna, "template_any_ID", "rna_uiTemplateAnyID");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
@@ -711,6 +721,8 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block");
RNA_def_string(func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block");
RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
+ RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
+ "", "Optionally limit the items which can be selected");
func = RNA_def_function(srna, "template_search", "uiTemplateSearch");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 1cdd43eeffc..7bd1e4bb3b2 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -24,6 +24,7 @@
* \ingroup RNA
*/
+#include <limits.h>
#include <stdlib.h>
#include "DNA_curve_types.h"
@@ -34,6 +35,7 @@
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
#include "BKE_appdir.h"
#include "BKE_DerivedMesh.h"
@@ -145,6 +147,12 @@ static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}
+static void rna_userdef_update_ui(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_WINDOW, NULL);
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+}
+
static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
BLF_cache_clear();
@@ -638,6 +646,27 @@ static StructRNA *rna_AddonPref_refine(PointerRNA *ptr)
#else
+/* TODO(sergey): This technically belongs to blenlib, but we don't link
+ * makesrna against it.
+ */
+
+/* Get maximum addressable memory in megabytes, */
+static size_t max_memory_in_megabytes(void)
+{
+ /* Maximum addressable bytes on this platform. */
+ const size_t limit_bytes = (((size_t)1) << ((sizeof(size_t) * 8) - 1));
+ /* Convert it to megabytes and return. */
+ return (limit_bytes >> 20);
+}
+
+/* Same as above, but clipped to int capacity. */
+static int max_memory_in_megabytes_int(void)
+{
+ const size_t limit_megabytes = max_memory_in_megabytes();
+ /* NOTE: The result will fit into integer. */
+ return (int)min_zz(limit_megabytes, (size_t)INT_MAX);
+}
+
static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3397,12 +3426,24 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_SPLASH_DISABLE);
RNA_def_property_ui_text(prop, "Show Splash", "Display splash screen on startup");
+
prop = RNA_def_property(srna, "show_playback_fps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_FPS);
RNA_def_property_ui_text(prop, "Show Playback FPS",
"Show the frames per second screen refresh rate, while animation is played back");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
+
+ /* app flags (use for app-templates) */
+ prop = RNA_def_property(srna, "show_layout_ui", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_LOCK_UI_LAYOUT);
+ RNA_def_property_ui_text(prop, "Show Layout Widgets", "Show screen layout editing UI");
+ RNA_def_property_update(prop, 0, "rna_userdef_update_ui");
+
+ prop = RNA_def_property(srna, "show_view3d_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_VIEW3D_HIDE_CURSOR);
+ RNA_def_property_ui_text(prop, "Show 3D View Cursor", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
/* menus */
prop = RNA_def_property(srna, "use_mouse_over_open", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO);
@@ -3479,12 +3520,12 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Global Pivot", "Lock the same rotation/scaling pivot in all 3D Views");
prop = RNA_def_property(srna, "use_mouse_depth_navigate", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZBUF_ORBIT);
+ RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_NAVIGATE);
RNA_def_property_ui_text(prop, "Auto Depth",
"Use the depth under the mouse to improve view pan/rotate/zoom functionality");
prop = RNA_def_property(srna, "use_mouse_depth_cursor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZBUF_CURSOR);
+ RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_CURSOR);
RNA_def_property_ui_text(prop, "Cursor Depth",
"Use the depth under the mouse when placing the cursor");
@@ -3552,6 +3593,11 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Manipulator", "Use 3D transform manipulator");
RNA_def_property_update(prop, 0, "rna_userdef_show_manipulator_update");
+ prop = RNA_def_property(srna, "show_manipulator_navigate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "manipulator_flag", USER_MANIPULATOR_DRAW_NAVIGATE);
+ RNA_def_property_ui_text(prop, "Navigate Manipulator", "Use 3D navigation manipulator");
+ RNA_def_property_update(prop, 0, "rna_userdef_show_manipulator_update");
+
/* TODO, expose once it's working. */
#if 0
prop = RNA_def_property(srna, "show_manipulator_shaded", PROP_BOOLEAN, PROP_NONE);
@@ -3670,7 +3716,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "undo_memory_limit", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "undomemory");
- RNA_def_property_range(prop, 0, 32767);
+ RNA_def_property_range(prop, 0, max_memory_in_megabytes_int());
RNA_def_property_ui_text(prop, "Undo Memory Size", "Maximum memory usage in megabytes (0 means unlimited)");
prop = RNA_def_property(srna, "use_global_undo", PROP_BOOLEAN, PROP_NONE);
@@ -4080,7 +4126,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "memory_cache_limit", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "memcachelimit");
- RNA_def_property_range(prop, 0, (sizeof(void *) == 8) ? 1024 * 32 : 1024); /* 32 bit 2 GB, 64 bit 32 GB */
+ RNA_def_property_range(prop, 0, max_memory_in_megabytes_int());
RNA_def_property_ui_text(prop, "Memory Cache Limit", "Memory cache limit (in megabytes)");
RNA_def_property_update(prop, 0, "rna_Userdef_memcache_update");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 36f07db727b..bcb5bb524f0 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1586,6 +1586,11 @@ static void rna_def_operator_options_runtime(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invoke", "True when invoked (even if only the execute callbacks available)");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "is_repeat", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_REPEAT);
+ RNA_def_property_ui_text(prop, "Repeat", "True when run from the redo panel");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "use_cursor_region", PROP_BOOLEAN, PROP_BOOLEAN);
RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_CURSOR_REGION);
RNA_def_property_ui_text(prop, "Focus Region", "Enable to use the region under the cursor for modal execution");
@@ -1908,7 +1913,12 @@ static void rna_def_event(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_tablet", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Event_is_tablet_get", NULL);
- RNA_def_property_ui_text(prop, "Tablet Pressure", "The pressure of the tablet or 1.0 if no tablet present");
+ RNA_def_property_ui_text(prop, "Is Tablet", "The event has tablet data");
+
+ prop = RNA_def_property(srna, "is_mouse_absolute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "is_motion_absolute", 1);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input");
/* modifiers */
prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 188b63d7d24..82077051c18 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -504,8 +504,11 @@ void RNA_api_wm(StructRNA *srna)
/* invoke enum */
func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke");
- RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of "
- "operator's type 'prop' EnumProperty, and execute it on confirmation)");
+ RNA_def_function_ui_description(
+ func,
+ "Operator search popup invoke which "
+ "searches values of the operator's :class:`bpy.types.Operator.bl_property` "
+ "(which must be an EnumProperty), executing it on confirmation");
rna_generic_op_invoke(func, 0);
/* invoke functions, for use with python */
diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c
index 00705456fc7..d6de12407b0 100644
--- a/source/blender/makesrna/intern/rna_wm_manipulator.c
+++ b/source/blender/makesrna/intern/rna_wm_manipulator.c
@@ -401,6 +401,7 @@ RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_value, flag, WM_MANIPULATOR_DR
RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_offset_scale, flag, WM_MANIPULATOR_DRAW_OFFSET_SCALE);
RNA_MANIPULATOR_GENERIC_FLAG_NEG_RW_DEF(flag_use_draw_scale, flag, WM_MANIPULATOR_DRAW_OFFSET_SCALE);
RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_MANIPULATOR_HIDDEN);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_grab_cursor, flag, WM_MANIPULATOR_GRAB_CURSOR);
/* wmManipulator.state */
RNA_MANIPULATOR_FLAG_RO_DEF(state_is_highlight, state, WM_MANIPULATOR_STATE_HIGHLIGHT);
@@ -1087,6 +1088,13 @@ static void rna_def_manipulator(BlenderRNA *brna, PropertyRNA *cprop)
prop, "rna_Manipulator_flag_hide_get", "rna_Manipulator_flag_hide_set");
RNA_def_property_ui_text(prop, "Hide", "");
RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_GRAB_CURSOR */
+ prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_grab_cursor_get", "rna_Manipulator_flag_use_grab_cursor_set");
+ RNA_def_property_ui_text(prop, "Grab Cursor", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
/* WM_MANIPULATOR_DRAW_HOVER */
prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 81ace75f2b1..91501e539c0 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -177,8 +177,8 @@ static void dm_mvert_map_doubles(
source_end = source_start + source_num_verts;
/* build array of MVerts to be tested for merging */
- sorted_verts_target = MEM_mallocN(sizeof(SortVertsElem) * target_num_verts, __func__);
- sorted_verts_source = MEM_mallocN(sizeof(SortVertsElem) * source_num_verts, __func__);
+ sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__);
+ sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__);
/* Copy target vertices index and cos into SortVertsElem array */
svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end);
@@ -491,7 +491,7 @@ static DerivedMesh *arrayModifier_doArray(
if (use_merge) {
/* Will need full_doubles_map for handling merge */
- full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map");
+ full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map");
copy_vn_i(full_doubles_map, result_nverts, -1);
}
@@ -608,6 +608,26 @@ static DerivedMesh *arrayModifier_doArray(
}
}
+ /* handle UVs */
+ if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) {
+ const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
+ for (i = 0; i < totuv; i++) {
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, i);
+ dmloopuv += chunk_nloops;
+ for (c = 1; c < count; c++) {
+ const float uv_offset[2] = {
+ amd->uv_offset[0] * (float)c,
+ amd->uv_offset[1] * (float)c,
+ };
+ int l_index = chunk_nloops;
+ for (; l_index-- != 0; dmloopuv++) {
+ dmloopuv->uv[0] += uv_offset[0];
+ dmloopuv->uv[1] += uv_offset[1];
+ }
+ }
+ }
+ }
+
last_chunk_start = (count - 1) * chunk_nverts;
last_chunk_nverts = chunk_nverts;
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 5811017f745..0554fbb0317 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -239,7 +239,7 @@ static DerivedMesh *applyModifier_bmesh(
int tottri;
BMLoop *(*looptris)[3];
- looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
+ looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 0a0ad11fe16..7a52ede8838 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -104,9 +104,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
MVert *mvert_src = dm->getVertArray(dm);
- vertMap = MEM_mallocN(sizeof(*vertMap) * numVert_src, "build modifier vertMap");
- edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap");
- faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap");
+ vertMap = MEM_malloc_arrayN(numVert_src, sizeof(*vertMap), "build modifier vertMap");
+ edgeMap = MEM_malloc_arrayN(numEdge_src, sizeof(*edgeMap), "build modifier edgeMap");
+ faceMap = MEM_malloc_arrayN(numPoly_src, sizeof(*faceMap), "build modifier faceMap");
range_vn_i(vertMap, numVert_src, 0);
range_vn_i(edgeMap, numEdge_src, 0);
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index b9a2310366a..d2ecbaeaafe 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -158,7 +158,7 @@ static void deformVerts(ModifierData *md, const struct EvaluationContext *UNUSED
{
const MLoop *mloop = dm->getLoopArray(dm);
const MLoopTri *looptri = dm->getLoopTriArray(dm);
- MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__);
+ MVertTri *tri = MEM_malloc_arrayN(collmd->tri_num, sizeof(*tri), __func__);
DM_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
collmd->tri = tri;
}
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 716b918d0f0..d95f0ae9286 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -156,7 +156,7 @@ static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
mpoly_num = (unsigned int)dm->getNumPolys(dm);
medge_num = (unsigned int)dm->getNumEdges(dm);
- boundaries = MEM_callocN(medge_num * sizeof(*boundaries), __func__);
+ boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
/* count the number of adjacent faces */
for (i = 0; i < mpoly_num; i++) {
@@ -199,9 +199,9 @@ static void smooth_iter__simple(
struct SmoothingData_Simple {
float delta[3];
- } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+ } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);
- vertex_edge_count_div = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
+ vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__);
/* calculate as floats to avoid int->float conversion in #smooth_iter */
for (i = 0; i < numEdges; i++) {
@@ -277,11 +277,11 @@ static void smooth_iter__length_weight(
struct SmoothingData_Weighted {
float delta[3];
float edge_length_sum;
- } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+ } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);
/* calculate as floats to avoid int->float conversion in #smooth_iter */
- vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
+ vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__);
for (i = 0; i < numEdges; i++) {
vertex_edge_count[edges[i].v1] += 1.0f;
vertex_edge_count[edges[i].v2] += 1.0f;
@@ -382,7 +382,7 @@ static void smooth_verts(
if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
- smooth_weights = MEM_mallocN(numVerts * sizeof(float), __func__);
+ smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__);
if (dvert) {
dm_get_weights(
@@ -530,7 +530,7 @@ static void calc_deltas(
float (*tangent_spaces)[3][3];
unsigned int i;
- tangent_spaces = MEM_callocN((size_t)(numVerts) * sizeof(float[3][3]), __func__);
+ tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
if (csmd->delta_cache_num != numVerts) {
MEM_SAFE_FREE(csmd->delta_cache);
@@ -539,7 +539,7 @@ static void calc_deltas(
/* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
if (!csmd->delta_cache) {
csmd->delta_cache_num = numVerts;
- csmd->delta_cache = MEM_mallocN((size_t)numVerts * sizeof(float[3]), __func__);
+ csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
}
smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts);
@@ -575,7 +575,7 @@ static void correctivesmooth_modifier_do(
const bool force_delta_cache_update =
/* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
- (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC));
+ (((ID *)ob->data)->recalc & ID_RECALC));
bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
MDeformVert *dvert = NULL;
@@ -680,7 +680,7 @@ static void correctivesmooth_modifier_do(
float (*tangent_spaces)[3][3];
/* calloc, since values are accumulated */
- tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);
+ tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
calc_tangent_spaces(dm, vertexCos, tangent_spaces);
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 078a3085fc7..83dcd7b9b89 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -142,7 +142,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
const unsigned int vert_tot = dm->getNumVerts(dm);
unsigned int i;
- vweights = MEM_mallocN(vert_tot * sizeof(float), __func__);
+ vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__);
if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
for (i = 0; i < vert_tot; i++) {
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index c9ccdc3b8c2..53a77b6fe38 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -187,7 +187,10 @@ typedef struct DisplaceUserdata {
float (*vert_clnors)[3];
} DisplaceUserdata;
-static void displaceModifier_do_task(void *userdata, const int iter)
+static void displaceModifier_do_task(
+ void *__restrict userdata,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
DisplaceUserdata *data = (DisplaceUserdata *)userdata;
DisplaceModifierData *dmd = data->dmd;
@@ -305,7 +308,7 @@ static void displaceModifier_do(
modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
if (dmd->texture) {
- tex_co = MEM_callocN(sizeof(*tex_co) * numVerts,
+ tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co),
"displaceModifier_do tex_co");
get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts);
@@ -326,7 +329,7 @@ static void displaceModifier_do(
}
clnors = CustomData_get_layer(ldata, CD_NORMAL);
- vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__);
+ vert_clnors = MEM_malloc_arrayN(numVerts, sizeof(*vert_clnors), __func__);
BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm),
(const float (*)[3])clnors, vert_clnors);
}
@@ -356,7 +359,13 @@ static void displaceModifier_do(
data.pool = BKE_image_pool_new();
BKE_texture_fetch_images_for_pool(dmd->texture, data.pool);
}
- BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, numVerts > 512);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numVerts > 512);
+ BLI_task_parallel_range(0, numVerts,
+ &data,
+ displaceModifier_do_task,
+ &settings);
if (data.pool != NULL) {
BKE_image_pool_free(data.pool);
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 38785abbc19..8483da60576 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -119,9 +119,9 @@ static void createFacepa(ExplodeModifierData *emd,
if (emd->facepa)
MEM_freeN(emd->facepa);
- facepa = emd->facepa = MEM_callocN(sizeof(int) * totface, "explode_facepa");
+ facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa");
- vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa");
+ vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa");
/* initialize all faces & verts to no particle */
for (i = 0; i < totface; i++)
@@ -557,8 +557,8 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
int totvert = dm->getNumVerts(dm);
int totface = dm->getNumTessFaces(dm);
- int *facesplit = MEM_callocN(sizeof(int) * totface, "explode_facesplit");
- int *vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa2");
+ int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit");
+ int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2");
int *facepa = emd->facepa;
int *fs, totesplit = 0, totfsplit = 0, curdupface = 0;
int i, v1, v2, v3, v4, esplit,
@@ -656,7 +656,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
* later interpreted as tri's, for this to work right I think we probably
* have to stop using tessface - campbell */
- facepa = MEM_callocN(sizeof(int) * (totface + (totfsplit * 2)), "explode_facepa");
+ facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa");
//memcpy(facepa, emd->facepa, totface*sizeof(int));
emd->facepa = facepa;
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 3684e947fe0..c9f475ad228 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -239,7 +239,7 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam
return NULL;
}
- normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals");
+ normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals");
if (!normals) {
if (dm)
dm->release(dm);
@@ -384,7 +384,7 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
if (fss->domainNovecgen > 0) return;
- fss->meshVelocities = MEM_callocN(sizeof(FluidVertexVelocity) * dm->getNumVerts(dm), "Fluidsim_velocities");
+ fss->meshVelocities = MEM_calloc_arrayN(dm->getNumVerts(dm), sizeof(FluidVertexVelocity), "Fluidsim_velocities");
fss->totvert = totvert;
velarray = fss->meshVelocities;
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index d322b8631d2..72db3f1c132 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -108,12 +108,12 @@ static LaplacianSystem *initLaplacianSystem(
sys->total_anchors = totalAnchors;
sys->repeat = iterations;
BLI_strncpy(sys->anchor_grp_name, defgrpName, sizeof(sys->anchor_grp_name));
- sys->co = MEM_mallocN(sizeof(float[3]) * totalVerts, "DeformCoordinates");
- sys->no = MEM_callocN(sizeof(float[3]) * totalVerts, "DeformNormals");
- sys->delta = MEM_callocN(sizeof(float[3]) * totalVerts, "DeformDeltas");
- sys->tris = MEM_mallocN(sizeof(int[3]) * totalTris, "DeformFaces");
- sys->index_anchors = MEM_mallocN(sizeof(int) * (totalAnchors), "DeformAnchors");
- sys->unit_verts = MEM_callocN(sizeof(int) * totalVerts, "DeformUnitVerts");
+ sys->co = MEM_malloc_arrayN(totalVerts, sizeof(float[3]), "DeformCoordinates");
+ sys->no = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformNormals");
+ sys->delta = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformDeltas");
+ sys->tris = MEM_malloc_arrayN(totalTris, sizeof(int[3]), "DeformFaces");
+ sys->index_anchors = MEM_malloc_arrayN((totalAnchors), sizeof(int), "DeformAnchors");
+ sys->unit_verts = MEM_calloc_arrayN(totalVerts, sizeof(int), "DeformUnitVerts");
return sys;
}
@@ -142,7 +142,7 @@ static void createFaceRingMap(
{
int i, j, totalr = 0;
int *indices, *index_iter;
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * mvert_tot, "DeformRingMap");
+ MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformRingMap");
const MLoopTri *mlt;
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
@@ -153,7 +153,7 @@ static void createFaceRingMap(
totalr++;
}
}
- indices = MEM_callocN(sizeof(int) * totalr, "DeformRingIndex");
+ indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformRingIndex");
index_iter = indices;
for (i = 0; i < mvert_tot; i++) {
map[i].indices = index_iter;
@@ -175,7 +175,7 @@ static void createVertRingMap(
const int mvert_tot, const MEdge *medge, const int medge_tot,
MeshElemMap **r_map, int **r_indices)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * mvert_tot, "DeformNeighborsMap");
+ MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformNeighborsMap");
int i, vid[2], totalr = 0;
int *indices, *index_iter;
const MEdge *me;
@@ -187,7 +187,7 @@ static void createVertRingMap(
map[vid[1]].count++;
totalr += 2;
}
- indices = MEM_callocN(sizeof(int) * totalr, "DeformNeighborsIndex");
+ indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformNeighborsIndex");
index_iter = indices;
for (i = 0; i < mvert_tot; i++) {
map[i].indices = index_iter;
@@ -521,7 +521,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh
LaplacianSystem *sys;
if (isValidVertexGroup(lmd, ob, dm)) {
- int *index_anchors = MEM_mallocN(sizeof(int) * numVerts, __func__); /* over-alloc */
+ int *index_anchors = MEM_malloc_arrayN(numVerts, sizeof(int), __func__); /* over-alloc */
const MLoopTri *mlooptri;
const MLoop *mloop;
@@ -547,7 +547,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh
memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors);
memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts);
MEM_freeN(index_anchors);
- lmd->vertexco = MEM_mallocN(sizeof(float[3]) * numVerts, "ModDeformCoordinates");
+ lmd->vertexco = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "ModDeformCoordinates");
memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts);
lmd->total_verts = numVerts;
@@ -631,7 +631,7 @@ static void LaplacianDeformModifier_do(
sys = lmd->cache_system;
if (sysdif) {
if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) {
- filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempModDeformCoordinates");
+ filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempModDeformCoordinates");
memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
MEM_SAFE_FREE(lmd->vertexco);
lmd->total_verts = 0;
@@ -667,7 +667,7 @@ static void LaplacianDeformModifier_do(
lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND;
}
else if (lmd->total_verts > 0 && lmd->total_verts == numVerts) {
- filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempDeformCoordinates");
+ filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempDeformCoordinates");
memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
MEM_SAFE_FREE(lmd->vertexco);
lmd->total_verts = 0;
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index d7bc7b6c427..977b8b41cc3 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -132,14 +132,14 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, in
sys->numLoops = a_numLoops;
sys->numVerts = a_numVerts;
- sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, __func__);
- sys->fweights = MEM_callocN(sizeof(float[3]) * sys->numLoops, __func__);
- sys->numNeEd = MEM_callocN(sizeof(short) * sys->numVerts, __func__);
- sys->numNeFa = MEM_callocN(sizeof(short) * sys->numVerts, __func__);
- sys->ring_areas = MEM_callocN(sizeof(float) * sys->numVerts, __func__);
- sys->vlengths = MEM_callocN(sizeof(float) * sys->numVerts, __func__);
- sys->vweights = MEM_callocN(sizeof(float) * sys->numVerts, __func__);
- sys->zerola = MEM_callocN(sizeof(short) * sys->numVerts, __func__);
+ sys->eweights = MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__);
+ sys->fweights = MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__);
+ sys->numNeEd = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
+ sys->numNeFa = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
+ sys->ring_areas = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
+ sys->vlengths = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
+ sys->vweights = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
+ sys->zerola = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
return sys;
}
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index d942b23b216..bcebbc40adb 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -162,7 +162,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
* - each cell is a boolean saying whether bone corresponding to the ith group is selected
* - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts)
*/
- bone_select_array = MEM_mallocN((size_t)defbase_tot * sizeof(char), "mask array");
+ bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array");
for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
pchan = BKE_pose_channel_find_name(oba->pose, def->name);
@@ -246,7 +246,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
mloop_src = dm->getLoopArray(dm);
/* overalloc, assume all polys are seen */
- loop_mapping = MEM_mallocN(sizeof(int) * (size_t)maxPolys, "mask loopmap");
+ loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap");
/* loop over edges and faces, and do the same thing to
* ensure that they only reference existing verts
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index c990951c578..5dfa1d874b2 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -94,7 +94,7 @@ static void meshcache_do(
{
const bool use_factor = mcmd->factor < 1.0f;
float (*vertexCos_Store)[3] = (use_factor || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ?
- MEM_mallocN(sizeof(*vertexCos_Store) * numVerts, __func__) : NULL;
+ MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_Store), __func__) : NULL;
float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real;
Scene *scene = mcmd->modifier.scene;
@@ -197,8 +197,8 @@ static void meshcache_do(
/* the moons align! */
int i;
- float (*vertexCos_Source)[3] = MEM_mallocN(sizeof(*vertexCos_Source) * numVerts, __func__);
- float (*vertexCos_New)[3] = MEM_mallocN(sizeof(*vertexCos_New) * numVerts, __func__);
+ float (*vertexCos_Source)[3] = MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_Source), __func__);
+ float (*vertexCos_New)[3] = MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_New), __func__);
MVert *mv = me->mvert;
for (i = 0; i < numVerts; i++, mv++) {
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index ab43204365d..da233a18d0a 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -215,7 +215,10 @@ typedef struct MeshdeformUserdata {
float (*icagemat)[3];
} MeshdeformUserdata;
-static void meshdeform_vert_task(void *userdata, const int iter)
+static void meshdeform_vert_task(
+ void *__restrict userdata,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
MeshdeformUserdata *data = userdata;
/*const*/ MeshDeformModifierData *mmd = data->mmd;
@@ -358,7 +361,7 @@ static void meshdeformModifier_do(
return;
}
- cagecos = MEM_mallocN(sizeof(*cagecos) * totcagevert, "meshdeformModifier vertCos");
+ cagecos = MEM_malloc_arrayN(totcagevert, sizeof(*cagecos), "meshdeformModifier vertCos");
/* setup deformation data */
cagedm->getVertCos(cagedm, cagecos);
@@ -367,7 +370,7 @@ static void meshdeformModifier_do(
/* We allocate 1 element extra to make it possible to
* load the values to SSE registers, which are float4.
*/
- dco = MEM_callocN(sizeof(*dco) * (totcagevert + 1), "MDefDco");
+ dco = MEM_calloc_arrayN((totcagevert + 1), sizeof(*dco), "MDefDco");
zero_v3(dco[totcagevert]);
for (a = 0; a < totcagevert; a++) {
/* get cage vertex in world space with binding transform */
@@ -394,7 +397,13 @@ static void meshdeformModifier_do(
data.icagemat = icagemat;
/* Do deformation. */
- BLI_task_parallel_range(0, totvert, &data, meshdeform_vert_task, totvert > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 16;
+ BLI_task_parallel_range(0, totvert,
+ &data,
+ meshdeform_vert_task,
+ &settings);
/* release cage derivedmesh */
MEM_freeN(dco);
@@ -458,8 +467,8 @@ void modifier_mdef_compact_influences(ModifierData *md)
}
/* allocate bind influences */
- mmd->bindinfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefBindInfluence");
- mmd->bindoffsets = MEM_callocN(sizeof(int) * (totvert + 1), "MDefBindOffset");
+ mmd->bindinfluences = MEM_calloc_arrayN(mmd->totinfluence, sizeof(MDefInfluence), "MDefBindInfluence");
+ mmd->bindoffsets = MEM_calloc_arrayN((totvert + 1), sizeof(int), "MDefBindOffset");
/* write influences */
totinfluence = 0;
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index db06dc43b8e..1b725e335a4 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -167,7 +167,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
if (do_vtargetmap) {
/* second half is filled with -1 */
- vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap");
+ vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
vtmap_a = vtargetmap;
vtmap_b = vtargetmap + maxVerts;
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 1c7c640b971..61a5b9bb03e 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -117,7 +117,7 @@ static void mix_normals(
int i;
if (dvert) {
- facs = MEM_mallocN(sizeof(*facs) * (size_t)num_loops, __func__);
+ facs = MEM_malloc_arrayN((size_t)num_loops, sizeof(*facs), __func__);
BKE_defvert_extract_vgroup_to_loopweights(
dvert, defgrp_index, num_verts, mloop, num_loops, facs, use_invert_vgroup);
}
@@ -195,8 +195,8 @@ static void normalEditModifier_do_radial(
{
int i;
- float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__);
- float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__);
+ float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__);
+ float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__);
float size[3];
BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
@@ -294,8 +294,8 @@ static void normalEditModifier_do_directional(
{
const bool use_parallel_normals = (enmd->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 (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__);
+ float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__);
float target_co[3];
int i;
@@ -434,7 +434,7 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *
polynors = dm->getPolyDataArray(dm, CD_NORMAL);
if (!polynors) {
- polynors = MEM_mallocN(sizeof(*polynors) * num_polys, __func__);
+ polynors = MEM_malloc_arrayN((size_t)num_polys, sizeof(*polynors), __func__);
BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false);
free_polynors = true;
}
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 189cfb8553e..b3a7ecaa138 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -261,7 +261,10 @@ typedef struct GenerateOceanGeometryData {
float ix, iy;
} GenerateOceanGeometryData;
-static void generate_ocean_geometry_vertices(void *userdata, const int y)
+static void generate_ocean_geometry_vertices(
+ void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
GenerateOceanGeometryData *gogd = userdata;
int x;
@@ -275,7 +278,10 @@ static void generate_ocean_geometry_vertices(void *userdata, const int y)
}
}
-static void generate_ocean_geometry_polygons(void *userdata, const int y)
+static void generate_ocean_geometry_polygons(
+ void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
GenerateOceanGeometryData *gogd = userdata;
int x;
@@ -305,7 +311,10 @@ static void generate_ocean_geometry_polygons(void *userdata, const int y)
}
}
-static void generate_ocean_geometry_uvs(void *userdata, const int y)
+static void generate_ocean_geometry_uvs(
+ void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
GenerateOceanGeometryData *gogd = userdata;
int x;
@@ -367,11 +376,15 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = use_threading;
+
/* create vertices */
- BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);
+ BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, &settings);
/* create faces */
- BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);
+ BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, &settings);
CDDM_calc_edges(result);
@@ -383,7 +396,7 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.ix = 1.0 / gogd.rx;
gogd.iy = 1.0 / gogd.ry;
- BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
+ BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, &settings);
}
}
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index de59635f335..09966da13a2 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -220,7 +220,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
if (pimd->flag & eParticleInstanceFlag_UseSize) {
float *si;
- si = size = MEM_callocN(totpart * sizeof(float), "particle size array");
+ si = size = MEM_calloc_arrayN(totpart, sizeof(float), "particle size array");
if (pimd->flag & eParticleInstanceFlag_Parents) {
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++)
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 010bf8bf092..979dc339e4e 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -139,7 +139,7 @@ static DerivedMesh *dm_remove_doubles_on_axis(
if (tot_doubles != 0) {
uint tot = totvert * step_tot;
- int *full_doubles_map = MEM_mallocN(sizeof(int) * tot, __func__);
+ int *full_doubles_map = MEM_malloc_arrayN(tot, sizeof(int), __func__);
copy_vn_i(full_doubles_map, (int)tot, -1);
uint tot_doubles_left = tot_doubles;
@@ -448,10 +448,10 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
mpoly_orig = dm->getPolyArray(dm);
mloop_orig = dm->getLoopArray(dm);
- edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__);
+ edge_poly_map = MEM_malloc_arrayN(totedge, sizeof(*edge_poly_map), __func__);
memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge);
- vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__);
+ vert_loop_map = MEM_malloc_arrayN(totvert, sizeof(*vert_loop_map), __func__);
memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);
for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
@@ -497,7 +497,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
* This makes the modifier faster with one less alloc.
*/
- vert_connect = MEM_mallocN(sizeof(ScrewVertConnect) * totvert, "ScrewVertConnect");
+ vert_connect = MEM_malloc_arrayN(totvert, sizeof(ScrewVertConnect), "ScrewVertConnect");
//vert_connect = (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */
vc = vert_connect;
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 146e882a6b6..6116e49d07d 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -32,7 +32,6 @@
* \ingroup modifiers
*/
-
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -48,9 +47,33 @@
#define BEND_EPS 0.000001f
+/* Re-maps the indicies for X Y Z by shifting them up and wrapping, such that
+ * X = Y, Y = Z, Z = X (for X axis), and X = Z, Y = X, Z = Y (for Y axis). This
+ * exists because the deformations (excluding bend) are based on the Z axis.
+ * Having this helps avoid long, drawn out switches. */
+static const uint axis_map_table[3][3] = {
+ {1, 2, 0},
+ {2, 0, 1},
+ {0, 1, 2},
+};
+
+BLI_INLINE void copy_v3_v3_map(float a[3], const float b[3], const uint map[3])
+{
+ a[0] = b[map[0]];
+ a[1] = b[map[1]];
+ a[2] = b[map[2]];
+}
+
+BLI_INLINE void copy_v3_v3_unmap(float a[3], const float b[3], const uint map[3])
+{
+ a[map[0]] = b[0];
+ a[map[1]] = b[1];
+ a[map[2]] = b[2];
+}
+
/* Clamps/Limits the given coordinate to: limits[0] <= co[axis] <= limits[1]
* The amount of clamp is saved on dcut */
-static void axis_limit(int axis, const float limits[2], float co[3], float dcut[3])
+static void axis_limit(const int axis, const float limits[2], float co[3], float dcut[3])
{
float val = co[axis];
if (limits[0] > val) val = limits[0];
@@ -60,7 +83,7 @@ static void axis_limit(int axis, const float limits[2], float co[3], float dcut[
co[axis] = val;
}
-static void simpleDeform_taper(const float factor, const float dcut[3], float r_co[3])
+static void simpleDeform_taper(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3])
{
float x = r_co[0], y = r_co[1], z = r_co[2];
float scale = z * factor;
@@ -69,14 +92,10 @@ static void simpleDeform_taper(const float factor, const float dcut[3], float r_
r_co[1] = y + y * scale;
r_co[2] = z;
- {
- r_co[0] += dcut[0];
- r_co[1] += dcut[1];
- r_co[2] += dcut[2];
- }
+ add_v3_v3(r_co, dcut);
}
-static void simpleDeform_stretch(const float factor, const float dcut[3], float r_co[3])
+static void simpleDeform_stretch(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3])
{
float x = r_co[0], y = r_co[1], z = r_co[2];
float scale;
@@ -87,14 +106,10 @@ static void simpleDeform_stretch(const float factor, const float dcut[3], float
r_co[1] = y * scale;
r_co[2] = z * (1.0f + factor);
- {
- r_co[0] += dcut[0];
- r_co[1] += dcut[1];
- r_co[2] += dcut[2];
- }
+ add_v3_v3(r_co, dcut);
}
-static void simpleDeform_twist(const float factor, const float *dcut, float r_co[3])
+static void simpleDeform_twist(const float factor, const int UNUSED(axis), const float *dcut, float r_co[3])
{
float x = r_co[0], y = r_co[1], z = r_co[2];
float theta, sint, cost;
@@ -107,32 +122,58 @@ static void simpleDeform_twist(const float factor, const float *dcut, float r_co
r_co[1] = x * sint + y * cost;
r_co[2] = z;
- {
- r_co[0] += dcut[0];
- r_co[1] += dcut[1];
- r_co[2] += dcut[2];
- }
+ add_v3_v3(r_co, dcut);
}
-static void simpleDeform_bend(const float factor, const float dcut[3], float r_co[3])
+static void simpleDeform_bend(const float factor, const int axis, const float dcut[3], float r_co[3])
{
float x = r_co[0], y = r_co[1], z = r_co[2];
float theta, sint, cost;
BLI_assert(!(fabsf(factor) < BEND_EPS));
- theta = x * factor;
+ switch (axis) {
+ case 0:
+ ATTR_FALLTHROUGH;
+ case 1:
+ theta = z * factor;
+ break;
+ default:
+ theta = x * factor;
+ }
sint = sinf(theta);
cost = cosf(theta);
- r_co[0] = -(y - 1.0f / factor) * sint;
- r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor;
- r_co[2] = z;
-
- {
- r_co[0] += cost * dcut[0];
- r_co[1] += sint * dcut[0];
- r_co[2] += dcut[2];
+ switch (axis) {
+ case 0:
+ r_co[0] = x;
+ r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor;
+ r_co[2] = -(y - 1.0f / factor) * sint;
+ {
+ r_co[0] += dcut[0];
+ r_co[1] += sint * dcut[2];
+ r_co[2] += cost * dcut[2];
+ }
+ break;
+ case 1:
+ r_co[0] = (x - 1.0f / factor) * cost + 1.0f / factor;
+ r_co[1] = y;
+ r_co[2] = -(x - 1.0f / factor) * sint;
+ {
+ r_co[0] += sint * dcut[2];
+ r_co[1] += dcut[1];
+ r_co[2] += cost * dcut[2];
+ }
+ break;
+ default:
+ r_co[0] = -(y - 1.0f / factor) * sint;
+ r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor;
+ r_co[2] = z;
+ {
+ r_co[0] += cost * dcut[0];
+ r_co[1] += sint * dcut[0];
+ r_co[2] += dcut[2];
+ }
}
}
@@ -142,16 +183,36 @@ static void simpleDeform_bend(const float factor, const float dcut[3], float r_c
static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
- static const float lock_axis[2] = {0.0f, 0.0f};
+ const float base_limit[2] = {0.0f, 0.0f};
int i;
- int limit_axis = 0;
float smd_limit[2], smd_factor;
SpaceTransform *transf = NULL, tmp_transf;
- void (*simpleDeform_callback)(const float factor, const float dcut[3], float co[3]) = NULL; /* Mode callback */
+ void (*simpleDeform_callback)(const float factor, const int axis, const float dcut[3], float co[3]) = NULL; /* Mode callback */
int vgroup;
MDeformVert *dvert;
+ /* This is historically the lock axis, _not_ the deform axis as the name would imply */
+ const int deform_axis = smd->deform_axis;
+ int lock_axis = smd->axis;
+ if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouln't have any lock axis */
+ lock_axis = 0;
+ }
+ else {
+ /* Don't lock axis if it is the chosen deform axis, as this flattens
+ * the geometry */
+ if (deform_axis == 0) {
+ lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X;
+ }
+ if (deform_axis == 1) {
+ lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y;
+ }
+ if (deform_axis == 2) {
+ lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z;
+ }
+ }
+
+
/* Safe-check */
if (smd->origin == ob) smd->origin = NULL; /* No self references */
@@ -166,11 +227,21 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin);
}
- /* Setup vars,
- * Bend limits on X.. all other modes limit on Z */
- limit_axis = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2;
-
/* Update limits if needed */
+ int limit_axis = deform_axis;
+ if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
+ /* Bend is a special case. */
+ switch (deform_axis) {
+ case 0:
+ ATTR_FALLTHROUGH;
+ case 1:
+ limit_axis = 2;
+ break;
+ default:
+ limit_axis = 0;
+ }
+ }
+
{
float lower = FLT_MAX;
float upper = -FLT_MAX;
@@ -212,6 +283,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup);
const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
+ const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2];
for (i = 0; i < numVerts; i++) {
float weight = defvert_array_find_weight_safe(dvert, i, vgroup);
@@ -229,14 +301,26 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
copy_v3_v3(co, vertexCos[i]);
- /* Apply axis limits */
- if (smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shoulnt have any lock axis */
- if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut);
- if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut);
+ /* Apply axis limits, and axis mappings */
+ if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
+ axis_limit(0, base_limit, co, dcut);
+ }
+ if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
+ axis_limit(1, base_limit, co, dcut);
+ }
+ if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
+ axis_limit(2, base_limit, co, dcut);
}
axis_limit(limit_axis, smd_limit, co, dcut);
- simpleDeform_callback(smd_factor, dcut, co); /* apply deform */
+ /* apply the deform to a mapped copy of the vertex, and then re-map it back. */
+ float co_remap[3];
+ float dcut_remap[3];
+ copy_v3_v3_map(co_remap, co, axis_map);
+ copy_v3_v3_map(dcut_remap, dcut, axis_map);
+ simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */
+ copy_v3_v3_unmap(co, co_remap, axis_map);
+
interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */
if (transf) {
@@ -254,6 +338,7 @@ static void initData(ModifierData *md)
smd->mode = MOD_SIMPLEDEFORM_MODE_TWIST;
smd->axis = 0;
+ smd->deform_axis = 0;
smd->origin = NULL;
smd->factor = DEG2RADF(45.0f);
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 9d1c6913c1c..97afe6d5e87 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -419,7 +419,7 @@ static Frame **collect_hull_frames(int v, SkinNode *frames,
int nbr, i;
(*tothullframe) = emap[v].count;
- hull_frames = MEM_callocN(sizeof(Frame *) * (*tothullframe),
+ hull_frames = MEM_calloc_arrayN((*tothullframe), sizeof(Frame *),
"hull_from_frames.hull_frames");
i = 0;
for (nbr = 0; nbr < emap[v].count; nbr++) {
@@ -600,7 +600,7 @@ static SkinNode *build_frames(const MVert *mvert, int totvert,
SkinNode *skin_nodes;
int v;
- skin_nodes = MEM_callocN(sizeof(SkinNode) * totvert, "build_frames.skin_nodes");
+ skin_nodes = MEM_calloc_arrayN(totvert, sizeof(SkinNode), "build_frames.skin_nodes");
for (v = 0; v < totvert; v++) {
if (emap[v].count <= 1)
@@ -722,7 +722,7 @@ static EMat *build_edge_mats(const MVertSkin *vs,
stack = BLI_stack_new(sizeof(stack_elem), "build_edge_mats.stack");
visited_e = BLI_BITMAP_NEW(totedge, "build_edge_mats.visited_e");
- emat = MEM_callocN(sizeof(EMat) * totedge, "build_edge_mats.emat");
+ emat = MEM_calloc_arrayN(totedge, sizeof(EMat), "build_edge_mats.emat");
/* Edge matrices are built from the root nodes, add all roots with
* children to the stack */
@@ -836,14 +836,14 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig)
totorigedge = orig->getNumEdges(orig);
/* Get degree of all vertices */
- degree = MEM_callocN(sizeof(int) * totorigvert, "degree");
+ degree = MEM_calloc_arrayN(totorigvert, sizeof(int), "degree");
for (i = 0; i < totorigedge; i++) {
degree[origedge[i].v1]++;
degree[origedge[i].v2]++;
}
/* Per edge, store how many subdivisions are needed */
- edge_subd = MEM_callocN(sizeof(int) * totorigedge, "edge_subd");
+ edge_subd = MEM_calloc_arrayN(totorigedge, sizeof(int), "edge_subd");
for (i = 0, totsubd = 0; i < totorigedge; i++) {
edge_subd[i] += calc_edge_subdivisions(origvert, orignode,
&origedge[i], degree);
@@ -882,7 +882,7 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig)
if (origdvert) {
const MDeformVert *dv1 = &origdvert[e->v1];
const MDeformVert *dv2 = &origdvert[e->v2];
- vgroups = MEM_callocN(sizeof(*vgroups) * dv1->totweight, "vgroup");
+ vgroups = MEM_calloc_arrayN(dv1->totweight, sizeof(*vgroups), "vgroup");
/* Only want vertex groups used by both vertices */
for (j = 0; j < dv1->totweight; j++) {
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index be55030e18a..91c724cd1c9 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -102,10 +102,10 @@ static void smoothModifier_do(
unsigned char *uctmp;
float *ftmp, fac, facm;
- ftmp = (float *)MEM_callocN(3 * sizeof(float) * numVerts,
+ ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float),
"smoothmodifier_f");
if (!ftmp) return;
- uctmp = (unsigned char *)MEM_callocN(sizeof(unsigned char) * numVerts,
+ uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char),
"smoothmodifier_uc");
if (!uctmp) {
if (ftmp) MEM_freeN(ftmp);
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 14b29855728..5635d37f100 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -101,7 +101,7 @@ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_ver
mp = mpoly;
{
- EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity");
+ EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN((size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity");
EdgeFaceRef *edge_ref;
float edge_normal[3];
@@ -235,7 +235,7 @@ static DerivedMesh *applyModifier(
unsigned int *new_edge_arr = NULL;
STACK_DECLARE(new_edge_arr);
- unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify");
+ unsigned int *old_vert_arr = MEM_calloc_arrayN(numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
unsigned int *edge_users = NULL;
char *edge_order = NULL;
@@ -270,7 +270,7 @@ static DerivedMesh *applyModifier(
if (need_face_normals) {
/* calculate only face normals */
- face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__);
+ face_nors = MEM_malloc_arrayN(numFaces, sizeof(*face_nors), __func__);
BKE_mesh_calc_normals_poly(
orig_mvert, NULL, (int)numVerts,
orig_mloop, orig_mpoly,
@@ -289,11 +289,11 @@ static DerivedMesh *applyModifier(
#define INVALID_UNUSED ((unsigned int)-1)
#define INVALID_PAIR ((unsigned int)-2)
- new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__);
- new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__);
+ new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
+ new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
- edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges");
- edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder");
+ edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
+ edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder");
/* save doing 2 loops here... */
@@ -366,7 +366,7 @@ static DerivedMesh *applyModifier(
}
if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
- vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq");
+ vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq");
dm_calc_normal(dm, face_nors, vert_nors);
}
@@ -517,7 +517,7 @@ static DerivedMesh *applyModifier(
if (do_clamp) {
unsigned int i;
- vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
+ vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
for (i = 0; i < numEdges; i++) {
const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
@@ -596,13 +596,13 @@ static DerivedMesh *applyModifier(
const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
#endif
/* same as EM_solidify() in editmesh_lib.c */
- float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
+ float *vert_angles = MEM_calloc_arrayN(numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */
float *vert_accum = vert_angles + numVerts;
unsigned int vidx;
unsigned int i;
if (vert_nors == NULL) {
- vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
+ vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno");
for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
normal_short_to_float_v3(vert_nors[i], mv->no);
}
@@ -682,7 +682,7 @@ static DerivedMesh *applyModifier(
}
if (do_clamp) {
- float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
+ float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const float offset_sq = offset * offset;
copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
@@ -765,7 +765,7 @@ static DerivedMesh *applyModifier(
#ifdef SOLIDIFY_SIDE_NORMALS
const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS);
/* annoying to allocate these since we only need the edge verts, */
- float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL;
+ float (*edge_vert_nos)[3] = do_side_normals ? MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) : NULL;
float nor[3];
#endif
const unsigned char crease_rim = smd->crease_rim * 255.0f;
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index c408b4fbd63..bef35ccf1fe 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -130,8 +130,8 @@ static void deformVerts(ModifierData *md, const struct EvaluationContext *UNUSED
surmd->v = NULL;
}
- surmd->x = MEM_callocN(numverts * sizeof(MVert), "MVert");
- surmd->v = MEM_callocN(numverts * sizeof(MVert), "MVert");
+ surmd->x = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert");
+ surmd->v = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert");
surmd->numverts = numverts;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index b623293ed5c..046a0ab27bf 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -314,11 +314,13 @@ BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr)
copy_v2_v2(prev_co, coords[nr - 1]);
sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]);
+ normalize_v2(prev_vec);
for (int i = 0; i < nr; i++) {
sub_v2_v2v2(curr_vec, coords[i], prev_co);
- if (len_squared_v2(curr_vec) < FLT_EPSILON) {
+ const float curr_len = normalize_v2(curr_vec);
+ if (curr_len < FLT_EPSILON) {
return MOD_SDEF_BIND_RESULT_OVERLAP_ERR;
}
@@ -386,7 +388,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data,
bwdata->numpoly = data->vert_edges[nearest].num / 2;
- bpoly = MEM_callocN(sizeof(*bpoly) * bwdata->numpoly, "SDefBindPoly");
+ bpoly = MEM_calloc_arrayN(bwdata->numpoly, sizeof(*bpoly), "SDefBindPoly");
if (bpoly == NULL) {
freeBindData(bwdata);
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
@@ -429,14 +431,14 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data,
bpoly->numverts = poly->totloop;
bpoly->loopstart = poly->loopstart;
- bpoly->coords = MEM_mallocN(sizeof(*bpoly->coords) * poly->totloop, "SDefBindPolyCoords");
+ bpoly->coords = MEM_malloc_arrayN(poly->totloop, sizeof(*bpoly->coords), "SDefBindPolyCoords");
if (bpoly->coords == NULL) {
freeBindData(bwdata);
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return NULL;
}
- bpoly->coords_v2 = MEM_mallocN(sizeof(*bpoly->coords_v2) * poly->totloop, "SDefBindPolyCoords_v2");
+ bpoly->coords_v2 = MEM_malloc_arrayN(poly->totloop, sizeof(*bpoly->coords_v2), "SDefBindPolyCoords_v2");
if (bpoly->coords_v2 == NULL) {
freeBindData(bwdata);
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
@@ -734,7 +736,10 @@ BLI_INLINE float computeNormalDisplacement(const float point_co[3], const float
return normal_dist;
}
-static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+static void bindVert(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SDefBindCalcData * const data = (SDefBindCalcData *)userdata;
float point_co[3];
@@ -760,7 +765,7 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind
return;
}
- sdvert->binds = MEM_callocN(sizeof(*sdvert->binds) * bwdata->numbinds, "SDefVertBindData");
+ sdvert->binds = MEM_calloc_arrayN(bwdata->numbinds, sizeof(*sdvert->binds), "SDefVertBindData");
if (sdvert->binds == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
sdvert->numbinds = 0;
@@ -782,13 +787,13 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind
sdbind->numverts = bpoly->numverts;
sdbind->mode = MOD_SDEF_MODE_NGON;
- sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * bpoly->numverts, "SDefNgonVertWeights");
+ sdbind->vert_weights = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_weights), "SDefNgonVertWeights");
if (sdbind->vert_weights == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return;
}
- sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefNgonVertInds");
+ sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefNgonVertInds");
if (sdbind->vert_inds == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return;
@@ -818,13 +823,13 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind
sdbind->numverts = bpoly->numverts;
sdbind->mode = MOD_SDEF_MODE_CENTROID;
- sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefCentVertWeights");
+ sdbind->vert_weights = MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefCentVertWeights");
if (sdbind->vert_weights == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return;
}
- sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefCentVertInds");
+ sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefCentVertInds");
if (sdbind->vert_inds == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return;
@@ -861,13 +866,13 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind
sdbind->numverts = bpoly->numverts;
sdbind->mode = MOD_SDEF_MODE_LOOPTRI;
- sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefTriVertWeights");
+ sdbind->vert_weights = MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefTriVertWeights");
if (sdbind->vert_weights == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return;
}
- sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefTriVertInds");
+ sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefTriVertInds");
if (sdbind->vert_inds == NULL) {
data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
return;
@@ -918,20 +923,20 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)
SDefAdjacency *adj_array;
SDefEdgePolys *edge_polys;
- vert_edges = MEM_callocN(sizeof(*vert_edges) * tnumverts, "SDefVertEdgeMap");
+ vert_edges = MEM_calloc_arrayN(tnumverts, sizeof(*vert_edges), "SDefVertEdgeMap");
if (vert_edges == NULL) {
modifier_setError((ModifierData *)smd, "Out of memory");
return false;
}
- adj_array = MEM_mallocN(sizeof(*adj_array) * tnumedges * 2, "SDefVertEdge");
+ adj_array = MEM_malloc_arrayN(tnumedges, 2 * sizeof(*adj_array), "SDefVertEdge");
if (adj_array == NULL) {
modifier_setError((ModifierData *)smd, "Out of memory");
MEM_freeN(vert_edges);
return false;
}
- edge_polys = MEM_callocN(sizeof(*edge_polys) * tnumedges, "SDefEdgeFaceMap");
+ edge_polys = MEM_calloc_arrayN(tnumedges, sizeof(*edge_polys), "SDefEdgeFaceMap");
if (edge_polys == NULL) {
modifier_setError((ModifierData *)smd, "Out of memory");
MEM_freeN(vert_edges);
@@ -939,7 +944,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)
return false;
}
- smd->verts = MEM_mallocN(sizeof(*smd->verts) * numverts, "SDefBindVerts");
+ smd->verts = MEM_malloc_arrayN(numverts, sizeof(*smd->verts), "SDefBindVerts");
if (smd->verts == NULL) {
modifier_setError((ModifierData *)smd, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
@@ -976,7 +981,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)
.medge = medge,
.mloop = mloop,
.looptri = tdm->getLoopTriArray(tdm),
- .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetBindVertArray"),
+ .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetBindVertArray"),
.bind_verts = smd->verts,
.vertexCos = vertexCos,
.falloff = smd->falloff,
@@ -994,8 +999,13 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)
mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
}
- BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, bindVert,
- numverts > 10000, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numverts > 10000);
+ BLI_task_parallel_range(0, numverts,
+ &data,
+ bindVert,
+ &settings);
MEM_freeN(data.targetCos);
@@ -1030,7 +1040,10 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)
return data.success == 1;
}
-static void deformVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+static void deformVert(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const SDefDeformData * const data = (SDefDeformData *)userdata;
const SDefBind *sdbind = data->bind_verts[index].binds;
@@ -1041,7 +1054,7 @@ static void deformVert(void *userdata, void *UNUSED(userdata_chunk), const int i
for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) {
/* Mode-generic operations (allocate poly coordinates) */
- float (*coords)[3] = MEM_mallocN(sizeof(*coords) * sdbind->numverts, "SDefDoPolyCoords");
+ float (*coords)[3] = MEM_malloc_arrayN(sdbind->numverts, sizeof(*coords), "SDefDoPolyCoords");
for (int k = 0; k < sdbind->numverts; k++) {
copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]);
@@ -1139,7 +1152,7 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
/* Actual vertex location update starts here */
SDefDeformData data = {
.bind_verts = smd->verts,
- .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetVertArray"),
+ .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetVertArray"),
.vertexCos = vertexCos,
};
@@ -1151,8 +1164,13 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
}
- BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, deformVert,
- numverts > 10000, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numverts > 10000);
+ BLI_task_parallel_range(0, numverts,
+ &data,
+ deformVert,
+ &settings);
if (tdm_vert_alloc) {
MEM_freeN((void *)mvert);
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index ded1f0b77e6..5b19bcf4817 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -87,7 +87,7 @@ void get_texture_coords(MappingInfoModifierData *dmd, Object *ob,
MPoly *mpoly = dm->getPolyArray(dm);
MPoly *mp;
MLoop *mloop = dm->getLoopArray(dm);
- char *done = MEM_callocN(sizeof(*done) * numVerts,
+ char *done = MEM_calloc_arrayN(numVerts, sizeof(*done),
"get_texture_coords done");
int numPolys = dm->getNumPolys(dm);
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index c9a842621b6..498dd2486f4 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -226,7 +226,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
numVerts = dm->getNumVerts(dm);
- coords = MEM_mallocN(sizeof(*coords) * numVerts,
+ coords = MEM_malloc_arrayN(numVerts, sizeof(*coords),
"uvprojectModifier_do coords");
dm->getVertCos(dm, coords);
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 3773eed26dc..32974d68d9d 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -110,7 +110,10 @@ typedef struct UVWarpData {
int axis_v;
} UVWarpData;
-static void uv_warp_compute(void *userdata, const int i)
+static void uv_warp_compute(
+ void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
const UVWarpData *data = userdata;
@@ -208,7 +211,13 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv,
.dvert = dvert, .defgrp_index = defgrp_index,
.warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v};
- BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numPolys > 1000);
+ BLI_task_parallel_range(0, numPolys,
+ &data,
+ uv_warp_compute,
+ &settings);
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 566ee5b2d24..be0be2671b9 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -214,7 +214,7 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob,
weight = strength;
if (wmd->texture) {
- tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co");
+ tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
modifier_init_texture(wmd->modifier.scene, wmd->texture);
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index c408f244afd..1271cccd719 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -206,7 +206,7 @@ static void waveModifier_do(WaveModifierData *md,
}
if (wmd->texture) {
- tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
+ tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co),
"waveModifier_do tex_co");
get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index da7230ed5af..416f2964d6e 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -143,9 +143,9 @@ void weightvg_do_mask(int num, const int *indices, float *org_w, const float *ne
t_map.map_object = tex_map_object;
BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
t_map.texmapping = tex_mapping;
- v_co = MEM_mallocN(sizeof(*v_co) * numVerts, "WeightVG Modifier, TEX mode, v_co");
+ v_co = MEM_malloc_arrayN(numVerts, sizeof(*v_co), "WeightVG Modifier, TEX mode, v_co");
dm->getVertCos(dm, v_co);
- tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "WeightVG Modifier, TEX mode, tex_co");
+ tex_co = MEM_calloc_arrayN(numVerts, sizeof(*tex_co), "WeightVG Modifier, TEX mode, tex_co");
get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
MEM_freeN(v_co);
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index dbdaafaa5a7..9aa4bad1707 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -213,9 +213,9 @@ static DerivedMesh *applyModifier(ModifierData *md,
}
/* Get org weights, assuming 0.0 for vertices not in given vgroup. */
- org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
- new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, new_w");
- dw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGEdit Modifier, dw");
+ org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w");
+ new_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, new_w");
+ dw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGEdit Modifier, dw");
for (i = 0; i < numVerts; i++) {
dw[i] = defvert_find_index(&dvert[i], defgrp_index);
if (dw[i]) {
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 5f30d4ca72a..ab1264cc9a0 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -265,9 +265,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
return dm;
}
/* Find out which vertices to work on. */
- tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx");
- tdw1 = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGMix Modifier, tdw1");
- tdw2 = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGMix Modifier, tdw2");
+ tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx");
+ tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1");
+ tdw2 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw2");
switch (wmd->mix_set) {
case MOD_WVG_SET_A:
/* All vertices in first vgroup. */
@@ -333,12 +333,12 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
return dm;
}
if (numIdx != -1) {
- indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices");
+ indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices");
memcpy(indices, tidx, sizeof(int) * numIdx);
- dw1 = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGMix Modifier, dw1");
+ dw1 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw1");
memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx);
MEM_freeN(tdw1);
- dw2 = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGMix Modifier, dw2");
+ dw2 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw2");
memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx);
MEM_freeN(tdw2);
}
@@ -351,8 +351,8 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
}
MEM_freeN(tidx);
- org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w");
- new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w");
+ org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, org_w");
+ new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, new_w");
/* Mix weights. */
for (i = 0; i < numIdx; i++) {
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index c8bbbfe44b2..8a5d0f833a8 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -90,10 +90,13 @@ typedef struct Vert2GeomDataChunk {
/**
* Callback used by BLI_task 'for loop' helper.
*/
-static void vert2geom_task_cb_ex(void *userdata, void *userdata_chunk, const int iter, const int UNUSED(thread_id))
+static void vert2geom_task_cb_ex(
+ void *__restrict userdata,
+ const int iter,
+ const ParallelRangeTLS *__restrict tls)
{
Vert2GeomData *data = userdata;
- Vert2GeomDataChunk *data_chunk = userdata_chunk;
+ Vert2GeomDataChunk *data_chunk = tls->userdata_chunk;
float tmp_co[3];
int i;
@@ -177,9 +180,16 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
data.dist[1] = dist_e;
data.dist[2] = dist_f;
- BLI_task_parallel_range_ex(
- 0, numVerts, &data, &data_chunk, sizeof(data_chunk), vert2geom_task_cb_ex,
- numVerts > 10000, false);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numVerts > 10000);
+ settings.userdata_chunk = &data_chunk;
+ settings.userdata_chunk_size = sizeof(data_chunk);
+ BLI_task_parallel_range(
+ 0, numVerts,
+ &data,
+ vert2geom_task_cb_ex,
+ &settings);
if (dist_v)
free_bvhtree_from_mesh(&treeData_v);
@@ -423,9 +433,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
/* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight.
*/
- tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx");
- tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw");
- tdw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGProximity Modifier, tdw");
+ tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx");
+ tw = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGProximity Modifier, tw");
+ tdw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGProximity Modifier, tdw");
for (i = 0; i < numVerts; i++) {
MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_index);
if (_dw) {
@@ -442,11 +452,11 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
return dm;
}
if (numIdx != numVerts) {
- indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices");
+ indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGProximity Modifier, indices");
memcpy(indices, tidx, sizeof(int) * numIdx);
- org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w");
+ org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, org_w");
memcpy(org_w, tw, sizeof(float) * numIdx);
- dw = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGProximity Modifier, dw");
+ dw = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGProximity Modifier, dw");
memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx);
MEM_freeN(tw);
MEM_freeN(tdw);
@@ -455,16 +465,16 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
org_w = tw;
dw = tdw;
}
- new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w");
+ new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, new_w");
MEM_freeN(tidx);
/* Get our vertex coordinates. */
- v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos");
+ v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos");
if (numIdx != numVerts) {
/* XXX In some situations, this code can be up to about 50 times more performant
* than simply using getVertCo for each affected vertex...
*/
- float (*tv_cos)[3] = MEM_mallocN(sizeof(float[3]) * numVerts, "WeightVGProximity Modifier, tv_cos");
+ float (*tv_cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "WeightVGProximity Modifier, tv_cos");
dm->getVertCos(dm, tv_cos);
for (i = 0; i < numIdx; i++)
copy_v3_v3(v_cos[i], tv_cos[indices[i]]);
@@ -503,9 +513,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
/* We must check that we do have a valid target_dm! */
if (target_dm) {
SpaceTransform loc2trgt;
- float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "dists_v") : NULL;
- float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL;
- float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL;
+ float *dists_v = use_trgt_verts ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_v") : NULL;
+ float *dists_e = use_trgt_edges ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_e") : NULL;
+ float *dists_f = use_trgt_faces ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_f") : NULL;
BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr);
get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 6fc1907ba0a..3cb35286114 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -52,11 +52,6 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
}
-static bool isDisabled(ModifierData *UNUSED(md), int UNUSED(useRenderParams))
-{
- return false;
-}
-
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WireframeModifierData *wmd = (WireframeModifierData *)md;
@@ -132,8 +127,8 @@ ModifierTypeInfo modifierType_Wireframe = {
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
- /* isDisabled */ isDisabled,
- /* updateDepsgraph */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a6e04510b03..c83daa185a8 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -194,6 +194,7 @@ set(SRC
shader/nodes/node_shader_subsurface_scattering.c
shader/nodes/node_shader_tangent.c
shader/nodes/node_shader_bevel.c
+ shader/nodes/node_shader_displacement.c
shader/nodes/node_shader_tex_brick.c
shader/nodes/node_shader_tex_checker.c
shader/nodes/node_shader_tex_coord.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 62a92e8d084..cbdfd8d3dbf 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -79,6 +79,7 @@ void register_node_type_sh_tex_pointdensity(void);
void register_node_type_sh_attribute(void);
void register_node_type_sh_bevel(void);
+void register_node_type_sh_displacement(void);
void register_node_type_sh_geometry(void);
void register_node_type_sh_light_path(void);
void register_node_type_sh_light_falloff(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index a18ee154af8..e2c1fae1bde 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -128,6 +128,7 @@ DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UV
DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" )
DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" )
DefNode( ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" )
+DefNode( ShaderNode, SH_NODE_DISPLACEMENT, 0, "DISPLACEMENT", Displacement, "Displacement", "" )
DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
diff --git a/source/blender/nodes/composite/node_composite_util.h b/source/blender/nodes/composite/node_composite_util.h
index 2dac0cc639a..22c5e6f9507 100644
--- a/source/blender/nodes/composite/node_composite_util.h
+++ b/source/blender/nodes/composite/node_composite_util.h
@@ -42,6 +42,7 @@
#include "BLT_translation.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
#include "BKE_texture.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
index 952ba78aff3..124e33d186f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
@@ -37,8 +37,8 @@
static bNodeSocketTemplate cmp_node_hue_sat_in[] = {
{ SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ -1, 0, "" }
};
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index bd7c4df317f..7712d7d0e71 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -341,6 +341,7 @@ void register_node_type_cmp_image(void)
node_type_init(&ntype, node_composit_init_image);
node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image);
node_type_update(&ntype, cmp_node_image_update, NULL);
+ node_type_label(&ntype, node_image_label);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
index 32d68550cd4..707f1d22efd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
@@ -46,7 +46,7 @@ static bNodeSocketTemplate cmp_node_valtorgb_out[] = {
static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_colorband(true);
+ node->storage = BKE_colorband_add(true);
}
void register_node_type_cmp_valtorgb(void)
diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c
index 382492707ce..e1d17003ba4 100644
--- a/source/blender/nodes/intern/node_socket.c
+++ b/source/blender/nodes/intern/node_socket.c
@@ -112,22 +112,21 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in
break;
}
if (sock) {
- sock->type = stemp->type;
+ if (sock->type != stemp->type) {
+ nodeModifySocketType(ntree, node, sock, stemp->type, stemp->subtype);
+ }
+
sock->limit = (stemp->limit == 0 ? 0xFFF : stemp->limit);
sock->flag |= stemp->flag;
-
- BLI_remlink(socklist, sock);
-
- return sock;
}
else {
/* no socket for this template found, make a new one */
sock = node_add_socket_from_template(ntree, node, stemp, in_out);
- /* remove the new socket from the node socket list first,
- * will be added back after verification.
- */
- BLI_remlink(socklist, sock);
}
+
+ /* remove the new socket from the node socket list first,
+ * will be added back after verification. */
+ BLI_remlink(socklist, sock);
return sock;
}
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index dd5715891d5..43d4136d556 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -91,6 +91,12 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma
BLI_strncpy(label, IFACE_(name), maxlen);
}
+void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+{
+ /* if there is no loaded image, return an empty string, and let nodeLabel() fill in the proper type translation. */
+ BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen);
+}
+
void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index 2e20a8e79d4..b4437dfcb78 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -72,6 +72,7 @@ extern void *node_initexec_curves(struct bNodeExecContext *context, struct bNode
/**** Labels ****/
void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index bd22a2be647..2f65188841e 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -460,6 +460,21 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree,
* cycles in the Cycles material :)
*/
nodeRemLink(ntree, displacement_link);
+
+ /* Convert displacement vector to bump height. */
+ bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH);
+ bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ dot_node->custom1 = 3; /* dot product */
+
+ nodeAddLink(ntree,
+ displacement_node, displacement_socket,
+ dot_node, dot_node->inputs.first);
+ nodeAddLink(ntree,
+ geo_node, ntree_shader_node_find_output(geo_node, "Normal"),
+ dot_node, dot_node->inputs.last);
+ displacement_node = dot_node;
+ displacement_socket = ntree_shader_node_find_output(dot_node, "Value");
+
/* We can't connect displacement to normal directly, use bump node for that
* and hope that it gives good enough approximation.
*/
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index 148888f7693..2363addb56a 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -55,6 +55,7 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_image.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index 15a8c47db7a..84481a50993 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -34,7 +34,7 @@
/* **************** BUMP ******************** */
static bNodeSocketTemplate sh_node_bump_in[] = {
{ SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- { SOCK_FLOAT, 1, N_("Distance"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
{ SOCK_FLOAT, 1, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
{ -1, 0, "" }
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.c
new file mode 100644
index 00000000000..d5c191b3966
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.c
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_displacement_in[] = {
+ { SOCK_FLOAT, 0, N_("Height"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 0, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_displacement_out[] = {
+ { SOCK_VECTOR, 0, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static int gpu_shader_displacement(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ if (!in[2].link) {
+ GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[2].link);
+ }
+
+ return GPU_stack_link(mat, node, "node_displacement", in, out);
+}
+
+/* node type definition */
+void register_node_type_sh_displacement(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, gpu_shader_displacement);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c
index 0418b039337..e901e7c4590 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c
@@ -34,7 +34,7 @@
static bNodeSocketTemplate sh_node_output_material_in[] = {
{ SOCK_SHADER, 1, N_("Surface")},
{ SOCK_SHADER, 1, N_("Volume")},
- { SOCK_FLOAT, 1, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_VECTOR, 1, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
{ -1, 0, "" }
};
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
index 8748c884a25..436eeeefb4a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
@@ -27,7 +27,6 @@
#include "../node_shader_util.h"
-#include "BKE_texture.h"
#include "RE_render_ext.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index b5e32e294bf..39598eb8675 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -53,14 +53,14 @@ static void node_shader_exec_valtorgb(void *UNUSED(data), int UNUSED(thread), bN
float fac;
nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- do_colorband(node->storage, fac, out[0]->vec);
+ BKE_colorband_evaluate(node->storage, fac, out[0]->vec);
out[1]->vec[0] = out[0]->vec[3];
}
}
static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_colorband(true);
+ node->storage = BKE_colorband_add(true);
}
static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@@ -68,7 +68,7 @@ static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
float *array;
int size;
- colorband_table_RGBA(node->storage, &array, &size);
+ BKE_colorband_evaluate_table_rgba(node->storage, &array, &size);
return GPU_stack_link(mat, node, "valtorgb", in, out, GPU_texture(size, array));
}
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 2263c271ccf..f6af5b1b6ca 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -53,6 +53,7 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_image.h"
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index 9b13589f3e1..8e9821c0fcb 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -106,6 +106,7 @@ void register_node_type_tex_image(void)
node_type_init(&ntype, init);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, exec);
-
+ node_type_label(&ntype, node_image_label);
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index a49d82d27a9..8b016c5aa50 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -49,7 +49,7 @@ static void valtorgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack *
if (node->storage) {
float fac = tex_input_value(in[0], p, thread);
- do_colorband(node->storage, fac, out);
+ BKE_colorband_evaluate(node->storage, fac, out);
}
}
@@ -60,7 +60,7 @@ static void valtorgb_exec(void *data, int UNUSED(thread), bNode *node, bNodeExec
static void valtorgb_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_colorband(true);
+ node->storage = BKE_colorband_add(true);
}
void register_node_type_tex_valtorgb(void)
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index fc0cd9e475b..224c8295a9b 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -650,7 +650,7 @@ static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *args)
bool do_remove = true;
if (!PyArg_ParseTuple(
- args, "O|i:face_join",
+ args, "O|O&:face_join",
&py_face_array,
PyC_ParseBool, &do_remove))
{
diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c
index 5b602e85a12..4f6b354b7be 100644
--- a/source/blender/python/gawain/gwn_py_types.c
+++ b/source/blender/python/gawain/gwn_py_types.c
@@ -634,7 +634,7 @@ static PyObject *bpygwn_VertBatch_uniform_i32(BPyGwn_Batch *self, PyObject *args
static PyObject *bpygwn_VertBatch_uniform_f32(BPyGwn_Batch *self, PyObject *args)
{
- static struct {
+ struct {
const char *id;
float values[4];
} params;
@@ -648,10 +648,10 @@ static PyObject *bpygwn_VertBatch_uniform_f32(BPyGwn_Batch *self, PyObject *args
}
switch (PyTuple_GET_SIZE(args)) {
- case 2: GWN_batch_uniform_1f(self->batch, params.id, params.values[0]); break;
- case 3: GWN_batch_uniform_2fv(self->batch, params.id, params.values); break;
- case 4: GWN_batch_uniform_3fv(self->batch, params.id, params.values); break;
- case 5: GWN_batch_uniform_4fv(self->batch, params.id, params.values); break;
+ case 2: GWN_batch_uniform_1f(self->batch, params.id, params.values[0]); break;
+ case 3: GWN_batch_uniform_2f(self->batch, params.id, UNPACK2(params.values)); break;
+ case 4: GWN_batch_uniform_3f(self->batch, params.id, UNPACK3(params.values)); break;
+ case 5: GWN_batch_uniform_4f(self->batch, params.id, UNPACK4(params.values)); break;
default:
BLI_assert(0);
}
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index fdad3a7d919..e220e6559a6 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1419,9 +1419,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
/* prefer not fail silently in case of api errors, maybe disable it later */
printf("RNA Warning: Current value \"%d\" "
- "matches no enum in '%s', '%s', '%s'\n",
- val, RNA_struct_identifier(ptr->type),
- ptr_name, RNA_property_identifier(prop));
+ "matches no enum in '%s', '%s', '%s'\n",
+ val, RNA_struct_identifier(ptr->type),
+ ptr_name, RNA_property_identifier(prop));
#if 0 /* gives python decoding errors while generating docs :( */
char error_str[256];
@@ -1751,10 +1751,8 @@ static int pyrna_py_to_prop(
return -1;
}
else {
- /* same as unicode */
- /* XXX, this is suspect but needed for function calls, need to see if theres a better way */
if (data) *((char **)data) = (char *)param;
- else RNA_property_string_set(ptr, prop, param);
+ else RNA_property_string_set_bytes(ptr, prop, param, PyBytes_Size(value));
}
}
else {
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
index 226bfcc7c21..91d407d18a8 100644
--- a/source/blender/python/intern/gpu_offscreen.c
+++ b/source/blender/python/intern/gpu_offscreen.c
@@ -354,7 +354,7 @@ static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyO
return NULL;
}
- ofs = GPU_offscreen_create(width, height, samples, err_out);
+ ofs = GPU_offscreen_create(width, height, samples, false, err_out);
if (ofs == NULL) {
PyErr_Format(PyExc_RuntimeError,
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 2578b19d5ec..924e46a8c00 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1641,9 +1641,9 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
PyDoc_STRVAR(Matrix_decompose_doc,
".. method:: decompose()\n"
"\n"
-" Return the translation, rotation and scale components of this matrix.\n"
+" Return the translation, rotation, and scale components of this matrix.\n"
"\n"
-" :return: trans, rot, scale triple.\n"
+" :return: tuple of translation, rotation, and scale\n"
" :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
);
static PyObject *Matrix_decompose(MatrixObject *self)
@@ -1680,7 +1680,8 @@ static PyObject *Matrix_decompose(MatrixObject *self)
PyDoc_STRVAR(Matrix_lerp_doc,
".. function:: lerp(other, factor)\n"
"\n"
-" Returns the interpolation of two matrices.\n"
+" Returns the interpolation of two matrices. Uses polar decomposition, see"
+" \"Matrix Animation and Polar Decomposition\", Shoemake and Duff, 1992.\n"
"\n"
" :arg other: value to interpolate with.\n"
" :type other: :class:`Matrix`\n"
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 60ffd8f42e4..f789ab702fe 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -183,6 +183,8 @@ void RE_engines_init(void);
void RE_engines_exit(void);
void RE_engines_register(struct Main *bmain, RenderEngineType *render_type);
+bool RE_engine_is_opengl(RenderEngineType *render_type);
+
RenderEngineType *RE_engines_find(const char *idname);
rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free);
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index a0f3a053618..0557efccc2f 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -392,6 +392,7 @@ void RE_updateRenderInstances(Render *re, int flag);
/******* defined in render_result.c *********/
bool RE_HasCombinedLayer(RenderResult *res);
+bool RE_HasFloatPixels(RenderResult *res);
bool RE_RenderResult_is_stereo(RenderResult *res);
struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id);
struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname);
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 74de3fcded6..19a87784ad4 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -3798,12 +3798,13 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
copy_v3_v3(vec, ob->obmat[2]);
normalize_v3(vec);
- InitSunSky(lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness,
- la->spread, la->sun_brightness, la->sun_size, la->backscattered_light,
- la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace);
-
- InitAtmosphere(lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor,
- la->atm_distance_factor);
+ InitSunSky(
+ lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness,
+ la->spread, la->sun_brightness, la->sun_size, la->backscattered_light,
+ la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace);
+ InitAtmosphere(
+ lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor,
+ la->atm_distance_factor);
}
}
else lar->ray_totsamp= 0;
@@ -4668,9 +4669,8 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
/* the emitter has to be processed first (render levels of modifiers) */
/* so here we only check if the emitter should be rendered */
if (ob->particlesystem.first) {
- show_emitter= 0;
+ show_emitter = (ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0;
for (psys=ob->particlesystem.first; psys; psys=psys->next) {
- show_emitter += psys->part->draw & PART_DRAW_EMITTER;
if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) {
psys_has_renderdata |= (psys->renderdata != NULL);
psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 68077d4d93b..2714e8b7685 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -155,6 +155,13 @@ bool RE_engine_is_external(Render *re)
return (re->engine && re->engine->type && re->engine->type->render_to_image);
}
+bool RE_engine_is_opengl(RenderEngineType *render_type)
+{
+ /* TODO refine? Can we have ogl render engine without ogl render pipeline? */
+ return (render_type->draw_engine != NULL) &&
+ DRW_engine_render_support(render_type->draw_engine);
+}
+
/* Create, Free */
RenderEngine *RE_engine_create(RenderEngineType *type)
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 7fdaf38a9ff..5a5c99724fe 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -37,6 +37,7 @@
#include <errno.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_image_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -448,8 +449,6 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
rr->rectz = rv->rectz;
rr->rect32 = rv->rect32;
- rr->have_combined = (rv->rectf != NULL);
-
/* active layer */
rl = render_get_active_layer(re, re->result);
@@ -860,7 +859,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->result = MEM_callocN(sizeof(RenderResult), "new render result");
re->result->rectx = re->rectx;
re->result->recty = re->recty;
- render_result_view_new(re->result, "new temporary view");
+ render_result_view_new(re->result, "");
}
if (re->r.scemode & R_VIEWPORT_PREVIEW)
@@ -2113,6 +2112,31 @@ static void tag_dependend_objects_for_render(Scene *scene, int UNUSED(renderlay)
}
#endif
+#define DEPSGRAPH_WORKAROUND_GROUP_HACK
+
+#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
+/**
+ * Make sure the COLLECTION_VIEWPORT / COLLECTION_RENDER is considered
+ * for the collections visibility.
+ *
+ * This won't be needed anymore once we have depsgraph per render engine.
+ */
+static void tag_groups_for_render(Render *re)
+{
+ for (Group *group = re->main->group.first; group; group = group->id.next) {
+ DEG_id_tag_update(&group->id, 0);
+ }
+
+#ifdef WITH_FREESTYLE
+ if (re->freestyle_bmain) {
+ for (Group *group = re->freestyle_bmain->group.first; group; group = group->id.next) {
+ DEG_id_tag_update(&group->id, 0);
+ }
+ }
+#endif
+}
+#endif
+
static void tag_scenes_for_render(Render *re)
{
bNode *node;
@@ -2196,6 +2220,10 @@ static void ntree_render_scenes(Render *re)
if (re->scene->nodetree == NULL) return;
tag_scenes_for_render(re);
+
+#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
+ tag_groups_for_render(re);
+#endif
/* now foreach render-result node tagged we do a full render */
/* results are stored in a way compisitor will find it */
@@ -2413,6 +2441,10 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
}
}
+#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
+ tag_groups_for_render(re);
+#endif
+
/* composite */
if (ntree) {
ntreeCompositTagRender(re->scene);
@@ -2564,6 +2596,11 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
#ifdef WITH_FREESTYLE
free_all_freestyle_renders();
#endif
+
+#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
+ /* Restore their visibility based on the viewport visibility flags. */
+ tag_groups_for_render(re);
+#endif
}
/* returns fully composited render-result on given time step (in RenderData) */
@@ -2662,6 +2699,11 @@ static void do_render_composite_fields_blur_3d(Render *re)
free_all_freestyle_renders();
#endif
+#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
+ /* Restore their visibility based on the viewport visibility flags. */
+ tag_groups_for_render(re);
+#endif
+
/* weak... the display callback wants an active renderlayer pointer... */
if (re->result != NULL) {
re->result->renlay = render_get_active_layer(re, re->result);
@@ -3223,6 +3265,11 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
/* check all scenes involved */
tag_scenes_for_render(re);
+#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
+ /* Update group collections visibility. */
+ tag_groups_for_render(re);
+#endif
+
/*
* Disabled completely for now,
* can be later set as render profile option
@@ -3346,7 +3393,8 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
return false;
bool is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
- bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER);
+ bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ RE_HasFloatPixels(rr);
if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr)
{
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
index 97d6b060e0a..ddbdb35bf51 100644
--- a/source/blender/render/intern/source/pixelshading.c
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -576,7 +576,7 @@ void shadeSunView(float col_r[3], const float view[3])
GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2],
- lar->sunsky->sky_colorspace);
+ lar->sunsky->sky_colorspace);
ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector);
}
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index e94a452c94a..4f300b7286c 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -48,6 +48,7 @@
#include "DNA_particle_types.h"
#include "DNA_texture_types.h"
+#include "BKE_colorband.h"
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
@@ -55,7 +56,6 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_texture.h"
#include "BKE_colortools.h"
#include "DEG_depsgraph.h"
@@ -786,7 +786,7 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co
switch (pd->color_source) {
case TEX_PD_COLOR_PARTAGE:
if (pd->coba) {
- if (do_colorband(pd->coba, age, rgba)) {
+ if (BKE_colorband_evaluate(pd->coba, age, rgba)) {
texres->talpha = true;
copy_v3_v3(&texres->tr, rgba);
texres->tin *= rgba[3];
@@ -799,7 +799,7 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co
float speed = len_v3(vec) * pd->speed_scale;
if (pd->coba) {
- if (do_colorband(pd->coba, speed, rgba)) {
+ if (BKE_colorband_evaluate(pd->coba, speed, rgba)) {
texres->talpha = true;
copy_v3_v3(&texres->tr, rgba);
texres->tin *= rgba[3];
@@ -831,7 +831,7 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co
break;
case TEX_PD_COLOR_VERTWEIGHT:
texres->talpha = true;
- if (pd->coba && do_colorband(pd->coba, col[0], rgba)) {
+ if (pd->coba && BKE_colorband_evaluate(pd->coba, col[0], rgba)) {
copy_v3_v3(&texres->tr, rgba);
texres->tin *= rgba[3];
}
@@ -1033,7 +1033,10 @@ typedef struct SampleCallbackData {
float *values;
} SampleCallbackData;
-static void point_density_sample_func(void *data_v, const int iter)
+static void point_density_sample_func(
+ void *__restrict data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
SampleCallbackData *data = (SampleCallbackData *)data_v;
@@ -1108,11 +1111,14 @@ void RE_point_density_sample(
data.min = min;
data.dim = dim;
data.values = values;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (resolution > 32);
BLI_task_parallel_range(0,
resolution,
&data,
point_density_sample_func,
- resolution > 32);
+ &settings);
free_pointdensity(pd);
}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 0e7f35fbca3..6749fedb16e 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -80,6 +80,8 @@ static void render_result_views_free(RenderResult *res)
MEM_freeN(rv);
}
+
+ res->have_combined = false;
}
void render_result_free(RenderResult *res)
@@ -1081,7 +1083,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
continue;
}
- IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname);
+ IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname, false);
}
BLI_unlock_thread(LOCK_IMAGE);
@@ -1095,13 +1097,11 @@ void render_result_save_empty_result_tiles(Render *re)
for (rr = re->result; rr; rr = rr->next) {
for (rl = rr->layers.first; rl; rl = rl->next) {
- IMB_exr_clear_channels(rl->exrhandle);
-
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status != PART_STATUS_MERGED) {
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
- IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname);
+ IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname, true);
}
}
}
@@ -1354,6 +1354,8 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I
RenderView *rv = RE_RenderViewGetById(rr, view_id);
if (ibuf->rect_float) {
+ rr->have_combined = true;
+
if (!rv->rectf)
rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
@@ -1364,6 +1366,8 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I
MEM_SAFE_FREE(rv->rect32);
}
else if (ibuf->rect) {
+ rr->have_combined = true;
+
if (!rv->rect32)
rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
@@ -1419,6 +1423,19 @@ bool RE_HasCombinedLayer(RenderResult *res)
return (rv->rect32 || rv->rectf);
}
+bool RE_HasFloatPixels(RenderResult *res)
+{
+ RenderView *rview;
+
+ for (rview = res->views.first; rview; rview = rview->next) {
+ if (rview->rect32 && !rview->rectf) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool RE_RenderResult_is_stereo(RenderResult *res)
{
if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name)))
@@ -1485,9 +1502,6 @@ static RenderView *duplicate_render_view(RenderView *rview)
if (new_rview->rectf != NULL) {
new_rview->rectf = MEM_dupallocN(new_rview->rectf);
}
- if (new_rview->rectf != NULL) {
- new_rview->rectf = MEM_dupallocN(new_rview->rectf);
- }
if (new_rview->rectz != NULL) {
new_rview->rectz = MEM_dupallocN(new_rview->rectz);
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 91d1f63a1be..4241dff96de 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -54,6 +54,7 @@
#include "BKE_node.h"
#include "BKE_animsys.h"
+#include "BKE_colorband.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -161,15 +162,15 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres)
{
if (tex->flag & TEX_COLORBAND) {
float col[4];
- if (do_colorband(tex->coba, texres->tin, col)) {
+ if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) {
float fac0, fac1, fac2, fac3;
fac0= (col[0]+col[1]+col[2]);
- do_colorband(tex->coba, texres->nor[0], col);
+ BKE_colorband_evaluate(tex->coba, texres->nor[0], col);
fac1= (col[0]+col[1]+col[2]);
- do_colorband(tex->coba, texres->nor[1], col);
+ BKE_colorband_evaluate(tex->coba, texres->nor[1], col);
fac2= (col[0]+col[1]+col[2]);
- do_colorband(tex->coba, texres->nor[2], col);
+ BKE_colorband_evaluate(tex->coba, texres->nor[2], col);
fac3= (col[0]+col[1]+col[2]);
texres->nor[0]= (fac0 - fac1) / 3.0f;
@@ -1218,7 +1219,7 @@ static int multitex(Tex *tex,
if (tex->flag & TEX_COLORBAND) {
float col[4];
- if (do_colorband(tex->coba, texres->tin, col)) {
+ if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) {
texres->talpha = true;
texres->tr= col[0];
texres->tg= col[1];
@@ -3753,7 +3754,7 @@ Material *RE_sample_material_init(Material *orig_mat, Scene *scene)
if (!orig_mat) return NULL;
/* copy material */
- mat = localize_material(orig_mat);
+ mat = BKE_material_localize(orig_mat);
/* update material anims */
BKE_animsys_evaluate_animdata(scene, &mat->id, mat->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 9279899ef66..c2d5c060530 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -27,7 +27,6 @@
* \ingroup render
*/
-
#include <stdio.h>
#include <float.h>
#include <math.h>
@@ -36,10 +35,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_material.h"
-#include "BKE_texture.h"
-
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
@@ -942,7 +940,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi)
if (ma->ramp_col) {
if (ma->rampin_col==MA_RAMP_IN_RESULT) {
float fac = IMB_colormanagement_get_luminance(diff);
- do_colorband(ma->ramp_col, fac, col);
+ BKE_colorband_evaluate(ma->ramp_col, fac, col);
/* blending method */
fac= col[3]*ma->rampfac_col;
@@ -986,7 +984,7 @@ static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is,
break;
}
- do_colorband(ma->ramp_col, fac, col);
+ BKE_colorband_evaluate(ma->ramp_col, fac, col);
/* blending method */
fac = col[3] * ma->rampfac_col;
@@ -1015,7 +1013,7 @@ static void ramp_spec_result(float spec_col[3], ShadeInput *shi)
float col[4];
float fac = IMB_colormanagement_get_luminance(spec_col);
- do_colorband(ma->ramp_spec, fac, col);
+ BKE_colorband_evaluate(ma->ramp_spec, fac, col);
/* blending method */
fac= col[3]*ma->rampfac_spec;
@@ -1055,7 +1053,7 @@ static void do_specular_ramp(ShadeInput *shi, float is, float t, float spec[3])
break;
}
- do_colorband(ma->ramp_spec, fac, col);
+ BKE_colorband_evaluate(ma->ramp_spec, fac, col);
/* blending method */
fac= col[3]*ma->rampfac_spec;
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index b5784fe543c..059055daea9 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
intern/wm_window.c
intern/wm_stereo.c
intern/wm_toolsystem.c
+ intern/wm_tooltip.c
manipulators/intern/wm_manipulator.c
manipulators/intern/wm_manipulator_group.c
manipulators/intern/wm_manipulator_group_type.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 61ffbc98426..16c376888df 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -216,7 +216,6 @@ struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase
/* mouse */
void WM_event_add_mousemove(struct bContext *C);
bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
-bool WM_event_is_absolute(const struct wmEvent *event);
bool WM_event_is_last_mousemove(const struct wmEvent *event);
#ifdef WITH_INPUT_NDOF
@@ -234,11 +233,11 @@ void WM_report_banner_show(void);
void WM_report(ReportType type, const char *message);
void WM_reportf(ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
-void wm_event_add_ex(
+struct wmEvent *wm_event_add_ex(
struct wmWindow *win, const struct wmEvent *event_to_add,
const struct wmEvent *event_to_add_after)
ATTR_NONNULL(1, 2);
-void wm_event_add(
+struct wmEvent *wm_event_add(
struct wmWindow *win, const struct wmEvent *event_to_add)
ATTR_NONNULL(1, 2);
@@ -258,6 +257,7 @@ void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+void WM_menu_name_call(struct bContext *C, const char *menu_name, short context);
int WM_enum_search_invoke_previews(struct bContext *C, struct wmOperator *op, short prv_cols, short prv_rows);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, confirm menu + exec */
@@ -541,6 +541,11 @@ void WM_progress_set(struct wmWindow *win, float progress);
void WM_progress_clear(struct wmWindow *win);
/* Draw (for screenshot) */
+void *WM_draw_cb_activate(
+ struct wmWindow *win,
+ void (*draw)(const struct wmWindow *, void *),
+ void *customdata);
+void WM_draw_cb_exit(struct wmWindow *win, void *handle);
void WM_redraw_windows(struct bContext *C);
void WM_main_playanim(int argc, const char **argv);
@@ -573,6 +578,17 @@ void WM_toolsystem_link(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_set(struct bContext *C, const struct bToolDef *tool);
void WM_toolsystem_init(struct bContext *C);
+/* wm_tooltip.c */
+typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, bool *);
+
+void WM_tooltip_timer_init(
+ struct bContext *C, struct wmWindow *win, struct ARegion *ar,
+ wmTooltipInitFn init);
+void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win);
+void WM_tooltip_clear(struct bContext *C, struct wmWindow *win);
+void WM_tooltip_init(struct bContext *C, struct wmWindow *win);
+void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 27f872fc2bb..cb90029a5e7 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -474,8 +474,9 @@ typedef struct wmEvent {
short keymodifier; /* rawkey modifier */
/* set in case a KM_PRESS went by unhandled */
- short check_click;
-
+ char check_click;
+ char is_motion_absolute;
+
/* keymap item, set by handler (weak?) */
const char *keymap_idname;
@@ -702,6 +703,23 @@ typedef struct wmDropBox {
} wmDropBox;
+/**
+ * Struct to store tool-tip timer and possible creation if the time is reached.
+ * Allows UI code to call #WM_tooltip_timer_init without each user having to handle the timer.
+ */
+typedef struct wmTooltipState {
+ /** Create tooltip on this event. */
+ struct wmTimer *timer;
+ /** The region the tooltip is created in. */
+ struct ARegion *region_from;
+ /** The tooltip region. */
+ struct ARegion *region;
+ /** Create the tooltip region (assign to 'region'). */
+ struct ARegion *(*init)(struct bContext *, struct ARegion *, bool *r_exit_on_event);
+ /** Exit on any event, not needed for buttons since their highlight state is used. */
+ bool exit_on_event;
+} wmTooltipState;
+
/* *************** migrated stuff, clean later? ************** */
typedef struct RecentFile {
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index d4c3928bd6c..ad5e83ceda7 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -213,13 +213,10 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4])
}
if ((G.debug & G_DEBUG) == 0) {
if (win->ghostwin) {
- const GHOST_TabletData *tabletdata = GHOST_GetTabletData(win->ghostwin);
-
/* Note: There is no tabletdata on Windows if no tablet device is connected. */
- if (!tabletdata)
- GHOST_SetCursorGrab(win->ghostwin, mode, bounds, NULL);
- else if (tabletdata->Active == GHOST_kTabletModeNone)
+ if (win->eventstate->is_motion_absolute == false) {
GHOST_SetCursorGrab(win->ghostwin, mode, bounds, NULL);
+ }
win->grabcursor = mode;
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 5650c16ee0e..30197537e14 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -50,6 +50,8 @@
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "GHOST_C-api.h"
@@ -133,7 +135,8 @@ static bool wm_area_test_invalid_backbuf(ScrArea *sa)
return true;
}
-static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegion *ar)
+static void wm_region_test_render_do_draw(const Scene *scene, const struct Depsgraph *depsgraph,
+ ScrArea *sa, ARegion *ar)
{
/* tag region for redraw from render engine preview running inside of it */
if (sa->spacetype == SPACE_VIEW3D) {
@@ -146,7 +149,7 @@ static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegi
rcti border_rect;
/* do partial redraw when possible */
- if (ED_view3d_calc_render_border(scene, v3d, ar, &border_rect))
+ if (ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect))
ED_region_tag_redraw_partial(ar, &border_rect);
else
ED_region_tag_redraw(ar);
@@ -170,6 +173,46 @@ static void wm_draw_region(bContext *C, ARegion *ar)
/********************** draw all **************************/
/* - reference method, draw all each time */
+typedef struct WindowDrawCB {
+ struct WindowDrawCB *next, *prev;
+
+ void(*draw)(const struct wmWindow *, void *);
+ void *customdata;
+
+} WindowDrawCB;
+
+void *WM_draw_cb_activate(
+ wmWindow *win,
+ void(*draw)(const struct wmWindow *, void *),
+ void *customdata)
+{
+ WindowDrawCB *wdc = MEM_callocN(sizeof(*wdc), "WindowDrawCB");
+
+ BLI_addtail(&win->drawcalls, wdc);
+ wdc->draw = draw;
+ wdc->customdata = customdata;
+
+ return wdc;
+}
+
+void WM_draw_cb_exit(wmWindow *win, void *handle)
+{
+ for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) {
+ if (wdc == (WindowDrawCB *)handle) {
+ BLI_remlink(&win->drawcalls, wdc);
+ MEM_freeN(wdc);
+ return;
+ }
+ }
+}
+
+static void wm_draw_callbacks(wmWindow *win)
+{
+ for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) {
+ wdc->draw(win, wdc->customdata);
+ }
+}
+
static void wm_method_draw_full(bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -193,8 +236,9 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
CTX_wm_area_set(C, NULL);
}
- ED_screen_draw(win);
+ ED_screen_draw_edges(win);
screen->do_draw = false;
+ wm_draw_callbacks(win);
/* draw overlapping regions */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -330,17 +374,19 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
/* after area regions so we can do area 'overlay' drawing */
if (screen->do_draw) {
- ED_screen_draw(win);
+ ED_screen_draw_edges(win);
screen->do_draw = false;
+ wm_draw_callbacks(win);
if (exchange)
screen->swap = WIN_FRONT_OK;
}
else if (exchange) {
if (screen->swap == WIN_FRONT_OK) {
- ED_screen_draw(win);
+ ED_screen_draw_edges(win);
screen->do_draw = false;
screen->swap = WIN_BOTH_OK;
+ wm_draw_callbacks(win);
}
else if (screen->swap == WIN_BACK_OK)
screen->swap = WIN_FRONT_OK;
@@ -626,8 +672,9 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
}
/* after area regions so we can do area 'overlay' drawing */
- ED_screen_draw(win);
+ ED_screen_draw_edges(win);
WM_window_get_active_screen(win)->do_draw = false;
+ wm_draw_callbacks(win);
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -800,10 +847,12 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
}
/* after area regions so we can do area 'overlay' drawing */
- ED_screen_draw(win);
+ ED_screen_draw_edges(win);
if (sview == STEREO_RIGHT_ID)
screen->do_draw = false;
+ wm_draw_callbacks(win);
+
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->swinid) {
@@ -834,7 +883,10 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
/* quick test to prevent changing window drawable */
static bool wm_draw_update_test_window(wmWindow *win)
{
- const Scene *scene = WM_window_get_active_scene(win);
+ /*const*/ struct WorkSpace *workspace = WM_window_get_active_workspace(win);
+ /*const*/ Scene *scene = WM_window_get_active_scene(win);
+ /*const*/ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
+ struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
const bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
bool do_draw = false;
@@ -850,7 +902,7 @@ static bool wm_draw_update_test_window(wmWindow *win)
ED_screen_areas_iter(win, screen, sa) {
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- wm_region_test_render_do_draw(scene, sa, ar);
+ wm_region_test_render_do_draw(scene, depsgraph, sa, ar);
if (ar->swinid && ar->do_draw)
do_draw = true;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 02cf9981a3a..e66e7728d31 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -97,7 +97,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
/* ************ event management ************** */
-void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
+wmEvent *wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
{
wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
@@ -105,6 +105,13 @@ void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *
update_tablet_data(win, event);
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ /* We could have a preference to support relative tablet motion (we can't detect that). */
+ event->is_motion_absolute = (
+ (event->tablet_data != NULL) &&
+ (event->tablet_data->Active != GHOST_kTabletModeNone));
+ }
+
if (event_to_add_after == NULL) {
BLI_addtail(&win->queue, event);
}
@@ -112,11 +119,12 @@ void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *
/* note, strictly speaking this breaks const-correctness, however we're only changing 'next' member */
BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event);
}
+ return event;
}
-void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
+wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
{
- wm_event_add_ex(win, event_to_add, NULL);
+ return wm_event_add_ex(win, event_to_add, NULL);
}
void wm_event_free(wmEvent *event)
@@ -695,11 +703,6 @@ void WM_report_banner_show(void)
wm_reports->reporttimer->customdata = rti;
}
-bool WM_event_is_absolute(const wmEvent *event)
-{
- return (event->tablet_data != NULL);
-}
-
bool WM_event_is_last_mousemove(const wmEvent *event)
{
while ((event = event->next)) {
@@ -870,14 +873,22 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
return retval;
if (op->type->exec) {
- if (op->type->flag & OPTYPE_UNDO)
+ if (op->type->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
+ }
+ if (repeat) {
+ op->flag |= OP_IS_REPEAT;
+ }
retval = op->type->exec(C, op);
OPERATOR_RETVAL_CHECK(retval);
+ if (repeat) {
+ op->flag &= ~OP_IS_REPEAT;
+ }
- if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
+ if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
wm->op_undo_depth--;
+ }
}
/* XXX Disabled the repeat check to address part 2 of #31840.
@@ -1472,6 +1483,19 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin
}
/**
+ * Call an existent menu. The menu can be created in C or Python.
+ */
+void WM_menu_name_call(bContext *C, const char *menu_name, short context)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_string_set(&ptr, "name", menu_name);
+ WM_operator_name_call_ptr(C, ot, context, &ptr);
+ WM_operator_properties_free(&ptr);
+}
+
+/**
* Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
*
* - #wmOperatorType is used instead of operator name since python already has the operator type.
@@ -2274,8 +2298,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
int part;
mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part);
wm_manipulatormap_highlight_set(mmap, C, mpr, part);
+ if (mpr != NULL) {
+ WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_manipulatormap_tooltip_init);
+ }
}
- /* handle user configurable manipulator-map keymap */
else {
/* Either we operate on a single highlighted item
* or groups attached to the selected manipulators.
@@ -2712,6 +2738,13 @@ void wm_event_do_handlers(bContext *C)
CTX_wm_window_set(C, win);
+ /* Clear tool-tip on mouse move. */
+ if (screen->tool_tip && screen->tool_tip->exit_on_event) {
+ if (ISMOUSE(event->type)) {
+ WM_tooltip_clear(C, win);
+ }
+ }
+
/* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
CTX_wm_area_set(C, area_event_inside(C, &event->x));
CTX_wm_region_set(C, region_event_inside(C, &event->x));
@@ -2728,7 +2761,16 @@ void wm_event_do_handlers(bContext *C)
/* fileread case */
if (CTX_wm_window(C) == NULL)
return;
-
+
+ /* check for a tooltip */
+ if (screen == WM_window_get_active_screen(win)) {
+ if (screen->tool_tip && screen->tool_tip->timer) {
+ if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
+ WM_tooltip_init(C, win);
+ }
+ }
+ }
+
/* check dragging, creates new event or frees, adds draw tag */
wm_event_drag_test(wm, win, event);
@@ -3512,7 +3554,7 @@ static bool wm_event_is_double_click(wmEvent *event, const wmEvent *event_state)
return false;
}
-static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
+static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
{
wmEvent *event_last = win->queue.last;
@@ -3522,16 +3564,13 @@ static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
if (event_last && event_last->type == MOUSEMOVE)
event_last->type = INBETWEEN_MOUSEMOVE;
- wm_event_add(win, event);
-
- {
- wmEvent *event_new = win->queue.last;
- if (event_last == NULL) {
- event_last = win->eventstate;
- }
-
- copy_v2_v2_int(&event_new->prevx, &event_last->x);
+ wmEvent *event_new = wm_event_add(win, event);
+ if (event_last == NULL) {
+ event_last = win->eventstate;
}
+
+ copy_v2_v2_int(&event_new->prevx, &event_last->x);
+ return event_new;
}
/* windows store own event queues, no bContext here */
@@ -3561,8 +3600,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
wm_stereo3d_mouse_offset_apply(win, &event.x);
event.type = MOUSEMOVE;
- wm_event_add_mousemove(win, &event);
- copy_v2_v2_int(&evt->x, &event.x);
+ {
+ wmEvent *event_new = wm_event_add_mousemove(win, &event);
+ copy_v2_v2_int(&evt->x, &event_new->x);
+ evt->is_motion_absolute = event_new->is_motion_absolute;
+ }
/* also add to other window if event is there, this makes overdraws disappear nicely */
/* it remaps mousecoord to other window in event */
@@ -3574,8 +3616,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
copy_v2_v2_int(&oevent.x, &event.x);
oevent.type = MOUSEMOVE;
- wm_event_add_mousemove(owin, &oevent);
- copy_v2_v2_int(&oevt->x, &oevent.x);
+ {
+ wmEvent *event_new = wm_event_add_mousemove(owin, &oevent);
+ copy_v2_v2_int(&oevt->x, &event_new->x);
+ oevt->is_motion_absolute = event_new->is_motion_absolute;
+ }
}
break;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 7c8059fcda9..6a86644da17 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1043,7 +1043,7 @@ static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, ViewLayer *view_
ibuf = ED_view3d_draw_offscreen_imbuf_simple(
&eval_ctx, scene, view_layer, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, OB_SOLID, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
+ IB_rect, V3D_OFSDRAW_NONE, OB_SOLID, R_ALPHAPREMUL, 0, NULL,
NULL, NULL, err_out);
}
else {
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 96cb11f11ab..8980c4acf26 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1953,7 +1953,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
if (ibuf_template) {
const int x_expect = ibuf->x;
- const int y_expect = 230 * (int)U.pixelsize;
+ const int y_expect = 282 * (int)U.pixelsize;
/* don't cover the header text */
if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index c0800705b28..84b739a692e 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -397,7 +397,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
/**
* If needed, this adjusts \a r_mouse_xy so that drawn cursor and handled mouse position are matching visually.
-*/
+ */
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
{
if (!WM_stereo3d_enabled(win, false))
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
new file mode 100644
index 00000000000..83d620d1522
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_tooltip.c
@@ -0,0 +1,106 @@
+/*
+ * ***** 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/windowmanager/intern/wm_tooltip.c
+ * \ingroup wm
+ *
+ * Manages a per-window tool-tip.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+void WM_tooltip_timer_init(
+ bContext *C, wmWindow *win, ARegion *ar,
+ wmTooltipInitFn init)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (screen->tool_tip == NULL) {
+ screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
+ }
+ screen->tool_tip->region_from = ar;
+ screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY);
+ screen->tool_tip->init = init;
+}
+
+void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->tool_tip != NULL) {
+ if (screen->tool_tip->timer != NULL) {
+ WM_event_remove_timer(wm, win, screen->tool_tip->timer);
+ screen->tool_tip->timer = NULL;
+ }
+ }
+}
+
+void WM_tooltip_clear(bContext *C, wmWindow *win)
+{
+ WM_tooltip_timer_clear(C, win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->tool_tip != NULL) {
+ if (screen->tool_tip->region) {
+ UI_tooltip_free(C, screen, screen->tool_tip->region);
+ screen->tool_tip->region = NULL;
+ }
+ MEM_freeN(screen->tool_tip);
+ screen->tool_tip = NULL;
+ }
+}
+
+void WM_tooltip_init(bContext *C, wmWindow *win)
+{
+ WM_tooltip_timer_clear(C, win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->tool_tip->region) {
+ UI_tooltip_free(C, screen, screen->tool_tip->region);
+ screen->tool_tip->region = NULL;
+ }
+ screen->tool_tip->region = screen->tool_tip->init(
+ C, screen->tool_tip->region_from, &screen->tool_tip->exit_on_event);
+ if (screen->tool_tip->region == NULL) {
+ WM_tooltip_clear(C, win);
+ }
+}
+
+void WM_tooltip_refresh(bContext *C, wmWindow *win)
+{
+ WM_tooltip_timer_clear(C, win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->tool_tip != NULL) {
+ if (screen->tool_tip->region) {
+ UI_tooltip_free(C, screen, screen->tool_tip->region);
+ screen->tool_tip->region = NULL;
+ }
+ WM_tooltip_init(C, win);
+ }
+}
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
index 9214bccb6a0..53bee9c6775 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
@@ -259,6 +259,9 @@ bool WM_manipulatormap_minmax(
const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select,
float r_min[3], float r_max[3]);
+struct ARegion *WM_manipulatormap_tooltip_init(
+ struct bContext *C, struct ARegion *ar, bool *r_exit_on_event);
+
/* -------------------------------------------------------------------- */
/* wmManipulatorMapType */
@@ -326,6 +329,6 @@ void WM_manipulator_group_type_unlink_delayed_ptr(
void WM_manipulator_group_type_unlink_delayed(const char *idname);
/* Utilities */
-void WM_manipulator_group_type_is_any_selected(const char *idname);
+bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step);
#endif /* __WM_MANIPULATOR_API_H__ */
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
index 5fa89b8d35f..6d83f411db1 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
@@ -80,6 +80,10 @@ typedef enum eWM_ManipulatorFlag {
* This simply skips scale when calculating the final matrix.
* Needed when the manipulator needs to align with the interface underneath it. */
WM_MANIPULATOR_DRAW_NO_SCALE = (1 << 5),
+ /**
+ * Hide the cursor and lock it's position while interacting with this manipulator.
+ */
+ WM_MANIPULATOR_GRAB_CURSOR = (1 << 6),
} eWM_ManipulatorFlag;
/**
@@ -178,6 +182,8 @@ struct wmManipulator {
/* Optional ID for highlighting different parts of this manipulator.
* -1 when unset, otherwise a valid index. (Used as index to 'op_data'). */
int highlight_part;
+ /* For single click button manipulators, use a different part as a fallback, -1 when unused. */
+ int drag_part;
/* Transformation of the manipulator in 2d or 3d space.
* - Matrix axis are expected to be unit length (scale is applied after).
@@ -307,6 +313,9 @@ typedef struct wmManipulatorType {
/* called when manipulator selection state changes */
wmManipulatorFnSelectRefresh select_refresh;
+ /* Free data (not the manipulator it's self), use when the manipulator allocates it's own members. */
+ wmManipulatorFnFree free;
+
/* RNA for properties */
struct StructRNA *srna;
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
index 7ca1f8fd5f2..3a78dd32f94 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
@@ -98,6 +98,8 @@ static wmManipulator *wm_manipulator_create(
unit_m4(mpr->matrix_basis);
unit_m4(mpr->matrix_offset);
+ mpr->drag_part = -1;
+
return mpr;
}
@@ -164,6 +166,10 @@ static void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *m
*/
void WM_manipulator_free(wmManipulator *mpr)
{
+ if (mpr->type->free != NULL) {
+ mpr->type->free(mpr);
+ }
+
#ifdef WITH_PYTHON
if (mpr->py_instance) {
/* do this first in case there are any __del__ functions or
@@ -729,3 +735,28 @@ void WM_manipulator_properties_free(PointerRNA *ptr)
}
/** \} */
+
+/** \name General Utilities
+ *
+ * \{ */
+
+bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step)
+{
+ switch (step) {
+ case WM_MANIPULATORMAP_DRAWSTEP_2D:
+ {
+ break;
+ }
+ case WM_MANIPULATORMAP_DRAWSTEP_3D:
+ {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (ED_screen_animation_playing(wm)) {
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
index d62aac8cd87..0e63f3d6ffe 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
@@ -39,6 +39,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -61,6 +62,10 @@
# include "BPY_extern.h"
#endif
+/* Allow manipulator part's to be single click only,
+ * dragging falls back to activating their 'drag_part' action. */
+#define USE_DRAG_DETECT
+
/* -------------------------------------------------------------------- */
/** \name wmManipulatorGroup
*
@@ -140,7 +145,7 @@ void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmMani
mpr->parent_mgroup = mgroup;
}
-wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
+wmManipulator *wm_manipulatorgroup_find_intersected_manipulator(
const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event,
int *r_part)
{
@@ -303,19 +308,81 @@ void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot)
typedef struct ManipulatorTweakData {
wmManipulatorMap *mmap;
+ wmManipulatorGroup *mgroup;
wmManipulator *mpr_modal;
int init_event; /* initial event type */
int flag; /* tweak flags */
+
+#ifdef USE_DRAG_DETECT
+ /* True until the mouse is moved (only use when the operator has no modal).
+ * this allows some manipulators to be click-only. */
+ enum {
+ /* Don't detect dragging. */
+ DRAG_NOP = 0,
+ /* Detect dragging (wait until a drag or click is detected). */
+ DRAG_DETECT,
+ /* Drag has started, idle until there is no active modal operator.
+ * This is needed because finishing the modal operator also exits
+ * the modal manipulator state (un-grabbs the cursor).
+ * Ideally this workaround could be removed later. */
+ DRAG_IDLE,
+ } drag_state;
+#endif
+
} ManipulatorTweakData;
-static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel)
+static bool manipulator_tweak_start(
+ bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr, const wmEvent *event)
+{
+ /* activate highlighted manipulator */
+ wm_manipulatormap_modal_set(mmap, C, mpr, event, true);
+
+ return (mpr->state & WM_MANIPULATOR_STATE_MODAL);
+}
+
+static bool manipulator_tweak_start_and_finish(
+ bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr, const wmEvent *event, bool *r_is_modal)
+{
+ wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part);
+ if (r_is_modal) {
+ *r_is_modal = false;
+ }
+ if (mpop && mpop->type) {
+ /* XXX temporary workaround for modal manipulator operator
+ * conflicting with modal operator attached to manipulator */
+ if (mpop->type->modal) {
+ /* activate highlighted manipulator */
+ wm_manipulatormap_modal_set(mmap, C, mpr, event, true);
+ if (r_is_modal) {
+ *r_is_modal = true;
+ }
+ }
+ else {
+ /* Allow for 'button' manipulators, single click to run an action. */
+ WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel, bool clear_modal)
{
ManipulatorTweakData *mtweak = op->customdata;
if (mtweak->mpr_modal->type->exit) {
mtweak->mpr_modal->type->exit(C, mtweak->mpr_modal, cancel);
}
- wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false);
+ if (clear_modal) {
+ /* The manipulator may have been removed. */
+ if ((BLI_findindex(&mtweak->mmap->groups, mtweak->mgroup) != -1) &&
+ (BLI_findindex(&mtweak->mgroup->manipulators, mtweak->mpr_modal) != -1))
+ {
+ wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false);
+ }
+ }
MEM_freeN(mtweak);
}
@@ -323,27 +390,68 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e
{
ManipulatorTweakData *mtweak = op->customdata;
wmManipulator *mpr = mtweak->mpr_modal;
+ int retval = OPERATOR_PASS_THROUGH;
+ bool clear_modal = true;
if (mpr == NULL) {
BLI_assert(0);
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
- if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
- manipulator_tweak_finish(C, op, false);
- return OPERATOR_FINISHED;
- }
+#ifdef USE_DRAG_DETECT
+ wmManipulatorMap *mmap = mtweak->mmap;
+ if (mtweak->drag_state == DRAG_DETECT) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (len_manhattan_v2v2_int(&event->x, mmap->mmap_context.event_xy) > 2) {
+ mtweak->drag_state = DRAG_IDLE;
+ mpr->highlight_part = mpr->drag_part;
+ }
+ }
+ else if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
+ mtweak->drag_state = DRAG_NOP;
+ retval = OPERATOR_FINISHED;
+ }
+ if (mtweak->drag_state != DRAG_DETECT) {
+ /* Follow logic in 'manipulator_tweak_invoke' */
+ bool is_modal = false;
+ if (manipulator_tweak_start_and_finish(C, mmap, mpr, event, &is_modal)) {
+ if (is_modal) {
+ clear_modal = false;
+ }
+ }
+ else {
+ if (!manipulator_tweak_start(C, mmap, mpr, event)) {
+ retval = OPERATOR_FINISHED;
+ }
+ }
+ }
+ }
+ if (mtweak->drag_state == DRAG_IDLE) {
+ if (mmap->mmap_context.modal != NULL) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ else {
+ manipulator_tweak_finish(C, op, false, false);
+ return OPERATOR_FINISHED;
+ }
+ }
+#endif /* USE_DRAG_DETECT */
- if (event->type == EVT_MODAL_MAP) {
+ if (retval == OPERATOR_FINISHED) {
+ /* pass */
+ }
+ else if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
+ retval = OPERATOR_FINISHED;
+ }
+ else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case TWEAK_MODAL_CANCEL:
- manipulator_tweak_finish(C, op, true);
- return OPERATOR_CANCELLED;
+ retval = OPERATOR_CANCELLED;
+ break;
case TWEAK_MODAL_CONFIRM:
- manipulator_tweak_finish(C, op, false);
- return OPERATOR_FINISHED;
-
+ retval = OPERATOR_FINISHED;
+ break;
case TWEAK_MODAL_PRECISION_ON:
mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE;
break;
@@ -360,20 +468,28 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e
}
}
+ if (retval != OPERATOR_PASS_THROUGH) {
+ manipulator_tweak_finish(C, op, retval != OPERATOR_FINISHED, clear_modal);
+ return retval;
+ }
+
/* handle manipulator */
wmManipulatorFnModal modal_fn = mpr->custom_modal ? mpr->custom_modal : mpr->type->modal;
- int retval = modal_fn(C, mpr, event, mtweak->flag);
+ if (modal_fn) {
+ int modal_retval = modal_fn(C, mpr, event, mtweak->flag);
- if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
- manipulator_tweak_finish(C, op, (retval & OPERATOR_CANCELLED) != 0);
- return OPERATOR_FINISHED;
- }
+ if ((modal_retval & OPERATOR_RUNNING_MODAL) == 0) {
+ manipulator_tweak_finish(C, op, (modal_retval & OPERATOR_CANCELLED) != 0, true);
+ return OPERATOR_FINISHED;
+ }
- /* Ugly hack to send manipulator events */
- ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE;
+ /* Ugly hack to send manipulator events */
+ ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE;
+ }
/* always return PASS_THROUGH so modal handlers
* with manipulators attached can update */
+ BLI_assert(retval == OPERATOR_PASS_THROUGH);
return OPERATOR_PASS_THROUGH;
}
@@ -383,37 +499,58 @@ static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *
wmManipulatorMap *mmap = ar->manipulator_map;
wmManipulator *mpr = mmap->mmap_context.highlight;
+ /* Needed for single click actions which don't enter modal state. */
+ WM_tooltip_clear(C, CTX_wm_window(C));
+
if (!mpr) {
/* wm_handlers_do_intern shouldn't let this happen */
BLI_assert(0);
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
+ bool use_drag_fallback = false;
- /* activate highlighted manipulator */
- wm_manipulatormap_modal_set(mmap, C, mpr, event, true);
+#ifdef USE_DRAG_DETECT
+ use_drag_fallback = !ELEM(mpr->drag_part, -1, mpr->highlight_part);
+#endif
- /* XXX temporary workaround for modal manipulator operator
- * conflicting with modal operator attached to manipulator */
- wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part);
- if (mpop && mpop->type) {
- if (mpop->type->modal) {
+ if (use_drag_fallback == false) {
+ if (manipulator_tweak_start_and_finish(C, mmap, mpr, event, NULL)) {
return OPERATOR_FINISHED;
}
}
- /* Couldn't start the manipulator. */
- if ((mpr->state & WM_MANIPULATOR_STATE_MODAL) == 0) {
- return OPERATOR_PASS_THROUGH;
+ bool use_drag_detect = false;
+#ifdef USE_DRAG_DETECT
+ if (use_drag_fallback) {
+ wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part);
+ if (mpop && mpop->type) {
+ if (mpop->type->modal == NULL) {
+ use_drag_detect = true;
+ }
+ }
+ }
+#endif
+
+ if (use_drag_detect == false) {
+ if (!manipulator_tweak_start(C, mmap, mpr, event)) {
+ /* failed to start */
+ return OPERATOR_PASS_THROUGH;
+ }
}
ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__);
mtweak->init_event = WM_userdef_event_type_from_keymap_type(event->type);
mtweak->mpr_modal = mmap->mmap_context.highlight;
+ mtweak->mgroup = mtweak->mpr_modal->parent_mgroup;
mtweak->mmap = mmap;
mtweak->flag = 0;
+#ifdef USE_DRAG_DETECT
+ mtweak->drag_state = use_drag_detect ? DRAG_DETECT : DRAG_NOP;
+#endif
+
op->customdata = mtweak;
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
index bf5c38b9e39..b7982cf00df 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
@@ -69,7 +69,7 @@ struct wmManipulatorGroup *wm_manipulatorgroup_new_from_type(
struct wmManipulatorMap *mmap, struct wmManipulatorGroupType *wgt);
void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorGroup *mgroup);
void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr);
-struct wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
+struct wmManipulator *wm_manipulatorgroup_find_intersected_manipulator(
const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event,
int *r_part);
void wm_manipulatorgroup_intersectable_manipulators_to_list(
@@ -112,6 +112,9 @@ struct wmManipulatorMap {
struct wmManipulator *modal;
/* array for all selected manipulators */
struct wmManipulatorMapSelectState select;
+ /* cursor location at point of entering modal (see: WM_MANIPULATOR_GRAB_CURSOR) */
+ int event_xy[2];
+ short event_grabcursor;
} mmap_context;
};
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
index 5d9810272cc..a9875020fbb 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
@@ -51,6 +51,9 @@
#include "WM_types.h"
#include "wm_event_system.h"
+/* for tool-tips */
+#include "UI_interface.h"
+
#include "DEG_depsgraph.h"
/* own includes */
@@ -442,6 +445,10 @@ void WM_manipulatormap_draw(
wmManipulatorMap *mmap, const bContext *C,
const eWM_ManipulatorMapDrawStep drawstep)
{
+ if (!WM_manipulator_context_check_drawstep(C, drawstep)) {
+ return;
+ }
+
ListBase draw_manipulators = {NULL};
manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep);
@@ -547,6 +554,7 @@ static wmManipulator *manipulator_find_intersected_3d(
};
*r_part = 0;
+
/* set up view matrices */
view3d_operator_needs_opengl(C);
@@ -585,6 +593,11 @@ wmManipulator *wm_manipulatormap_highlight_find(
{
wmManipulator *mpr = NULL;
ListBase visible_3d_manipulators = {NULL};
+ bool do_step[WM_MANIPULATORMAP_DRAWSTEP_MAX];
+
+ for (int i = 0; i < ARRAY_SIZE(do_step); i++) {
+ do_step[i] = WM_manipulator_context_check_drawstep(C, i);
+ }
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
@@ -596,25 +609,28 @@ wmManipulator *wm_manipulatormap_highlight_find(
}
if (wm_manipulatorgroup_is_visible(mgroup, C)) {
+ eWM_ManipulatorMapDrawStep step;
if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) {
- if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_3D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) &&
- mgroup->type->refresh)
- {
- mgroup->type->refresh(C, mgroup);
- /* cleared below */
- }
- wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
+ step = WM_MANIPULATORMAP_DRAWSTEP_3D;
}
else {
- if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_2D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) &&
- mgroup->type->refresh)
+ step = WM_MANIPULATORMAP_DRAWSTEP_2D;
+ }
+
+ if (do_step[step]) {
+ if ((mmap->update_flag[step] & MANIPULATORMAP_IS_REFRESH_CALLBACK) &&
+ (mgroup->type->refresh != NULL))
{
mgroup->type->refresh(C, mgroup);
/* cleared below */
}
-
- if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) {
- break;
+ if (step == WM_MANIPULATORMAP_DRAWSTEP_3D) {
+ wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
+ }
+ else if (step == WM_MANIPULATORMAP_DRAWSTEP_2D) {
+ if ((mpr = wm_manipulatorgroup_find_intersected_manipulator(mgroup, C, event, r_part))) {
+ break;
+ }
}
}
}
@@ -886,27 +902,39 @@ void wm_manipulatormap_modal_set(
{
if (enable) {
BLI_assert(mmap->mmap_context.modal == NULL);
+ wmWindow *win = CTX_wm_window(C);
- /* For now only grab cursor for 3D manipulators. */
- bool grab_cursor = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) != 0;
- int retval = OPERATOR_RUNNING_MODAL;
+ WM_tooltip_clear(C, win);
if (mpr->type->invoke &&
(mpr->type->modal || mpr->custom_modal))
{
- retval = mpr->type->invoke(C, mpr, event);
- }
-
- if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
- return;
+ const int retval = mpr->type->invoke(C, mpr, event);
+ if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
+ return;
+ }
}
mpr->state |= WM_MANIPULATOR_STATE_MODAL;
mmap->mmap_context.modal = mpr;
+ if ((mpr->flag & WM_MANIPULATOR_GRAB_CURSOR) &&
+ (event->is_motion_absolute == false))
+ {
+ WM_cursor_grab_enable(win, true, true, NULL);
+ copy_v2_v2_int(mmap->mmap_context.event_xy, &event->x);
+ mmap->mmap_context.event_grabcursor = win->grabcursor;
+ }
+ else {
+ mmap->mmap_context.event_xy[0] = INT_MAX;
+ }
+
struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part);
if (mpop && mpop->type) {
- WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr);
+ const int retval = WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr);
+ if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
+ wm_manipulatormap_modal_set(mmap, C, mpr, event, false);
+ }
/* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
if (!mmap->mmap_context.modal) {
@@ -915,10 +943,6 @@ void wm_manipulatormap_modal_set(
}
return;
}
-
- if (grab_cursor) {
- WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
- }
}
else {
BLI_assert(ELEM(mmap->mmap_context.modal, NULL, mpr));
@@ -931,10 +955,23 @@ void wm_manipulatormap_modal_set(
mmap->mmap_context.modal = NULL;
if (C) {
- WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ wmWindow *win = CTX_wm_window(C);
+ if (mmap->mmap_context.event_xy[0] != INT_MAX) {
+ /* Check if some other part of Blender (typically operators)
+ * have adjusted the grab mode since it was set.
+ * If so: warp, so we have a predictable outcome. */
+ if (mmap->mmap_context.event_grabcursor == win->grabcursor) {
+ WM_cursor_grab_disable(win, mmap->mmap_context.event_xy);
+ }
+ else {
+ WM_cursor_warp(win, UNPACK2(mmap->mmap_context.event_xy));
+ }
+ }
ED_region_tag_redraw(CTX_wm_region(C));
WM_event_add_mousemove(C);
}
+
+ mmap->mmap_context.event_xy[0] = INT_MAX;
}
}
@@ -977,6 +1014,27 @@ void WM_manipulatormap_message_subscribe(
/* -------------------------------------------------------------------- */
+/** \name Tooltip Handling
+ *
+ * \{ */
+
+struct ARegion *WM_manipulatormap_tooltip_init(
+ struct bContext *C, struct ARegion *ar, bool *r_exit_on_event)
+{
+ wmManipulatorMap *mmap = ar->manipulator_map;
+ *r_exit_on_event = true;
+ if (mmap) {
+ wmManipulator *mpr = mmap->mmap_context.highlight;
+ if (mpr) {
+ return UI_tooltip_create_from_manipulator(C, mpr);
+ }
+ }
+ return NULL;
+}
+
+/** \} */ /* wmManipulatorMapType */
+
+/* -------------------------------------------------------------------- */
/** \name wmManipulatorMapType
*
* \{ */
diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
index 7e163f8a785..305d04eab68 100644
--- a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
+++ b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
@@ -59,6 +59,7 @@ typedef int (*wmManipulatorFnInvoke)(struct bContext *, struct wmManipulator
typedef void (*wmManipulatorFnExit)(struct bContext *, struct wmManipulator *, const bool);
typedef int (*wmManipulatorFnCursorGet)(struct wmManipulator *);
typedef void (*wmManipulatorFnSelectRefresh)(struct wmManipulator *);
+typedef void (*wmManipulatorFnFree)(struct wmManipulator *);
/* wmManipulatorProperty ('value' type defined by 'wmManipulatorProperty.data_type') */
typedef void (*wmManipulatorPropertyFnGet)(