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:
-rw-r--r--CMakeLists.txt1
-rw-r--r--build_files/build_environment/cmake/boost.cmake4
-rw-r--r--build_files/build_environment/patches/boost.diff15
-rw-r--r--build_files/buildbot/master.cfg368
-rw-r--r--build_files/buildbot/master_unpack.py151
-rw-r--r--build_files/buildbot/slave_compile.py7
-rw-r--r--build_files/cmake/config/blender_lite.cmake2
-rw-r--r--build_files/cmake/macros.cmake5
-rw-r--r--build_files/cmake/platform/platform_apple.cmake9
-rw-r--r--doc/doxygen/doxygen.source.h4
-rw-r--r--doc/guides/blender-guardedalloc.txt2
-rw-r--r--doc/python_api/examples/bpy.props.1.py52
-rw-r--r--doc/python_api/examples/bpy.props.5.py36
-rw-r--r--doc/python_api/rst/info_api_reference.rst2
-rw-r--r--doc/python_api/sphinx_doc_gen.py17
-rw-r--r--extern/cuew/src/cuew.c2
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.c2
-rw-r--r--intern/cycles/app/cycles_standalone.cpp32
-rw-r--r--intern/cycles/app/cycles_xml.cpp11
-rw-r--r--intern/cycles/blender/addon/__init__.py14
-rw-r--r--intern/cycles/blender/addon/engine.py15
-rw-r--r--intern/cycles/blender/addon/properties.py3
-rw-r--r--intern/cycles/blender/addon/ui.py10
-rw-r--r--intern/cycles/blender/addon/version_update.py56
-rw-r--r--intern/cycles/blender/blender_camera.cpp37
-rw-r--r--intern/cycles/blender/blender_curves.cpp32
-rw-r--r--intern/cycles/blender/blender_mesh.cpp76
-rw-r--r--intern/cycles/blender/blender_object.cpp80
-rw-r--r--intern/cycles/blender/blender_object_cull.cpp2
-rw-r--r--intern/cycles/blender/blender_python.cpp56
-rw-r--r--intern/cycles/blender/blender_session.cpp315
-rw-r--r--intern/cycles/blender/blender_session.h19
-rw-r--r--intern/cycles/blender/blender_shader.cpp53
-rw-r--r--intern/cycles/blender/blender_sync.cpp62
-rw-r--r--intern/cycles/blender/blender_sync.h34
-rw-r--r--intern/cycles/blender/blender_texture.cpp5
-rw-r--r--intern/cycles/blender/blender_texture.h2
-rw-r--r--intern/cycles/blender/blender_util.h54
-rw-r--r--intern/cycles/cmake/external_libs.cmake2
-rw-r--r--intern/cycles/graph/node_type.cpp2
-rw-r--r--intern/cycles/graph/node_xml.cpp23
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/bvh/bvh_nodes.h1
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h2
-rw-r--r--intern/cycles/kernel/bvh/qbvh_shadow_all.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_transparent.h29
-rw-r--r--intern/cycles/kernel/geom/geom_attribute.h5
-rw-r--r--intern/cycles/kernel/geom/geom_curve_intersect.h3
-rw-r--r--intern/cycles/kernel/geom/geom_object.h160
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h20
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h8
-rw-r--r--intern/cycles/kernel/kernel_bake.h40
-rw-r--r--intern/cycles/kernel/kernel_camera.h76
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h1
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h3
-rw-r--r--intern/cycles/kernel/kernel_emission.h16
-rw-r--r--intern/cycles/kernel/kernel_light.h151
-rw-r--r--intern/cycles/kernel/kernel_math.h1
-rw-r--r--intern/cycles/kernel/kernel_path.h90
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h53
-rw-r--r--intern/cycles/kernel/kernel_path_state.h51
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h10
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h17
-rw-r--r--intern/cycles/kernel/kernel_shader.h75
-rw-r--r--intern/cycles/kernel/kernel_shadow.h3
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h155
-rw-r--r--intern/cycles/kernel/kernel_textures.h18
-rw-r--r--intern/cycles/kernel/kernel_types.h200
-rw-r--r--intern/cycles/kernel/kernel_volume.h38
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp2
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp91
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl19
-rw-r--r--intern/cycles/kernel/shaders/node_bevel.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_glass_bsdf.osl11
-rw-r--r--intern/cycles/kernel/shaders/node_glossy_bsdf.osl10
-rw-r--r--intern/cycles/kernel/shaders/node_principled_volume.osl95
-rw-r--r--intern/cycles/kernel/shaders/node_refraction_bsdf.osl5
-rw-r--r--intern/cycles/kernel/split/kernel_indirect_subsurface.h35
-rw-r--r--intern/cycles/kernel/split/kernel_next_iteration_setup.h63
-rw-r--r--intern/cycles/kernel/split/kernel_queue_enqueue.h1
-rw-r--r--intern/cycles/kernel/split/kernel_shader_eval.h2
-rw-r--r--intern/cycles/kernel/split/kernel_shader_setup.h10
-rw-r--r--intern/cycles/kernel/split/kernel_split_common.h7
-rw-r--r--intern/cycles/kernel/split/kernel_subsurface_scatter.h25
-rw-r--r--intern/cycles/kernel/svm/svm.h5
-rw-r--r--intern/cycles/kernel/svm/svm_bevel.h2
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h141
-rw-r--r--intern/cycles/kernel/svm/svm_mapping.h1
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h3
-rw-r--r--intern/cycles/kernel/svm/svm_types.h1
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h1
-rw-r--r--intern/cycles/render/CMakeLists.txt1
-rw-r--r--intern/cycles/render/attribute.cpp53
-rw-r--r--intern/cycles/render/attribute.h3
-rw-r--r--intern/cycles/render/bake.cpp2
-rw-r--r--intern/cycles/render/buffers.cpp33
-rw-r--r--intern/cycles/render/buffers.h1
-rw-r--r--intern/cycles/render/camera.cpp154
-rw-r--r--intern/cycles/render/camera.h28
-rw-r--r--intern/cycles/render/graph.h1
-rw-r--r--intern/cycles/render/image.cpp161
-rw-r--r--intern/cycles/render/image.h34
-rw-r--r--intern/cycles/render/light.cpp141
-rw-r--r--intern/cycles/render/mesh.cpp247
-rw-r--r--intern/cycles/render/mesh.h21
-rw-r--r--intern/cycles/render/mesh_volume.cpp586
-rw-r--r--intern/cycles/render/nodes.cpp274
-rw-r--r--intern/cycles/render/nodes.h35
-rw-r--r--intern/cycles/render/object.cpp293
-rw-r--r--intern/cycles/render/object.h56
-rw-r--r--intern/cycles/render/osl.cpp39
-rw-r--r--intern/cycles/render/osl.h2
-rw-r--r--intern/cycles/render/particles.cpp22
-rw-r--r--intern/cycles/render/scene.cpp13
-rw-r--r--intern/cycles/render/scene.h18
-rw-r--r--intern/cycles/render/session.cpp14
-rw-r--r--intern/cycles/render/session.h8
-rw-r--r--intern/cycles/render/shader.cpp24
-rw-r--r--intern/cycles/render/shader.h1
-rw-r--r--intern/cycles/render/svm.cpp11
-rw-r--r--intern/cycles/render/svm.h1
-rw-r--r--intern/cycles/util/CMakeLists.txt1
-rw-r--r--intern/cycles/util/util_math_float3.h10
-rw-r--r--intern/cycles/util/util_math_int3.h15
-rw-r--r--intern/cycles/util/util_projection.h177
-rw-r--r--intern/cycles/util/util_transform.cpp50
-rw-r--r--intern/cycles/util/util_transform.h187
-rw-r--r--intern/cycles/util/util_vector.h12
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h49
-rw-r--r--intern/gawain/CMakeLists.txt3
-rw-r--r--intern/gawain/gawain/gwn_batch.h56
-rw-r--r--intern/gawain/gawain/gwn_batch_private.h30
-rw-r--r--intern/gawain/gawain/gwn_buffer_id.h4
-rw-r--r--intern/gawain/gawain/gwn_context.h34
-rw-r--r--intern/gawain/gawain/gwn_element.h15
-rw-r--r--intern/gawain/gawain/gwn_shader_interface.h8
-rw-r--r--intern/gawain/gawain/gwn_vertex_array_id.h34
-rw-r--r--intern/gawain/gawain/gwn_vertex_buffer.h36
-rw-r--r--intern/gawain/gawain/gwn_vertex_format.h12
-rw-r--r--intern/gawain/src/gwn_batch.c532
-rw-r--r--intern/gawain/src/gwn_buffer_id.cpp45
-rw-r--r--intern/gawain/src/gwn_element.c120
-rw-r--r--intern/gawain/src/gwn_immediate.c10
-rw-r--r--intern/gawain/src/gwn_shader_interface.c61
-rw-r--r--intern/gawain/src/gwn_vertex_array_id.cpp170
-rw-r--r--intern/gawain/src/gwn_vertex_buffer.c169
-rw-r--r--intern/gawain/src/gwn_vertex_format.c2
-rw-r--r--intern/ghost/CMakeLists.txt3
-rw-r--r--intern/ghost/GHOST_C-api.h32
-rw-r--r--intern/ghost/GHOST_IContext.h78
-rw-r--r--intern/ghost/GHOST_ISystem.h15
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp28
-rw-r--r--intern/ghost/intern/GHOST_Context.h9
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h6
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm39
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp11
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.h6
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp35
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.h6
-rw-r--r--intern/ghost/intern/GHOST_ContextNone.cpp6
-rw-r--r--intern/ghost/intern/GHOST_ContextNone.h6
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.cpp12
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.h6
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp133
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.h10
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h19
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm70
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp94
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h15
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp99
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h20
-rw-r--r--intern/ghost/intern/GHOST_TaskbarX11.cpp130
-rw-r--r--intern/ghost/intern/GHOST_TaskbarX11.h45
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp22
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h7
-rw-r--r--intern/openvdb/intern/openvdb_dense_convert.cc24
-rw-r--r--intern/openvdb/intern/openvdb_dense_convert.h45
-rw-r--r--intern/openvdb/openvdb_capi.cc18
-rw-r--r--intern/openvdb/openvdb_capi.h24
m---------release/datafiles/locale0
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/addon_utils.py14
-rw-r--r--release/scripts/modules/bpy/path.py5
-rw-r--r--release/scripts/modules/bpy_types.py25
-rw-r--r--release/scripts/presets/camera/1_colon_2.3_inch.py (renamed from release/scripts/presets/camera/1__colon__2.3_inch.py)0
-rw-r--r--release/scripts/presets/camera/1_colon_2.5_inch.py (renamed from release/scripts/presets/camera/1__colon__2.5_inch.py)0
-rw-r--r--release/scripts/presets/camera/2_colon_3_inch.py (renamed from release/scripts/presets/camera/2__colon__3_inch.py)0
-rw-r--r--release/scripts/presets/camera/4_colon_3_inch.py (renamed from release/scripts/presets/camera/4__colon__3_inch.py)0
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py98
-rw-r--r--release/scripts/startup/bl_operators/wm.py33
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_workspace.py56
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py18
-rw-r--r--release/scripts/startup/bl_ui/space_time.py2
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py15
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h4
-rw-r--r--source/blender/blenkernel/BKE_editlattice.h34
-rw-r--r--source/blender/blenkernel/BKE_global.h22
-rw-r--r--source/blender/blenkernel/BKE_group.h6
-rw-r--r--source/blender/blenkernel/BKE_icons.h8
-rw-r--r--source/blender/blenkernel/BKE_layer.h30
-rw-r--r--source/blender/blenkernel/BKE_mesh.h48
-rw-r--r--source/blender/blenkernel/BKE_modifier.h15
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h1
-rw-r--r--source/blender/blenkernel/BKE_nla.h24
-rw-r--r--source/blender/blenkernel/BKE_node.h9
-rw-r--r--source/blender/blenkernel/BKE_object.h123
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h3
-rw-r--r--source/blender/blenkernel/BKE_scene.h3
-rw-r--r--source/blender/blenkernel/BKE_screen.h2
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h2
-rw-r--r--source/blender/blenkernel/BKE_workspace.h3
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c16
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c41
-rw-r--r--source/blender/blenkernel/intern/armature_update.c25
-rw-r--r--source/blender/blenkernel/intern/collection.c16
-rw-r--r--source/blender/blenkernel/intern/collision.c16
-rw-r--r--source/blender/blenkernel/intern/constraint.c7
-rw-r--r--source/blender/blenkernel/intern/curve.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c8
-rw-r--r--source/blender/blenkernel/intern/editlattice.c147
-rw-r--r--source/blender/blenkernel/intern/fcurve.c10
-rw-r--r--source/blender/blenkernel/intern/group.c16
-rw-r--r--source/blender/blenkernel/intern/icons.c27
-rw-r--r--source/blender/blenkernel/intern/idprop.c5
-rw-r--r--source/blender/blenkernel/intern/ipo.c2
-rw-r--r--source/blender/blenkernel/intern/layer.c29
-rw-r--r--source/blender/blenkernel/intern/library_query.c6
-rw-r--r--source/blender/blenkernel/intern/library_remap.c33
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c7
-rw-r--r--source/blender/blenkernel/intern/material.c15
-rw-r--r--source/blender/blenkernel/intern/mesh.c23
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c292
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c20
-rw-r--r--source/blender/blenkernel/intern/movieclip.c23
-rw-r--r--source/blender/blenkernel/intern/nla.c85
-rw-r--r--source/blender/blenkernel/intern/node.c7
-rw-r--r--source/blender/blenkernel/intern/object.c4
-rw-r--r--source/blender/blenkernel/intern/object_deform.c64
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c14
-rw-r--r--source/blender/blenkernel/intern/object_update.c21
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/particle_child.c2
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c2
-rw-r--r--source/blender/blenkernel/intern/particle_system.c17
-rw-r--r--source/blender/blenkernel/intern/pointcache.c54
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c50
-rw-r--r--source/blender/blenkernel/intern/scene.c207
-rw-r--r--source/blender/blenkernel/intern/sequencer.c57
-rw-r--r--source/blender/blenkernel/intern/smoke.c6
-rw-r--r--source/blender/blenkernel/intern/texture.c10
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.c14
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenlib/BLI_array.h49
-rw-r--r--source/blender/blenlib/BLI_assert.h111
-rw-r--r--source/blender/blenlib/BLI_console.h42
-rw-r--r--source/blender/blenlib/BLI_ghash.h4
-rw-r--r--source/blender/blenlib/BLI_hash.h12
-rw-r--r--source/blender/blenlib/BLI_iterator.h2
-rw-r--r--source/blender/blenlib/BLI_link_utils.h12
-rw-r--r--source/blender/blenlib/BLI_math_base.h1
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h6
-rw-r--r--source/blender/blenlib/BLI_utildefines.h73
-rw-r--r--source/blender/blenlib/BLI_voronoi_2d.h6
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/intern/BLI_array.c20
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c4
-rw-r--r--source/blender/blenlib/intern/array_store.c9
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c2
-rw-r--r--source/blender/blenlib/intern/jitter_2d.c2
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c2
-rw-r--r--source/blender/blenlib/intern/math_bits_inline.c4
-rw-r--r--source/blender/blenlib/intern/math_color.c185
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c7
-rw-r--r--source/blender/blenlib/intern/rand.c6
-rw-r--r--source/blender/blenlib/intern/storage.c2
-rw-r--r--source/blender/blenlib/intern/string.c4
-rw-r--r--source/blender/blenlib/intern/task.c10
-rw-r--r--source/blender/blenloader/intern/readfile.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c18
-rw-r--r--source/blender/blenloader/intern/writefile.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c74
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c12
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c6
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c6
-rw-r--r--source/blender/bmesh/operators/bmo_edgenet.c28
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c10
-rw-r--r--source/blender/collada/AnimationExporter.cpp646
-rw-r--r--source/blender/collada/AnimationExporter.h37
-rw-r--r--source/blender/collada/AnimationImporter.cpp64
-rw-r--r--source/blender/collada/AnimationImporter.h4
-rw-r--r--source/blender/collada/ArmatureExporter.cpp6
-rw-r--r--source/blender/collada/ArmatureImporter.cpp11
-rw-r--r--source/blender/collada/ControllerExporter.cpp6
-rw-r--r--source/blender/collada/DocumentExporter.cpp33
-rw-r--r--source/blender/collada/DocumentExporter.h9
-rw-r--r--source/blender/collada/DocumentImporter.cpp21
-rw-r--r--source/blender/collada/EffectExporter.cpp4
-rw-r--r--source/blender/collada/ExportSettings.h29
-rw-r--r--source/blender/collada/ImageExporter.cpp4
-rw-r--r--source/blender/collada/ImportSettings.h7
-rw-r--r--source/blender/collada/MeshImporter.cpp10
-rw-r--r--source/blender/collada/SceneExporter.cpp11
-rw-r--r--source/blender/collada/SceneExporter.h5
-rw-r--r--source/blender/collada/collada.cpp102
-rw-r--r--source/blender/collada/collada.h49
-rw-r--r--source/blender/collada/collada_internal.cpp6
-rw-r--r--source/blender/collada/collada_internal.h4
-rw-r--r--source/blender/collada/collada_utils.cpp205
-rw-r--r--source/blender/collada/collada_utils.h12
-rw-r--r--source/blender/compositor/CMakeLists.txt1
-rw-r--r--source/blender/compositor/operations/COM_MapRangeOperation.cpp5
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h37
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h16
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc93
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_map.cc64
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_map.h69
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc235
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc171
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc143
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc95
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc35
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h15
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h1
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc3
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc20
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc2
-rw-r--r--source/blender/draw/CMakeLists.txt10
-rw-r--r--source/blender/draw/DRW_engine.h16
-rw-r--r--source/blender/draw/engines/clay/clay_engine.c473
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_copy.glsl10
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_frag.glsl73
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_fxaa.glsl18
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl44
-rw-r--r--source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl6
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c10
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c55
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c410
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c220
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c249
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h45
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c130
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c26
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl23
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl1
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl145
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl4
-rw-r--r--source/blender/draw/intern/DRW_render.h51
-rw-r--r--source/blender/draw/intern/draw_cache.c7
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c59
-rw-r--r--source/blender/draw/intern/draw_common.c9
-rw-r--r--source/blender/draw/intern/draw_instance_data.c240
-rw-r--r--source/blender/draw/intern/draw_instance_data.h9
-rw-r--r--source/blender/draw/intern/draw_manager.c2940
-rw-r--r--source/blender/draw/intern/draw_manager.h358
-rw-r--r--source/blender/draw/intern/draw_manager_data.c934
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c1076
-rw-r--r--source/blender/draw/intern/draw_manager_framebuffer.c189
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c126
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c377
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c215
-rw-r--r--source/blender/draw/modes/object_mode.c113
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl14
-rw-r--r--source/blender/editors/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/anim_filter.c74
-rw-r--r--source/blender/editors/animation/keyframing.c4
-rw-r--r--source/blender/editors/armature/CMakeLists.txt1
-rw-r--r--source/blender/editors/armature/armature_add.c24
-rw-r--r--source/blender/editors/armature/armature_naming.c17
-rw-r--r--source/blender/editors/armature/armature_select.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c78
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c6
-rw-r--r--source/blender/editors/armature/editarmature_undo.c112
-rw-r--r--source/blender/editors/armature/pose_edit.c12
-rw-r--r--source/blender/editors/armature/pose_lib.c34
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/curve_intern.h5
-rw-r--r--source/blender/editors/curve/editcurve.c131
-rw-r--r--source/blender/editors/curve/editcurve_paint.c2
-rw-r--r--source/blender/editors/curve/editcurve_select.c4
-rw-r--r--source/blender/editors/curve/editcurve_undo.c163
-rw-r--r--source/blender/editors/curve/editfont.c2
-rw-r--r--source/blender/editors/include/ED_armature.h8
-rw-r--r--source/blender/editors/include/ED_curve.h4
-rw-r--r--source/blender/editors/include/ED_lattice.h18
-rw-r--r--source/blender/editors/include/ED_mesh.h6
-rw-r--r--source/blender/editors/include/ED_object.h37
-rw-r--r--source/blender/editors/include/ED_particle.h2
-rw-r--r--source/blender/editors/include/ED_scene.h7
-rw-r--r--source/blender/editors/include/ED_screen.h11
-rw-r--r--source/blender/editors/include/ED_uvedit.h84
-rw-r--r--source/blender/editors/include/ED_view3d.h2
-rw-r--r--source/blender/editors/interface/interface.c6
-rw-r--r--source/blender/editors/interface/interface_handlers.c4
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_ops.c10
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c3
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c3
-rw-r--r--source/blender/editors/interface/interface_templates.c4
-rw-r--r--source/blender/editors/interface/interface_widgets.c1
-rw-r--r--source/blender/editors/io/io_alembic.c8
-rw-r--r--source/blender/editors/io/io_collada.c123
-rw-r--r--source/blender/editors/lattice/CMakeLists.txt46
-rw-r--r--source/blender/editors/lattice/editlattice_select.c (renamed from source/blender/editors/object/object_lattice.c)514
-rw-r--r--source/blender/editors/lattice/editlattice_tools.c341
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c113
-rw-r--r--source/blender/editors/lattice/lattice_intern.h44
-rw-r--r--source/blender/editors/lattice/lattice_ops.c80
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editface.c260
-rw-r--r--source/blender/editors/mesh/editmesh_add.c7
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c5
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c119
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c7
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_path.c31
-rw-r--r--source/blender/editors/mesh/editmesh_select.c478
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c731
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c380
-rw-r--r--source/blender/editors/mesh/mesh_data.c31
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c377
-rw-r--r--source/blender/editors/mesh/meshtools.c116
-rw-r--r--source/blender/editors/metaball/CMakeLists.txt1
-rw-r--r--source/blender/editors/metaball/editmball_undo.c131
-rw-r--r--source/blender/editors/metaball/mball_edit.c95
-rw-r--r--source/blender/editors/object/CMakeLists.txt2
-rw-r--r--source/blender/editors/object/object_add.c12
-rw-r--r--source/blender/editors/object/object_bake.c8
-rw-r--r--source/blender/editors/object/object_bake_api.c41
-rw-r--r--source/blender/editors/object/object_edit.c134
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_intern.h10
-rw-r--r--source/blender/editors/object/object_modes.c318
-rw-r--r--source/blender/editors/object/object_ops.c33
-rw-r--r--source/blender/editors/object/object_relations.c83
-rw-r--r--source/blender/editors/object/object_select.c75
-rw-r--r--source/blender/editors/object/object_transform.c6
-rw-r--r--source/blender/editors/object/object_vgroup.c8
-rw-r--r--source/blender/editors/physics/CMakeLists.txt2
-rw-r--r--source/blender/editors/physics/particle_edit.c409
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c341
-rw-r--r--source/blender/editors/physics/particle_edit_utildefines.h50
-rw-r--r--source/blender/editors/physics/particle_object.c33
-rw-r--r--source/blender/editors/physics/physics_intern.h15
-rw-r--r--source/blender/editors/physics/physics_pointcache.c4
-rw-r--r--source/blender/editors/render/render_internal.c42
-rw-r--r--source/blender/editors/render/render_opengl.c8
-rw-r--r--source/blender/editors/render/render_preview.c2
-rw-r--r--source/blender/editors/scene/scene_edit.c36
-rw-r--r--source/blender/editors/screen/area.c8
-rw-r--r--source/blender/editors/screen/screen_context.c24
-rw-r--r--source/blender/editors/screen/screen_draw.c3
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/workspace_edit.c104
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c238
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c4
-rw-r--r--source/blender/editors/space_action/action_data.c4
-rw-r--r--source/blender/editors/space_action/action_select.c10
-rw-r--r--source/blender/editors/space_api/spacetypes.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c16
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c4
-rw-r--r--source/blender/editors/space_graph/graph_utils.c4
-rw-r--r--source/blender/editors/space_graph/space_graph.c7
-rw-r--r--source/blender/editors/space_nla/nla_channels.c8
-rw-r--r--source/blender/editors/space_nla/nla_draw.c22
-rw-r--r--source/blender/editors/space_nla/nla_edit.c22
-rw-r--r--source/blender/editors/space_nla/space_nla.c7
-rw-r--r--source/blender/editors/space_node/drawnode.c25
-rw-r--r--source/blender/editors/space_node/node_draw.c8
-rw-r--r--source/blender/editors/space_node/node_templates.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c59
-rw-r--r--source/blender/editors/space_view3d/drawobject.c6
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c27
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c204
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c96
-rw-r--r--source/blender/editors/transform/transform_conversions.c149
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator2d.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c18
-rw-r--r--source/blender/editors/util/ed_util.c43
-rw-r--r--source/blender/editors/util/editmode_undo.c260
-rw-r--r--source/blender/editors/util/numinput.c7
-rw-r--r--source/blender/editors/util/undo.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c267
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h31
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c641
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c14
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp5
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_batch.h4
-rw-r--r--source/blender/gpu/GPU_material.h19
-rw-r--r--source/blender/gpu/GPU_select.h1
-rw-r--r--source/blender/gpu/GPU_shader.h1
-rw-r--r--source/blender/gpu/GPU_texture.h3
-rw-r--r--source/blender/gpu/GPU_viewport.h6
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c24
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c264
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h25
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c2
-rw-r--r--source/blender/gpu/intern/gpu_material.c75
-rw-r--r--source/blender/gpu/intern/gpu_select.c12
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c112
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c26
-rw-r--r--source/blender/gpu/intern/gpu_shader.c3
-rw-r--r--source/blender/gpu/intern/gpu_texture.c13
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c179
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl123
-rw-r--r--source/blender/imbuf/intern/anim_movie.c4
-rw-r--r--source/blender/imbuf/intern/indexer.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp29
-rw-r--r--source/blender/makesdna/DNA_object_enums.h3
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h3
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h8
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h10
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesrna/RNA_access.h16
-rw-r--r--source/blender/makesrna/RNA_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_access.c62
-rw-r--r--source/blender/makesrna/intern/rna_animation.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c1
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c17
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c2
-rw-r--r--source/blender/makesrna/intern/rna_layer.c15
-rw-r--r--source/blender/makesrna/intern/rna_nla.c6
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c64
-rw-r--r--source/blender/makesrna/intern/rna_object.c11
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c87
-rw-r--r--source/blender/makesrna/intern/rna_render.c30
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c1
-rw-r--r--source/blender/makesrna/intern/rna_rna.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c8
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c125
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c21
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c53
-rw-r--r--source/blender/makesrna/intern/rna_ui.c22
-rw-r--r--source/blender/makesrna/intern/rna_wm.c11
-rw-r--r--source/blender/makesrna/intern/rna_wm_manipulator.c11
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c103
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c10
-rw-r--r--source/blender/modifiers/intern/MOD_array.c48
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c12
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c10
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c10
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c12
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c8
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c10
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c10
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c14
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c12
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c12
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c8
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c8
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c10
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c10
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c8
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c8
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c8
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c14
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c8
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c4
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c12
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c12
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c8
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c8
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c16
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c12
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c10
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c10
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c14
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c18
-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/shader/node_shader_util.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.c165
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.c2
-rw-r--r--source/blender/python/gawain/gwn_py_types.c4
-rw-r--r--source/blender/python/intern/bpy.c3
-rw-r--r--source/blender/python/intern/bpy_app.c5
-rw-r--r--source/blender/python/intern/bpy_msgbus.c4
-rw-r--r--source/blender/python/intern/bpy_rna.c37
-rw-r--r--source/blender/python/intern/bpy_rna.h4
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c8
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c18
-rw-r--r--source/blender/render/extern/include/RE_engine.h9
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h13
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h17
-rw-r--r--source/blender/render/intern/include/pointdensity.h5
-rw-r--r--source/blender/render/intern/include/render_result.h23
-rw-r--r--source/blender/render/intern/include/render_types.h3
-rw-r--r--source/blender/render/intern/include/renderdatabase.h3
-rw-r--r--source/blender/render/intern/source/convertblender.c155
-rw-r--r--source/blender/render/intern/source/envmap.c4
-rw-r--r--source/blender/render/intern/source/external_engine.c78
-rw-r--r--source/blender/render/intern/source/initrender.c5
-rw-r--r--source/blender/render/intern/source/pipeline.c156
-rw-r--r--source/blender/render/intern/source/pointdensity.c58
-rw-r--r--source/blender/render/intern/source/render_result.c23
-rw-r--r--source/blender/render/intern/source/render_texture.c4
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h7
-rw-r--r--source/blender/windowmanager/WM_keymap.h3
-rw-r--r--source/blender/windowmanager/intern/wm.c16
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files.c8
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c31
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c35
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c37
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c6
-rw-r--r--source/blender/windowmanager/intern/wm_window.c114
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_api.h2
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_types.h1
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c12
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h1
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c8
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c2
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c5
-rw-r--r--source/blender/windowmanager/wm_window.h1
-rw-r--r--source/blenderplayer/CMakeLists.txt4
-rw-r--r--source/blenderplayer/bad_level_call_stubs/CMakeLists.txt1
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c46
-rw-r--r--source/creator/CMakeLists.txt4
-rw-r--r--source/creator/creator_args.c53
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp4
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp2
m---------source/tools0
-rw-r--r--tests/python/CMakeLists.txt21
-rwxr-xr-xtests/python/alembic_tests.py59
-rw-r--r--tests/python/collada/CMakeLists.txt66
-rw-r--r--tests/python/collada/animation/test_animation_simple.py280
-rw-r--r--tests/python/collada/mesh/test_mesh_simple.py154
-rwxr-xr-xtests/python/ffmpeg_tests.py86
-rwxr-xr-xtests/python/modules/test_utils.py105
-rw-r--r--tests/python/view_layer/CMakeLists.txt2
-rw-r--r--tests/python/view_layer/test_group_e.py72
-rw-r--r--tests/python/view_layer/test_make_single_user.py54
705 files changed, 22713 insertions, 13018 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bfff781e922..d45cfefcb78 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1461,6 +1461,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
"/wd4267" # conversion from 'size_t' to 'type', possible loss of data
"/wd4305" # truncation from 'type1' to 'type2'
"/wd4800" # forcing value to bool 'true' or 'false'
+ "/wd4828" # The file contains a character that is illegal
# errors:
"/we4013" # 'function' undefined; assuming extern returning int
"/we4133" # incompatible pointer types
diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake
index 2c6bf195e07..46840b7ead4 100644
--- a/build_files/build_environment/cmake/boost.cmake
+++ b/build_files/build_environment/cmake/boost.cmake
@@ -53,17 +53,20 @@ if(WIN32)
if(BUILD_MODE STREQUAL Release)
set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-1_60/ ${HARVEST_TARGET}/boost/include/)
endif()
+ set(BOOST_PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/boost/src/external_boost < ${PATCH_DIR}/boost.diff)
elseif(APPLE)
set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
set(BOOST_BUILD_COMMAND ./bjam)
set(BOOST_BUILD_OPTIONS toolset=clang cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} --disable-icu boost.locale.icu=off)
set(BOOST_HARVEST_CMD echo .)
+ set(BOOST_PATCH_COMMAND echo .)
else()
set(BOOST_HARVEST_CMD echo .)
set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
set(BOOST_BUILD_COMMAND ./bjam)
set(BOOST_BUILD_OPTIONS cxxflags=${PLATFORM_CXXFLAGS} --disable-icu boost.locale.icu=off)
+ set(BOOST_PATCH_COMMAND echo .)
endif()
set(BOOST_OPTIONS
@@ -96,6 +99,7 @@ ExternalProject_Add(external_boost
URL_HASH MD5=${BOOST_MD5}
PREFIX ${BUILD_DIR}/boost
UPDATE_COMMAND ""
+ PATCH_COMMAND ${BOOST_PATCH_COMMAND}
CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND}
BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=x86 address-model=${BOOST_ADDRESS_MODEL} variant=${BOOST_BUILD_TYPE} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install
BUILD_IN_SOURCE 1
diff --git a/build_files/build_environment/patches/boost.diff b/build_files/build_environment/patches/boost.diff
new file mode 100644
index 00000000000..ea3ec035518
--- /dev/null
+++ b/build_files/build_environment/patches/boost.diff
@@ -0,0 +1,15 @@
+--- a/boost/config/compiler/visualc.hpp 2015-12-08 11:55:19 -0700
++++ b/boost/config/compiler/visualc.hpp 2018-03-17 10:29:52 -0600
+@@ -287,12 +287,3 @@
+ # define BOOST_COMPILER "Microsoft Visual C++ version " BOOST_STRINGIZE(BOOST_COMPILER_VERSION)
+ #endif
+
+-//
+-// last known and checked version is 19.00.23026 (VC++ 2015 RTM):
+-#if (_MSC_VER > 1900)
+-# if defined(BOOST_ASSERT_CONFIG)
+-# error "Unknown compiler version - please run the configure tests and report the results"
+-# else
+-# pragma message("Unknown compiler version - please run the configure tests and report the results")
+-# endif
+-#endif
diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg
deleted file mode 100644
index e3101430e50..00000000000
--- a/build_files/buildbot/master.cfg
+++ /dev/null
@@ -1,368 +0,0 @@
-# -*- python -*-
-# ex: set syntax=python:
-
-# <pep8 compliant>
-
-# List of the branches being built automatically overnight
-NIGHT_SCHEDULE_BRANCHES = [None, "blender2.8"]
-
-# List of the branches available for force build
-FORCE_SCHEDULE_BRANCHES = ["master", "blender2.8", "experimental-build"]
-
-"""
-Stock Twisted directory lister doesn't provide any information about last file
-modification time, we hack the class a bit in order to have such functionaliity
-:)
-"""
-
-from buildbot.status.web.base import DirectoryLister
-
-
-def get_files_and_directories(self, directory):
- from twisted.web.static import (getTypeAndEncoding,
- formatFileSize)
- import urllib
- import cgi
- import time
- import os
- files = []
- dirs = []
- for path in directory:
- url = urllib.quote(path, "/")
- escapedPath = cgi.escape(path)
- lastmodified = time.ctime(os.path.getmtime(
- os.path.join(self.path, path)))
- if os.path.isdir(os.path.join(self.path, path)):
- url = url + '/'
- dirs.append({'text': escapedPath + "/", 'href': url,
- 'size': '', 'type': '[Directory]',
- 'encoding': '',
- 'lastmodified': lastmodified})
- else:
- mimetype, encoding = getTypeAndEncoding(path, self.contentTypes,
- self.contentEncodings,
- self.defaultType)
- try:
- size = os.stat(os.path.join(self.path, path)).st_size
- except OSError:
- continue
- files.append({
- 'text': escapedPath, "href": url,
- 'type': '[%s]' % mimetype,
- 'encoding': (encoding and '[%s]' % encoding or ''),
- 'size': formatFileSize(size),
- 'lastmodified': lastmodified})
- return dirs, files
-DirectoryLister._getFilesAndDirectories = get_files_and_directories
-
-# Dictionary that the buildmaster pays attention to.
-c = BuildmasterConfig = {}
-
-# BUILD SLAVES
-#
-# We load the slaves and their passwords from a separator file, so we can have
-# this one in SVN.
-
-from buildbot.buildslave import BuildSlave
-import master_private
-
-c['slaves'] = []
-
-for slave in master_private.slaves:
- c['slaves'].append(BuildSlave(slave['name'], slave['password']))
-
-# TCP port through which slaves connect
-
-c['slavePortnum'] = 9989
-
-# CHANGE SOURCES
-
-from buildbot.changes.svnpoller import SVNPoller
-from buildbot.changes.gitpoller import GitPoller
-
-c['change_source'] = GitPoller(
- 'git://git.blender.org/blender.git',
- pollinterval=1200)
-
-
-# CODEBASES
-#
-# Allow to control separately things like branches for each repo and submodules.
-
-all_repositories = {
- r'git://git.blender.org/blender.git': 'blender',
- r'git://git.blender.org/blender-translations.git': 'blender-translations',
- r'git://git.blender.org/blender-addons.git': 'blender-addons',
- r'git://git.blender.org/blender-addons-contrib.git': 'blender-addons-contrib',
- r'git://git.blender.org/blender-dev-tools.git': 'blender-dev-tools',
- r'https://svn.blender.org/svnroot/bf-blender/': 'lib svn',
-}
-
-
-def codebaseGenerator(chdict):
- return all_repositories[chdict['repository']]
-
-c['codebaseGenerator'] = codebaseGenerator
-
-
-# SCHEDULERS
-#
-# Decide how to react to incoming changes.
-
-# from buildbot.scheduler import Scheduler
-from buildbot.schedulers import timed, forcesched
-
-c['schedulers'] = []
-
-
-def schedule_force_build(name):
- c['schedulers'].append(forcesched.ForceScheduler(name='force ' + name,
- builderNames=[name],
- codebases=[forcesched.CodebaseParameter(
- codebase="blender",
- branch=forcesched.ChoiceStringParameter(
- name="branch", choices=FORCE_SCHEDULE_BRANCHES, default="master"),
- # Do not hide revision, can be handy!
- repository=forcesched.FixedParameter(name="repository", default="", hide=True),
- project=forcesched.FixedParameter(name="project", default="", hide=True)),
- # For now, hide other codebases.
- forcesched.CodebaseParameter(hide=True, codebase="blender-translations"),
- forcesched.CodebaseParameter(
- codebase="blender-addons",
- branch=forcesched.ChoiceStringParameter(
- name="branch", choices=["master", "blender2.8"], default="master"),
- repository=forcesched.FixedParameter(name="repository", default="", hide=True),
- project=forcesched.FixedParameter(name="project", default="", hide=True),
- revision=forcesched.FixedParameter(name="revision", default="", hide=True),
- ),
- forcesched.CodebaseParameter(hide=True, codebase="blender-addons-contrib"),
- forcesched.CodebaseParameter(hide=True, codebase="blender-dev-tools"),
- forcesched.CodebaseParameter(hide=True, codebase="lib svn")],
- properties=[]))
-
-
-def schedule_build(name, hour, minute=0):
- for current_branch in NIGHT_SCHEDULE_BRANCHES:
- scheduler_name = "nightly " + name
- if current_branch:
- scheduler_name += ' ' + current_branch
- # Use special addons submodule branch when building blender2.8 branch.
- addons_branch = "master"
- if current_branch == "blender2.8":
- addons_branch = "blender2.8"
- c['schedulers'].append(timed.Nightly(name=scheduler_name,
- codebases={
- "blender": {"repository": ""},
- "blender-translations": {"repository": "", "branch": "master"},
- "blender-addons": {"repository": "", "branch": addons_branch},
- "blender-addons-contrib": {"repository": "", "branch": "master"},
- "blender-dev-tools": {"repository": "", "branch": "master"},
- "lib svn": {"repository": "", "branch": "trunk"}},
- branch=current_branch,
- builderNames=[name],
- hour=hour,
- minute=minute))
-
-
-# BUILDERS
-#
-# The 'builders' list defines the Builders, which tell Buildbot how to
-# perform a build: what steps, and which slaves can execute them.
-# Note that any particular build will only take place on one slave.
-
-from buildbot.process.factory import BuildFactory
-from buildbot.process.properties import Interpolate
-from buildbot.steps.source import SVN
-from buildbot.steps.source import Git
-from buildbot.steps.shell import ShellCommand
-from buildbot.steps.shell import Compile
-from buildbot.steps.shell import Test
-from buildbot.steps.transfer import FileUpload
-from buildbot.steps.master import MasterShellCommand
-from buildbot.config import BuilderConfig
-
-# add builder utility
-
-c['builders'] = []
-buildernames = []
-
-
-def add_builder(c, name, libdir, factory, branch='',
- rsync=False, hour=3, minute=0):
- slavenames = []
-
- for slave in master_private.slaves:
- if name in slave['builders']:
- slavenames.append(slave['name'])
-
- if len(slavenames) > 0:
- f = factory(name, libdir, branch, rsync)
- c['builders'].append(BuilderConfig(name=name,
- slavenames=slavenames,
- factory=f,
- category='blender'))
- buildernames.append(name)
-
- schedule_build(name, hour, minute)
- schedule_force_build(name)
-
-# common steps
-
-
-def git_submodule_step(submodule):
- return Git(name=submodule + '.git',
- repourl='git://git.blender.org/' + submodule + '.git',
- mode='update',
- codebase=submodule,
- workdir=submodule + '.git')
-
-
-def git_step(branch=''):
- if branch:
- return Git(name='blender.git',
- repourl='git://git.blender.org/blender.git',
- mode='update',
- branch=branch,
- codebase='blender',
- workdir='blender.git',
- submodules=True)
- else:
- return Git(name='blender.git',
- repourl='git://git.blender.org/blender.git',
- mode='update',
- codebase='blender',
- workdir='blender.git',
- submodules=True)
-
-
-def git_submodules_update():
- command = ['git', 'submodule', 'update', '--remote']
- return ShellCommand(name='Submodules Update',
- command=command,
- description='updating',
- descriptionDone='up to date',
- workdir='blender.git')
-
-
-def lib_svn_step(dir):
- return SVN(name='lib svn',
- baseURL='https://svn.blender.org/svnroot/bf-blender/%%BRANCH%%/lib/' + dir,
- codebase='lib svn',
- mode='update',
- defaultBranch='trunk',
- workdir='lib/' + dir)
-
-
-def rsync_step(id, branch, rsync_script):
- return ShellCommand(name='rsync',
- command=['python', rsync_script, id, branch],
- description='uploading',
- descriptionDone='uploaded',
- workdir='install')
-
-# generic builder
-
-
-def generic_builder(id, libdir='', branch='', rsync=False):
- filename = 'uploaded/buildbot_upload_' + id + '.zip'
- compile_script = '../blender.git/build_files/buildbot/slave_compile.py'
- test_script = '../blender.git/build_files/buildbot/slave_test.py'
- pack_script = '../blender.git/build_files/buildbot/slave_pack.py'
- rsync_script = '../blender.git/build_files/buildbot/slave_rsync.py'
- unpack_script = 'master_unpack.py'
-
- f = BuildFactory()
- if libdir != '':
- f.addStep(lib_svn_step(libdir))
-
- for submodule in ('blender-translations',
- 'blender-addons',
- 'blender-addons-contrib',
- 'blender-dev-tools'):
- f.addStep(git_submodule_step(submodule))
-
- f.addStep(git_step(branch))
- f.addStep(git_submodules_update())
-
- f.addStep(Compile(command=['python', compile_script, id], timeout=3600))
- f.addStep(Test(command=['python', test_script, id]))
- f.addStep(ShellCommand(name='package',
- command=['python', pack_script, id, branch or Interpolate('%(src:blender:branch)s')],
- description='packaging',
- descriptionDone='packaged'))
- if rsync:
- f.addStep(rsync_step(id, branch, rsync_script))
- else:
- f.addStep(FileUpload(name='upload',
- slavesrc='buildbot_upload.zip',
- masterdest=filename,
- maxsize=180 * 1024 * 1024,
- workdir='install'))
- f.addStep(MasterShellCommand(name='unpack',
- command=['python2.7', unpack_script, filename],
- description='unpacking',
- descriptionDone='unpacked'))
- return f
-
-# Builders
-
-add_builder(c, 'mac_x86_64_10_9_cmake', 'darwin', generic_builder, hour=1)
-add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=2)
-add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=1)
-add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=1)
-add_builder(c, 'win64_cmake_vc2013', 'win64_vc12', generic_builder, hour=2)
-add_builder(c, 'win32_cmake_vc2015', 'windows_vc14', generic_builder, hour=3)
-add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=4)
-
-# STATUS TARGETS
-#
-# 'status' is a list of Status Targets. The results of each build will be
-# pushed to these targets. buildbot/status/*.py has a variety to choose from,
-# including web pages, email senders, and IRC bots.
-
-c['status'] = []
-
-from buildbot.status import html
-from buildbot.status.web import authz
-from buildbot.status.web import auth
-
-users = []
-for slave in master_private.slaves:
- users += [(slave['name'], slave['password'])]
-
-authz_cfg = authz.Authz(
- auth=auth.BasicAuth(users),
- # change any of these to True to enable; see the manual for more
- # options
- gracefulShutdown=False,
- forceBuild=True, # use this to test your slave once it is set up
- forceAllBuilds=False,
- pingBuilder=False,
- stopBuild=True,
- stopAllBuilds=False,
- cancelPendingBuild=True,
-)
-
-c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg))
-#c['status'].append(html.WebStatus(http_port=8010))
-
-# PROJECT IDENTITY
-
-c['projectName'] = "Blender"
-c['projectURL'] = "http://www.blender.org"
-
-# the 'buildbotURL' string should point to the location where the buildbot's
-# internal web server (usually the html.WebStatus page) is visible. This
-# typically uses the port number set in the Waterfall 'status' entry, but
-# with an externally-visible host name which the buildbot cannot figure out
-# without some help.
-
-c['buildbotURL'] = "http://builder.blender.org/"
-
-# DB URL
-#
-# This specifies what database buildbot uses to store change and scheduler
-# state. You can leave this at its default for all but the largest
-# installations.
-
-c['db_url'] = "sqlite:///state.sqlite"
diff --git a/build_files/buildbot/master_unpack.py b/build_files/buildbot/master_unpack.py
deleted file mode 100644
index 157e244e210..00000000000
--- a/build_files/buildbot/master_unpack.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# Runs on Buildbot master, to unpack incoming unload.zip into latest
-# builds directory and remove older builds.
-
-# <pep8 compliant>
-
-import os
-import shutil
-import sys
-import zipfile
-
-
-# extension stripping
-def strip_extension(filename):
- extensions = '.zip', '.tar', '.bz2', '.gz', '.tgz', '.tbz', '.exe'
-
- for ext in extensions:
- if filename.endswith(ext):
- filename = filename[:-len(ext)]
-
- return filename
-
-
-# extract platform from package name
-def get_platform(filename):
- # name is blender-version-platform.extension. we want to get the
- # platform out, but there may be some variations, so we fiddle a
- # bit to handle current and hopefully future names
- filename = strip_extension(filename)
- filename = strip_extension(filename)
-
- tokens = filename.split("-")
- platforms = ('osx', 'mac', 'bsd',
- 'win', 'linux', 'source',
- 'irix', 'solaris')
- platform_tokens = []
- found = False
-
- for i, token in enumerate(tokens):
- if not found:
- for platform in platforms:
- if platform in token.lower():
- found = True
- break
-
- if found:
- platform_tokens += [token]
-
- return '-'.join(platform_tokens)
-
-
-def get_branch(filename):
- if filename.startswith("blender-2.8"):
- return "blender2.8"
-
- tokens = filename.split("-")
- branch = ""
-
- for token in tokens:
- if token == "blender":
- return branch
-
- if branch == "":
- branch = token
- else:
- branch = branch + "-" + token
-
- return ""
-
-# get filename
-if len(sys.argv) < 2:
- sys.stderr.write("Not enough arguments, expecting file to unpack\n")
- sys.exit(1)
-
-filename = sys.argv[1]
-
-# open zip file
-if not os.path.exists(filename):
- sys.stderr.write("File %r not found.\n" % filename)
- sys.exit(1)
-
-try:
- z = zipfile.ZipFile(filename, "r")
-except Exception as ex:
- sys.stderr.write('Failed to open zip file: %s\n' % str(ex))
- sys.exit(1)
-
-if len(z.namelist()) != 1:
- sys.stderr.write("Expected one file in %r." % filename)
- sys.exit(1)
-
-package = z.namelist()[0]
-packagename = os.path.basename(package)
-
-# detect platform and branch
-platform = get_platform(packagename)
-branch = get_branch(packagename)
-
-if platform == '':
- sys.stderr.write('Failed to detect platform ' +
- 'from package: %r\n' % packagename)
- sys.exit(1)
-
-# extract
-if not branch or branch == 'master':
- directory = 'public_html/download'
-elif branch == 'experimental-build':
- directory = 'public_html/download/experimental'
-else:
- directory = 'public_html/download'
-
-try:
- filename = os.path.join(directory, packagename)
- zf = z.open(package)
- f = file(filename, "wb")
-
- shutil.copyfileobj(zf, f)
- os.chmod(filename, 0644)
-
- zf.close()
- z.close()
-except Exception as ex:
- sys.stderr.write('Failed to unzip package: %s\n' % str(ex))
- sys.exit(1)
-
-# remove other files from the same platform and branch
-try:
- for f in os.listdir(directory):
- if get_platform(f) == platform and get_branch(f) == branch:
- if f != packagename:
- os.remove(os.path.join(directory, f))
-except Exception as ex:
- sys.stderr.write('Failed to remove old packages: %s\n' % str(ex))
- sys.exit(1)
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index f2f8edc614d..ff19bcce758 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -73,8 +73,9 @@ if 'cmake' in builder:
if builder.endswith('x86_64_10_9_cmake'):
cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
cmake_extra_options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')
- cmake_extra_options.append('-DCUDA_HOST_COMPILER=/usr/local/cuda-hack/clang')
- cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/nvcc')
+ # Used to trick CUDFA to see CLang as an older version.
+ # cmake_extra_options.append('-DCUDA_HOST_COMPILER=/usr/local/cuda-hack/clang')
+ # cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/nvcc')
elif builder.startswith('win'):
if builder.endswith('_vc2015'):
@@ -116,7 +117,7 @@ if 'cmake' in builder:
# Prepare CMake options needed to configure cuda binaries compilation, 64bit only.
if bits == 64:
cuda_cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=%s" % ('ON' if build_cubins else 'OFF'))
- cuda_cmake_options.append("-DCYCLES_CUDA_BINARIES_ARCH=sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61")
+ cuda_cmake_options.append("-DCYCLES_CUDA_BINARIES_ARCH=sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61;sm_70")
if build_cubins or 'cuda' in targets:
cuda_cmake_options.append("-DCUDA_64_BIT_DEVICE_CODE=ON")
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 7db26c3f7c0..1a5e6a3158a 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -9,6 +9,7 @@ set(WITH_INSTALL_PORTABLE ON CACHE BOOL "" FORCE)
set(WITH_SYSTEM_GLEW ON CACHE BOOL "" FORCE)
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
+set(WITH_BOOST OFF CACHE BOOL "" FORCE)
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
@@ -54,4 +55,3 @@ set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE)
-
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index e9d5c25b11e..dc657c7c445 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -596,6 +596,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_editor_mesh
bf_editor_metaball
bf_editor_object
+ bf_editor_lattice
bf_editor_armature
bf_editor_physics
bf_editor_render
@@ -1145,7 +1146,9 @@ endmacro()
# External libs may need 'signed char' to be default.
macro(remove_cc_flag_unsigned_char)
- if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|Intel)$")
+ if(CMAKE_COMPILER_IS_GNUCC OR
+ (CMAKE_C_COMPILER_ID MATCHES "Clang") OR
+ (CMAKE_C_COMPILER_ID MATCHES "Intel"))
remove_cc_flag("-funsigned-char")
elseif(MSVC)
remove_cc_flag("/J")
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index ca01e08afe9..534acab266a 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -31,6 +31,9 @@ endmacro()
if(NOT DEFINED LIBDIR)
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin)
+ # Prefer lib directory paths
+ file(GLOB LIB_SUBDIRS ${LIBDIR}/*)
+ set(CMAKE_PREFIX_PATH ${LIB_SUBDIRS})
else()
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
endif()
@@ -327,8 +330,8 @@ if(WITH_OPENVDB)
endif()
if(WITH_LLVM)
- set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
- set(LLVM_VERSION "3.4" CACHE STRING "Version of LLVM to use")
+ set(LLVM_ROOT_DIR ${LIBDIR}/llvm)
+ set(LLVM_VERSION 3.4)
if(EXISTS "${LLVM_ROOT_DIR}/bin/llvm-config")
set(LLVM_CONFIG "${LLVM_ROOT_DIR}/bin/llvm-config")
else()
@@ -365,7 +368,7 @@ if(WITH_LLVM)
endif()
if(WITH_CYCLES_OSL)
- set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
+ set(CYCLES_OSL ${LIBDIR}/osl)
find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
diff --git a/doc/doxygen/doxygen.source.h b/doc/doxygen/doxygen.source.h
index da58584ab36..ebc20940529 100644
--- a/doc/doxygen/doxygen.source.h
+++ b/doc/doxygen/doxygen.source.h
@@ -196,6 +196,10 @@
* \ingroup editors
*/
+/** \defgroup edlattice lattice
+ * \ingroup editors
+ */
+
/** \defgroup edmesh mesh
* \ingroup editors
*/
diff --git a/doc/guides/blender-guardedalloc.txt b/doc/guides/blender-guardedalloc.txt
index 44a9722a4e4..3db647a4e77 100644
--- a/doc/guides/blender-guardedalloc.txt
+++ b/doc/guides/blender-guardedalloc.txt
@@ -1,7 +1,7 @@
MEMORY MANAGEMENT IN BLENDER (guardedalloc)
-------------------------------------------
-NOTE: This file does not cover memutil and smart pointers and rerefence counted
+NOTE: This file does not cover memutil and smart pointers and reference counted
garbage collection, which are contained in the memutil module.
Blender takes care of dynamic memory allocation using a set of own functions
diff --git a/doc/python_api/examples/bpy.props.1.py b/doc/python_api/examples/bpy.props.1.py
index 51534628930..dd3a3ebc432 100644
--- a/doc/python_api/examples/bpy.props.1.py
+++ b/doc/python_api/examples/bpy.props.1.py
@@ -2,30 +2,56 @@
Operator Example
++++++++++++++++
-A common use of custom properties is for python based :class:`Operator` classes.
+A common use of custom properties is for python based :class:`Operator`
+classes. Test this code by running it in the text editor, or by clicking the
+button in the 3D Viewport's Tools panel. The latter will show the properties
+in the Redo panel and allow you to change them.
"""
-
import bpy
-class DialogOperator(bpy.types.Operator):
- bl_idname = "object.dialog_operator"
+class OBJECT_OT_property_example(bpy.types.Operator):
+ bl_idname = "object.property_example"
bl_label = "Property Example"
+ bl_options = {'REGISTER', 'UNDO'}
my_float = bpy.props.FloatProperty(name="Some Floating Point")
my_bool = bpy.props.BoolProperty(name="Toggle Option")
my_string = bpy.props.StringProperty(name="String Value")
def execute(self, context):
- print("Dialog Runs")
+ self.report({'INFO'}, 'F: %.2f B: %s S: %r' %
+ (self.my_float, self.my_bool, self.my_string))
+ print('My float:', self.my_float)
+ print('My bool:', self.my_bool)
+ print('My string:', self.my_string)
return {'FINISHED'}
- def invoke(self, context, event):
- wm = context.window_manager
- return wm.invoke_props_dialog(self)
-
-bpy.utils.register_class(DialogOperator)
-
-# test call
-bpy.ops.object.dialog_operator('INVOKE_DEFAULT')
+class OBJECT_PT_property_example(bpy.types.Panel):
+ bl_idname = "object_PT_property_example"
+ bl_label = "Property Example"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_category = "Tools"
+
+ def draw(self, context):
+ # You can set the property values that should be used when the user
+ # presses the button in the UI.
+ props = self.layout.operator('object.property_example')
+ props.my_bool = True
+ props.my_string = "Shouldn't that be 47?"
+
+ # You can set properties dynamically:
+ if context.object:
+ props.my_float = context.object.location.x
+ else:
+ props.my_float = 327
+
+
+bpy.utils.register_class(OBJECT_OT_property_example)
+bpy.utils.register_class(OBJECT_PT_property_example)
+
+# Demo call. Be sure to also test in the 3D Viewport.
+bpy.ops.object.property_example(my_float=47, my_bool=True,
+ my_string="Shouldn't that be 327?")
diff --git a/doc/python_api/examples/bpy.props.5.py b/doc/python_api/examples/bpy.props.5.py
index 87741cbab8a..a9e79fa0272 100644
--- a/doc/python_api/examples/bpy.props.5.py
+++ b/doc/python_api/examples/bpy.props.5.py
@@ -1,13 +1,12 @@
"""
-Get/Set Example
-+++++++++++++++
+Getter/Setter Example
++++++++++++++++++++++
-Get/Set functions can be used for boolean, int, float, string and enum properties.
+Getter/setter functions can be used for boolean, int, float, string and enum properties.
If these callbacks are defined the property will not be stored in the ID properties
-automatically, instead the get/set functions will be called when the property is
-read or written from the API.
+automatically. Instead, the `get` and `set` functions will be called when the property
+is respectively read or written from the API.
"""
-
import bpy
@@ -65,25 +64,24 @@ def set_enum(self, value):
bpy.types.Scene.test_enum = bpy.props.EnumProperty(items=test_items, get=get_enum, set=set_enum)
-# Testing
-
+# Testing the properties:
scene = bpy.context.scene
scene.test_float = 12.34
-print(scene.test_float)
+print('test_float:', scene.test_float)
scene.test_array = (True, False)
-print([x for x in scene.test_array])
+print('test_array:', tuple(scene.test_array))
# scene.test_date = "blah" # this would fail, property is read-only
-print(scene.test_date)
+print('test_date:', scene.test_date)
scene.test_enum = 'BLUE'
-print(scene.test_enum)
-
-
-# >>> 12.34000015258789
-# >>> [True, False]
-# >>> 2013-01-05 16:33:52.135340
-# >>> setting value 3
-# >>> GREEN
+print('test_enum:', scene.test_enum)
+
+# The above outputs:
+# test_float: 12.34000015258789
+# test_array: (True, False)
+# test_date: 2018-03-14 11:36:53.158653
+# setting value 3
+# test_enum: GREEN
diff --git a/doc/python_api/rst/info_api_reference.rst b/doc/python_api/rst/info_api_reference.rst
index 5ef5866c44a..ab690a8ee06 100644
--- a/doc/python_api/rst/info_api_reference.rst
+++ b/doc/python_api/rst/info_api_reference.rst
@@ -53,7 +53,7 @@ Here are some characteristics ID Data-Blocks share.
Simple Data Access
------------------
-Lets start with a simple case, say you wan't a python script to adjust the objects location.
+Lets start with a simple case, say you want a python script to adjust the objects location.
Start by finding this setting in the interface ``Properties Window -> Object -> Transform -> Location``
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 75064f2c5ef..b0200c0f7d8 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -420,19 +420,28 @@ MODULE_GROUPING = {
# -------------------------------BLENDER----------------------------------------
blender_version_strings = [str(v) for v in bpy.app.version]
+is_release = bpy.app.version_cycle in {"rc", "release"}
# converting bytes to strings, due to T30154
BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8')
BLENDER_DATE = str(bpy.app.build_date, 'utf_8')
-BLENDER_VERSION_DOTS = ".".join(blender_version_strings) # '2.62.1'
+if is_release:
+ # '2.62a'
+ BLENDER_VERSION_DOTS = ".".join(blender_version_strings[:2]) + bpy.app.version_char
+else:
+ # '2.62.1'
+ BLENDER_VERSION_DOTS = ".".join(blender_version_strings)
if BLENDER_REVISION != "Unknown":
- BLENDER_VERSION_DOTS += " " + BLENDER_REVISION # '2.62.1 SHA1'
+ # '2.62a SHA1' (release) or '2.62.1 SHA1' (non-release)
+ BLENDER_VERSION_DOTS += " " + BLENDER_REVISION
-BLENDER_VERSION_PATH = "_".join(blender_version_strings) # '2_62_1'
-if bpy.app.version_cycle in {"rc", "release"}:
+if is_release:
# '2_62a_release'
BLENDER_VERSION_PATH = "%s%s_release" % ("_".join(blender_version_strings[:2]), bpy.app.version_char)
+else:
+ # '2_62_1'
+ BLENDER_VERSION_PATH = "_".join(blender_version_strings)
# --------------------------DOWNLOADABLE FILES----------------------------------
diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c
index 329dfbad3aa..ad216e66452 100644
--- a/extern/cuew/src/cuew.c
+++ b/extern/cuew/src/cuew.c
@@ -338,7 +338,7 @@ static int cuewCudaInit(void) {
/* Default installation path. */
const char *cuda_paths[] = {"/usr/local/cuda/lib/libcuda.dylib", NULL};
#else
- const char *cuda_paths[] = {"libcuda.so", NULL};
+ const char *cuda_paths[] = {"libcuda.so", "libcuda.so.1", NULL};
#endif
static int initialized = 0;
static int result = 0;
diff --git a/extern/curve_fit_nd/intern/generic_heap.c b/extern/curve_fit_nd/intern/generic_heap.c
index f41025318c4..09ed84bea43 100644
--- a/extern/curve_fit_nd/intern/generic_heap.c
+++ b/extern/curve_fit_nd/intern/generic_heap.c
@@ -305,3 +305,5 @@ void *HEAP_node_ptr(HeapNode *node)
{
return node->ptr;
}
+
+/** \} */
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index 2d4b0d35e54..c682744f5fa 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -51,6 +51,7 @@ struct Options {
SessionParams session_params;
bool quiet;
bool show_help, interactive, pause;
+ string output_path;
} options;
static void session_print(const string& str)
@@ -86,6 +87,34 @@ static void session_print_status()
session_print(status);
}
+static bool write_render(const uchar *pixels, int w, int h, int channels)
+{
+ string msg = string_printf("Writing image %s", options.output_path.c_str());
+ session_print(msg);
+
+ ImageOutput *out = ImageOutput::create(options.output_path);
+ if(!out) {
+ return false;
+ }
+
+ ImageSpec spec(w, h, channels, TypeDesc::UINT8);
+ if(!out->open(options.output_path, spec)) {
+ return false;
+ }
+
+ /* conversion for different top/bottom convention */
+ out->write_image(TypeDesc::UINT8,
+ pixels + (h - 1) * w * channels,
+ AutoStride,
+ -w * channels,
+ AutoStride);
+
+ out->close();
+ delete out;
+
+ return true;
+}
+
static BufferParams& session_buffer_params()
{
static BufferParams buffer_params;
@@ -120,6 +149,7 @@ static void scene_init()
static void session_init()
{
+ options.session_params.write_render_cb = write_render;
options.session = new Session(options.session_params);
if(options.session_params.background && !options.quiet)
@@ -364,7 +394,7 @@ static void options_parse(int argc, const char **argv)
"--background", &options.session_params.background, "Render in background, without user interface",
"--quiet", &options.quiet, "In background mode, don't print progress messages",
"--samples %d", &options.session_params.samples, "Number of samples to render",
- "--output %s", &options.session_params.output_path, "File path to write output image",
+ "--output %s", &options.output_path, "File path to write output image",
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
"--width %d", &options.width, "Window width in pixel",
"--height %d", &options.height, "Window height in pixel",
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 2d6e63468af..a46955322e3 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -40,6 +40,7 @@
#include "util/util_foreach.h"
#include "util/util_path.h"
+#include "util/util_projection.h"
#include "util/util_transform.h"
#include "util/util_xml.h"
@@ -204,7 +205,7 @@ static void xml_read_camera(XMLReadState& state, xml_node node)
cam->matrix = state.tfm;
cam->need_update = true;
- cam->update();
+ cam->update(state.scene);
}
/* Shader */
@@ -515,7 +516,7 @@ static void xml_read_mesh(const XMLReadState& state, xml_node node)
xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
sdparams.dicing_rate = std::max(0.1f, sdparams.dicing_rate);
- state.scene->camera->update();
+ state.scene->camera->update(state.scene);
sdparams.camera = state.scene->camera;
sdparams.objecttoworld = state.tfm;
}
@@ -546,8 +547,10 @@ static void xml_read_transform(xml_node node, Transform& tfm)
{
if(node.attribute("matrix")) {
vector<float> matrix;
- if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
- tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
+ if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16) {
+ ProjectionTransform projection = *(ProjectionTransform*)&matrix[0];
+ tfm = tfm * projection_to_transform(projection_transpose(projection));
+ }
}
if(node.attribute("translate")) {
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 1cb7835d14d..a15a9e046df 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -66,31 +66,31 @@ class CyclesRender(bpy.types.RenderEngine):
engine.free(self)
# final render
- def update(self, data, depsgraph, scene):
+ def update(self, data, scene):
if not self.session:
if self.is_preview:
cscene = bpy.context.scene.cycles
use_osl = cscene.shading_system and cscene.device == 'CPU'
- engine.create(self, data, depsgraph, scene,
+ engine.create(self, data, scene,
None, None, None, use_osl)
else:
- engine.create(self, data, depsgraph, scene)
+ engine.create(self, data, scene)
else:
engine.reset(self, data, scene)
def render_to_image(self, depsgraph):
engine.render(self, depsgraph)
- def bake(self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
- engine.bake(self, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)
+ def bake(self, depsgraph, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
+ engine.bake(self, depsgraph, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)
# viewport render
def view_update(self, context):
if not self.session:
- engine.create(self, context.blend_data, context.depsgraph, context.scene,
+ engine.create(self, context.blend_data, context.scene,
context.region, context.space_data, context.region_data)
- engine.update(self, context.blend_data, context.scene)
+ engine.update(self, context.depsgraph, context.blend_data, context.scene)
def render_to_view(self, context):
engine.draw(self, context.depsgraph, context.region, context.space_data, context.region_data)
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index cbc21b79da8..8a13b67f91d 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -123,13 +123,12 @@ def exit():
_cycles.exit()
-def create(engine, data, depsgraph, scene, region=None, v3d=None, rv3d=None, preview_osl=False):
+def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False):
import bpy
import _cycles
data = data.as_pointer()
userpref = bpy.context.user_preferences.as_pointer()
- depsgraph = depsgraph.as_pointer()
scene = scene.as_pointer()
if region:
region = region.as_pointer()
@@ -144,7 +143,7 @@ def create(engine, data, depsgraph, scene, region=None, v3d=None, rv3d=None, pre
_cycles.debug_flags_reset()
engine.session = _cycles.create(
- engine.as_pointer(), userpref, data, depsgraph, scene, region, v3d, rv3d, preview_osl)
+ engine.as_pointer(), userpref, data, scene, region, v3d, rv3d, preview_osl)
def free(engine):
@@ -158,14 +157,14 @@ def free(engine):
def render(engine, depsgraph):
import _cycles
if hasattr(engine, "session"):
- _cycles.render(engine.session)
+ _cycles.render(engine.session, depsgraph.as_pointer())
-def bake(engine, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
+def bake(engine, depsgraph, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
import _cycles
session = getattr(engine, "session", None)
if session is not None:
- _cycles.bake(engine.session, obj.as_pointer(), pass_type, pass_filter, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
+ _cycles.bake(engine.session, depsgraph.as_pointer(), obj.as_pointer(), pass_type, pass_filter, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
def reset(engine, data, scene):
@@ -175,9 +174,9 @@ def reset(engine, data, scene):
_cycles.reset(engine.session, data, scene)
-def update(engine, data, scene):
+def update(engine, depsgraph, data, scene):
import _cycles
- _cycles.sync(engine.session)
+ _cycles.sync(engine.session, depsgraph.as_pointer())
def draw(engine, depsgraph, region, v3d, rv3d):
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index fb7530f8663..0e88ed0b6ea 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -565,6 +565,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
('SHADOW', "Shadow", ""),
('NORMAL', "Normal", ""),
('UV', "UV", ""),
+ ('ROUGHNESS', "Roughness", ""),
('EMIT', "Emit", ""),
('ENVIRONMENT', "Environment", ""),
('DIFFUSE', "Diffuse", ""),
@@ -1082,7 +1083,7 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
cls.motion_steps = IntProperty(
name="Motion Steps",
- description="Control accuracy of deformation motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
+ description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
min=1, soft_max=8,
default=1,
)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 0166b494db7..6e4b0373a7a 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -783,7 +783,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def poll(cls, context):
ob = context.object
if CyclesButtonsPanel.poll(context) and ob:
- if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}:
+ if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
return True
if ob.dupli_type == 'GROUP' and ob.dupli_group:
return True
@@ -815,11 +815,9 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
layout.active = (rd.use_motion_blur and cob.use_motion_blur)
row = layout.row()
- row.prop(cob, "use_deform_motion", text="Deformation")
-
- sub = row.row()
- sub.active = cob.use_deform_motion
- sub.prop(cob, "motion_steps", text="Steps")
+ if ob.type != 'CAMERA':
+ row.prop(cob, "use_deform_motion", text="Deformation")
+ row.prop(cob, "motion_steps", text="Steps")
class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index f1dc5a6e15e..2689fa63ca8 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -17,6 +17,7 @@
# <pep8 compliant>
import bpy
+import math
from bpy.app.handlers import persistent
@@ -138,6 +139,56 @@ def displacement_principled_nodes(node):
if node.subsurface_method != 'RANDOM_WALK':
node.subsurface_method = 'BURLEY'
+def square_roughness_node_insert(material, nodetree, traversed):
+ if nodetree in traversed:
+ return
+ traversed.add(nodetree)
+
+ roughness_node_types = {
+ 'ShaderNodeBsdfAnisotropic',
+ 'ShaderNodeBsdfGlass',
+ 'ShaderNodeBsdfGlossy',
+ 'ShaderNodeBsdfRefraction'}
+
+ # Update default values
+ for node in nodetree.nodes:
+ if node.bl_idname == 'ShaderNodeGroup':
+ square_roughness_node_insert(material, node.node_tree, traversed)
+ elif node.bl_idname in roughness_node_types:
+ roughness_input = node.inputs['Roughness']
+ roughness_input.default_value = math.sqrt(max(roughness_input.default_value, 0.0))
+
+ # Gather roughness links to replace
+ roughness_links = []
+ for link in nodetree.links:
+ if link.to_node.bl_idname in roughness_node_types and \
+ link.to_socket.identifier == 'Roughness':
+ roughness_links.append(link)
+
+ # Replace links with sqrt node
+ for link in roughness_links:
+ from_node = link.from_node
+ from_socket = link.from_socket
+ to_node = link.to_node
+ to_socket = link.to_socket
+
+ nodetree.links.remove(link)
+
+ node = nodetree.nodes.new(type='ShaderNodeMath')
+ node.operation = 'POWER'
+ node.location[0] = 0.5 * (from_node.location[0] + to_node.location[0]);
+ node.location[1] = 0.5 * (from_node.location[1] + to_node.location[1]);
+
+ nodetree.links.new(from_socket, node.inputs[0])
+ node.inputs[1].default_value = 0.5
+ nodetree.links.new(node.outputs['Value'], to_socket)
+
+def square_roughness_nodes_insert():
+ traversed = set()
+ for material in bpy.data.materials:
+ if check_is_new_shading_material(material):
+ square_roughness_node_insert(material, material.node_tree, traversed)
+
def mapping_node_order_flip(node):
"""
@@ -377,3 +428,8 @@ def do_versions(self):
cmat.displacement_method = 'BUMP'
foreach_cycles_node(displacement_principled_nodes)
+
+ if bpy.data.version <= (2, 79, 3) or \
+ (bpy.data.version >= (2, 80, 0) and bpy.data.version <= (2, 80, 4)):
+ # Switch to squared roughness convention
+ square_roughness_nodes_insert()
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 62e950e3bef..f00ade320e7 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -83,6 +83,8 @@ struct BlenderCamera {
Transform matrix;
float offscreen_dicing_scale;
+
+ int motion_steps;
};
static void blender_camera_init(BlenderCamera *bcam,
@@ -226,6 +228,8 @@ static void blender_camera_from_object(BlenderCamera *bcam,
bcam->sensor_fit = BlenderCamera::HORIZONTAL;
else
bcam->sensor_fit = BlenderCamera::VERTICAL;
+
+ bcam->motion_steps = object_motion_steps(b_ob, b_ob);
}
else {
/* from lamp not implemented yet */
@@ -246,8 +250,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
result = tfm *
make_transform(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f);
+ 0.0f, 1.0f, 0.0f, 0.0f);
}
else {
/* Make it so environment camera needs to be pointed in the direction
@@ -257,8 +260,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
result = tfm *
make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
- -1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f);
+ -1.0f, 0.0f, 0.0f, 0.0f);
}
}
else {
@@ -455,9 +457,7 @@ static void blender_camera_sync(Camera *cam,
cam->matrix = blender_camera_matrix(bcam->matrix,
bcam->type,
bcam->panorama_type);
- cam->motion.pre = cam->matrix;
- cam->motion.post = cam->matrix;
- cam->use_motion = false;
+ cam->motion.resize(bcam->motion_steps, cam->matrix);
cam->use_perspective_motion = false;
cam->shuttertime = bcam->shuttertime;
cam->fov_pre = cam->fov;
@@ -566,20 +566,15 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
Transform tfm = get_transform(b_ob_matrix);
tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
- if(tfm != cam->matrix) {
- VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
- if(motion_time == 0.0f) {
- /* When motion blur is not centered in frame, cam->matrix gets reset. */
- cam->matrix = tfm;
- }
- else if(motion_time == -1.0f) {
- cam->motion.pre = tfm;
- cam->use_motion = true;
- }
- else if(motion_time == 1.0f) {
- cam->motion.post = tfm;
- cam->use_motion = true;
- }
+ if(motion_time == 0.0f) {
+ /* When motion blur is not centered in frame, cam->matrix gets reset. */
+ cam->matrix = tfm;
+ }
+
+ /* Set transform in motion array. */
+ int motion_step = cam->motion_step(motion_time);
+ if(motion_step >= 0) {
+ cam->motion[motion_step] = tfm;
}
if(cam->type == CAMERA_PERSPECTIVE) {
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 9c210830cfe..984442fb08c 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -326,14 +326,14 @@ static bool ObtainCacheParticleVcol(Mesh *mesh,
return true;
}
-static void set_resolution(BL::Object *b_ob, BL::Scene *scene, BL::ViewLayer *view_layer, bool render)
+static void set_resolution(BL::Object& b_ob, BL::Scene& scene, BL::ViewLayer& view_layer, bool render)
{
BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
+ for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- b_psys.set_resolution(*scene, *view_layer, *b_ob, (render)? 2: 1);
+ b_psys.set_resolution(scene, view_layer, b_ob, (render)? 2: 1);
}
}
}
@@ -633,10 +633,10 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
}
}
-static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
+static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step)
{
VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
- << ", time index " << time_index;
+ << ", motion step " << motion_step;
/* find attribute */
Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@@ -651,7 +651,7 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
/* export motion vectors for curve keys */
size_t numkeys = mesh->curve_keys.size();
- float4 *mP = attr_mP->data_float4() + time_index*numkeys;
+ float4 *mP = attr_mP->data_float4() + motion_step*numkeys;
bool have_motion = false;
int i = 0;
@@ -702,12 +702,12 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
}
mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
}
- else if(time_index > 0) {
- VLOG(1) << "Filling in new motion vertex position for time_index "
- << time_index;
+ else if(motion_step > 0) {
+ VLOG(1) << "Filling in new motion vertex position for motion_step "
+ << motion_step;
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
- for(int step = 0; step < time_index; step++) {
+ for(int step = 0; step < motion_step; step++) {
float4 *mP = attr_mP->data_float4() + step*numkeys;
for(int key = 0; key < numkeys; key++) {
@@ -884,11 +884,12 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->tag_update(scene);
}
-void BlenderSync::sync_curves(Mesh *mesh,
+void BlenderSync::sync_curves(BL::Depsgraph& b_depsgraph,
+ Mesh *mesh,
BL::Mesh& b_mesh,
BL::Object& b_ob,
bool motion,
- int time_index)
+ int motion_step)
{
if(!motion) {
/* Clear stored curve data */
@@ -920,8 +921,9 @@ void BlenderSync::sync_curves(Mesh *mesh,
ParticleCurveData CData;
+ BL::ViewLayer b_view_layer = b_depsgraph.view_layer();
if(!preview)
- set_resolution(&b_ob, &b_scene, &b_view_layer, true);
+ set_resolution(b_ob, b_scene, b_view_layer, true);
ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
@@ -952,7 +954,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
}
else {
if(motion)
- ExportCurveSegmentsMotion(mesh, &CData, time_index);
+ ExportCurveSegmentsMotion(mesh, &CData, motion_step);
else
ExportCurveSegments(scene, mesh, &CData);
}
@@ -1066,7 +1068,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
}
if(!preview)
- set_resolution(&b_ob, &b_scene, &b_view_layer, false);
+ set_resolution(b_ob, b_scene, b_view_layer, false);
mesh->compute_bounds();
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index df1b1a4ca10..afcfe3d434e 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -335,10 +335,13 @@ static void create_mesh_volume_attribute(BL::Object& b_ob,
if(!b_domain)
return;
+ mesh->volume_isovalue = b_domain.clipping();
+
Attribute *attr = mesh->attributes.add(std);
VoxelAttribute *volume_data = attr->data_voxel();
- bool is_float, is_linear;
+ ImageMetaData metadata;
bool animated = false;
+ bool use_alpha = true;
volume_data->manager = image_manager;
volume_data->slot = image_manager->add_image(
@@ -346,11 +349,10 @@ static void create_mesh_volume_attribute(BL::Object& b_ob,
b_ob.ptr.data,
animated,
frame,
- is_float,
- is_linear,
INTERPOLATION_LINEAR,
EXTENSION_CLIP,
- true);
+ use_alpha,
+ metadata);
}
static void create_mesh_volume_attributes(Scene *scene,
@@ -367,6 +369,8 @@ static void create_mesh_volume_attributes(Scene *scene,
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME, frame);
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT))
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT, frame);
+ if(mesh->need_attribute(scene, ATTR_STD_VOLUME_TEMPERATURE))
+ create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_TEMPERATURE, frame);
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY))
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY, frame);
}
@@ -1065,7 +1069,8 @@ static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh)
}
}
-Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
+Mesh *BlenderSync::sync_mesh(BL::Depsgraph& b_depsgraph,
+ BL::Object& b_ob,
BL::Object& b_ob_instance,
bool object_updated,
bool hide_tris)
@@ -1184,7 +1189,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
BL::Mesh b_mesh = object_to_mesh(b_data,
b_ob,
b_scene,
- b_view_layer,
+ b_depsgraph.view_layer(),
true,
!preview,
need_undeformed,
@@ -1202,7 +1207,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
}
if(view_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
- sync_curves(mesh, b_mesh, b_ob, false);
+ sync_curves(b_depsgraph, mesh, b_mesh, b_ob, false);
if(can_free_caches) {
b_ob.cache_release();
@@ -1229,7 +1234,8 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
return mesh;
}
-void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
+void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
+ BL::Object& b_ob,
Object *object,
float motion_time)
{
@@ -1246,36 +1252,10 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
if(mesh_synced.find(mesh) == mesh_synced.end())
return;
- /* for motion pass always compute, for motion blur it can be disabled */
- int time_index = 0;
-
- if(scene->need_motion() == Scene::MOTION_BLUR) {
- if(!mesh->use_motion_blur)
- return;
-
- /* see if this mesh needs motion data at this time */
- vector<float> object_times = object->motion_times();
- bool found = false;
-
- foreach(float object_time, object_times) {
- if(motion_time == object_time) {
- found = true;
- break;
- }
- else
- time_index++;
- }
-
- if(!found)
- return;
- }
- else {
- if(motion_time == -1.0f)
- time_index = 0;
- else if(motion_time == 1.0f)
- time_index = 1;
- else
- return;
+ /* Find time matching motion step required by mesh. */
+ int motion_step = mesh->motion_step(motion_time);
+ if(motion_step < 0) {
+ return;
}
/* skip empty meshes */
@@ -1299,7 +1279,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
b_mesh = object_to_mesh(b_data,
b_ob,
b_scene,
- b_view_layer,
+ b_depsgraph.view_layer(),
true,
!preview,
false,
@@ -1318,9 +1298,9 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
float3 *P = &mesh->verts[0];
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
- memcpy(attr_mP->data_float3() + time_index*numverts, P, sizeof(float3)*numverts);
+ memcpy(attr_mP->data_float3() + motion_step*numverts, P, sizeof(float3)*numverts);
if(attr_mN)
- memcpy(attr_mN->data_float3() + time_index*numverts, N, sizeof(float3)*numverts);
+ memcpy(attr_mN->data_float3() + motion_step*numverts, N, sizeof(float3)*numverts);
}
}
@@ -1330,7 +1310,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
if(attr_mP) {
float3 *keys = &mesh->curve_keys[0];
- memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys);
+ memcpy(attr_mP->data_float3() + motion_step*numkeys, keys, sizeof(float3)*numkeys);
}
}
@@ -1353,8 +1333,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
new_attribute = true;
}
/* Load vertex data from mesh. */
- float3 *mP = attr_mP->data_float3() + time_index*numverts;
- float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
+ float3 *mP = attr_mP->data_float3() + motion_step*numverts;
+ float3 *mN = (attr_mN)? attr_mN->data_float3() + motion_step*numverts: NULL;
/* NOTE: We don't copy more that existing amount of vertices to prevent
* possible memory corruption.
*/
@@ -1383,13 +1363,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
if(attr_mN)
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
}
- else if(time_index > 0) {
+ else if(motion_step > 0) {
VLOG(1) << "Filling deformation motion for object " << b_ob.name();
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
float3 *P = &mesh->verts[0];
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
- for(int step = 0; step < time_index; step++) {
+ for(int step = 0; step < motion_step; step++) {
memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
if(attr_mN)
memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
@@ -1399,7 +1379,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
else {
if(b_mesh.vertices.length() != numverts) {
VLOG(1) << "Topology differs, discarding motion blur for object "
- << b_ob.name() << " at time " << time_index;
+ << b_ob.name() << " at time " << motion_step;
memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts);
if(mN != NULL) {
memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts);
@@ -1410,7 +1390,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
/* hair motion */
if(numkeys)
- sync_curves(mesh, b_mesh, b_ob, true, time_index);
+ sync_curves(b_depsgraph, mesh, b_mesh, b_ob, true, motion_step);
/* free derived mesh */
b_data.meshes.remove(b_mesh, false, true, false);
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 6564eea4767..be4214ede65 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -263,7 +263,8 @@ void BlenderSync::sync_background_light(bool use_portal)
/* Object */
-Object *BlenderSync::sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
+Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph,
+ BL::Depsgraph::duplis_iterator& b_dupli_iter,
uint layer_flag,
float motion_time,
bool hide_tris,
@@ -346,27 +347,16 @@ Object *BlenderSync::sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
if(motion) {
object = object_map.find(key);
- if(object && (scene->need_motion() == Scene::MOTION_PASS ||
- object_use_motion(b_parent, b_ob)))
- {
- /* object transformation */
- if(tfm != object->tfm) {
- VLOG(1) << "Object " << b_ob.name() << " motion detected.";
- if(motion_time == -1.0f || motion_time == 1.0f) {
- object->use_motion = true;
- }
- }
-
- if(motion_time == -1.0f) {
- object->motion.pre = tfm;
- }
- else if(motion_time == 1.0f) {
- object->motion.post = tfm;
+ if(object && object->use_motion()) {
+ /* Set transform at matching motion time step. */
+ int time_index = object->motion_step(motion_time);
+ if(time_index >= 0) {
+ object->motion[time_index] = tfm;
}
/* mesh deformation */
if(object->mesh)
- sync_mesh_motion(b_ob, object, motion_time);
+ sync_mesh_motion(b_depsgraph, b_ob, object, motion_time);
}
return object;
@@ -379,7 +369,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
object_updated = true;
/* mesh sync */
- object->mesh = sync_mesh(b_ob, b_ob_instance, object_updated, hide_tris);
+ object->mesh = sync_mesh(b_depsgraph, b_ob, b_ob_instance, object_updated, hide_tris);
/* special case not tracked by object update flags */
@@ -408,25 +398,37 @@ Object *BlenderSync::sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
object->name = b_ob.name().c_str();
object->pass_id = b_ob.pass_index();
object->tfm = tfm;
- object->motion.pre = transform_empty();
- object->motion.post = transform_empty();
- object->use_motion = false;
+ object->motion.clear();
/* motion blur */
- if(scene->need_motion() == Scene::MOTION_BLUR && object->mesh) {
+ Scene::MotionType need_motion = scene->need_motion();
+ if(need_motion != Scene::MOTION_NONE && object->mesh) {
Mesh *mesh = object->mesh;
-
mesh->use_motion_blur = false;
+ mesh->motion_steps = 0;
- if(object_use_motion(b_parent, b_ob)) {
- if(object_use_deform_motion(b_parent, b_ob)) {
- mesh->motion_steps = object_motion_steps(b_ob);
+ uint motion_steps;
+
+ if(scene->need_motion() == Scene::MOTION_BLUR) {
+ motion_steps = object_motion_steps(b_parent, b_ob);
+ if(motion_steps && object_use_deform_motion(b_parent, b_ob)) {
+ mesh->motion_steps = motion_steps;
mesh->use_motion_blur = true;
}
+ }
+ else {
+ motion_steps = 3;
+ mesh->motion_steps = motion_steps;
+ }
+
+ object->motion.resize(motion_steps, transform_empty());
- vector<float> times = object->motion_times();
- foreach(float time, times)
- motion_times.insert(time);
+ if(motion_steps) {
+ object->motion[motion_steps/2] = tfm;
+
+ for(size_t step = 0; step < motion_steps; step++) {
+ motion_times.insert(object->motion_time(step));
+ }
}
}
@@ -520,7 +522,7 @@ static bool object_render_hide(BL::Object& b_ob,
/* Object Loop */
-void BlenderSync::sync_objects(float motion_time)
+void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time)
{
/* layer data */
bool motion = motion_time != 0.0f;
@@ -564,7 +566,8 @@ void BlenderSync::sync_objects(float motion_time)
if(!object_render_hide(b_ob, true, true, hide_tris)) {
/* object itself */
- sync_object(b_dupli_iter,
+ sync_object(b_depsgraph,
+ b_dupli_iter,
~(0), /* until we get rid of layers */
motion_time,
hide_tris,
@@ -596,6 +599,7 @@ void BlenderSync::sync_objects(float motion_time)
}
void BlenderSync::sync_motion(BL::RenderSettings& b_render,
+ BL::Depsgraph& b_depsgraph,
BL::Object& b_override,
int width, int height,
void **python_thread_state)
@@ -625,6 +629,8 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
assert(scene->camera->motion_position == Camera::MOTION_POSITION_START);
frame_center_delta = shuttertime * 0.5f;
}
+
+ /* TODO: move frame on depsgraph. */
float time = frame_center + subframe_center + frame_center_delta;
int frame = (int)floorf(time);
float subframe = time - frame;
@@ -632,7 +638,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
b_engine.frame_set(frame, subframe);
python_thread_state_save(python_thread_state);
sync_camera_motion(b_render, b_cam, width, height, 0.0f);
- sync_objects(0.0f);
+ sync_objects(b_depsgraph, 0.0f);
}
/* always sample these times for camera motion */
@@ -641,6 +647,11 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
/* note iteration over motion_times set happens in sorted order */
foreach(float relative_time, motion_times) {
+ /* center time is already handled. */
+ if(relative_time == 0.0f) {
+ continue;
+ }
+
VLOG(1) << "Synchronizing motion for the relative time "
<< relative_time << ".";
@@ -652,6 +663,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
int frame = (int)floorf(time);
float subframe = time - frame;
+ /* TODO: move frame on depsgraph. */
/* change frame */
python_thread_state_restore(python_thread_state);
b_engine.frame_set(frame, subframe);
@@ -666,7 +678,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
}
/* sync object */
- sync_objects(relative_time);
+ sync_objects(b_depsgraph, relative_time);
}
/* we need to set the python thread state again because this
diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp
index 1d747de647a..bdf7dc469b2 100644
--- a/intern/cycles/blender/blender_object_cull.cpp
+++ b/intern/cycles/blender/blender_object_cull.cpp
@@ -96,7 +96,7 @@ bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm)
bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
{
Camera *cam = scene->camera;
- Transform& worldtondc = cam->worldtondc;
+ const ProjectionTransform& worldtondc = cam->worldtondc;
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
bool all_behind = true;
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 9ade27d57d7..5c1181960c3 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -203,10 +203,10 @@ static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
static PyObject *create_func(PyObject * /*self*/, PyObject *args)
{
- PyObject *pyengine, *pyuserpref, *pydata, *pygraph, *pyscene, *pyregion, *pyv3d, *pyrv3d;
+ PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
int preview_osl;
- if(!PyArg_ParseTuple(args, "OOOOOOOOi", &pyengine, &pyuserpref, &pydata, &pygraph, &pyscene,
+ if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene,
&pyregion, &pyv3d, &pyrv3d, &preview_osl))
{
return NULL;
@@ -225,10 +225,6 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
BL::BlendData data(dataptr);
- PointerRNA graphptr;
- RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pygraph), &graphptr);
- BL::Depsgraph graph(graphptr);
-
PointerRNA sceneptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
BL::Scene scene(sceneptr);
@@ -253,7 +249,7 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
int width = region.width();
int height = region.height();
- session = new BlenderSession(engine, userpref, data, graph, scene, v3d, rv3d, width, height);
+ session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
}
else {
/* override some settings for preview */
@@ -265,7 +261,7 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
}
/* offline session or preview render */
- session = new BlenderSession(engine, userpref, data, graph, scene);
+ session = new BlenderSession(engine, userpref, data, scene);
}
python_thread_state_save(&session->python_thread_state);
@@ -284,13 +280,22 @@ static PyObject *free_func(PyObject * /*self*/, PyObject *value)
Py_RETURN_NONE;
}
-static PyObject *render_func(PyObject * /*self*/, PyObject *value)
+static PyObject *render_func(PyObject * /*self*/, PyObject *args)
{
- BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
+ PyObject *pysession, *pydepsgraph;
+
+ if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
+
+ PointerRNA depsgraphptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, (ID*)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
python_thread_state_save(&session->python_thread_state);
- session->render();
+ session->render(b_depsgraph);
python_thread_state_restore(&session->python_thread_state);
@@ -300,16 +305,20 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *value)
/* pixel_array and result passed as pointers */
static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
{
- PyObject *pysession, *pyobject;
+ PyObject *pysession, *pydepsgraph, *pyobject;
PyObject *pypixel_array, *pyresult;
const char *pass_type;
int num_pixels, depth, object_id, pass_filter;
- if(!PyArg_ParseTuple(args, "OOsiiOiiO", &pysession, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
+ if(!PyArg_ParseTuple(args, "OOOsiiOiiO", &pysession, &pydepsgraph, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
return NULL;
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
+ PointerRNA depsgraphptr;
+ RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
+
PointerRNA objectptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr);
BL::Object b_object(objectptr);
@@ -322,7 +331,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
- session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
+ session->bake(b_depsgraph, b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
python_thread_state_restore(&session->python_thread_state);
@@ -375,13 +384,22 @@ static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *sync_func(PyObject * /*self*/, PyObject *value)
+static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
{
- BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
+ PyObject *pysession, *pydepsgraph;
+
+ if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
+ return NULL;
+
+ BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
+
+ PointerRNA depsgraphptr;
+ RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
+ BL::Depsgraph b_depsgraph(depsgraphptr);
python_thread_state_save(&session->python_thread_state);
- session->synchronize();
+ session->synchronize(b_depsgraph);
python_thread_state_restore(&session->python_thread_state);
@@ -753,10 +771,10 @@ static PyMethodDef methods[] = {
{"exit", exit_func, METH_VARARGS, ""},
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_O, ""},
- {"render", render_func, METH_O, ""},
+ {"render", render_func, METH_VARARGS, ""},
{"bake", bake_func, METH_VARARGS, ""},
{"draw", draw_func, METH_VARARGS, ""},
- {"sync", sync_func, METH_O, ""},
+ {"sync", sync_func, METH_VARARGS, ""},
{"reset", reset_func, METH_VARARGS, ""},
#ifdef WITH_OSL
{"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 60e49161be2..8eec7c44928 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -52,15 +52,12 @@ int BlenderSession::end_resumable_chunk = 0;
BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
- BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene)
: b_engine(b_engine),
b_userpref(b_userpref),
b_data(b_data),
b_render(b_engine.render()),
- b_depsgraph(b_depsgraph),
b_scene(b_scene),
- b_view_layer(b_engine.view_layer()),
b_v3d(PointerRNA_NULL),
b_rv3d(PointerRNA_NULL),
python_thread_state(NULL)
@@ -79,7 +76,6 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
- BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
BL::SpaceView3D& b_v3d,
BL::RegionView3D& b_rv3d,
@@ -88,9 +84,7 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
b_userpref(b_userpref),
b_data(b_data),
b_render(b_scene.render()),
- b_depsgraph(b_depsgraph),
b_scene(b_scene),
- b_view_layer(b_engine.view_layer()),
b_v3d(b_v3d),
b_rv3d(b_rv3d),
width(width),
@@ -141,32 +135,25 @@ void BlenderSession::create_session()
scene = new Scene(scene_params, session->device);
/* setup callbacks for builtin image support */
- scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7, _8);
+ scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3);
scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5);
scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5);
session->scene = scene;
+ /* There is no single depsgraph to use for the entire render.
+ * So we need to handle this differently.
+ *
+ * We could loop over the final render result render layers in pipeline and keep Cycles unaware of multiple layers,
+ * or perhaps move syncing further down in the pipeline.
+ */
/* create sync */
- sync = new BlenderSync(b_engine, b_data, b_depsgraph, b_scene, scene, !background, session->progress);
+ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
BL::Object b_camera_override(b_engine.camera_override());
if(b_v3d) {
- if(session_pause == false) {
- /* full data sync */
- sync->sync_view(b_v3d, b_rv3d, width, height);
- sync->sync_data(b_render,
- b_v3d,
- b_camera_override,
- width, height,
- &python_thread_state,
- b_rlay_name.c_str());
- }
+ sync->sync_view(b_v3d, b_rv3d, width, height);
}
else {
- /* for final render we will do full data sync per render layer, only
- * do some basic syncing here, no objects or materials for speed */
- sync->sync_view_layers(b_v3d, NULL);
- sync->sync_integrator();
sync->sync_camera(b_render, b_camera_override, width, height, "");
}
@@ -216,15 +203,11 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_)
*/
session->stats.mem_peak = session->stats.mem_used;
+ /* There is no single depsgraph to use for the entire render.
+ * See note on create_session().
+ */
/* sync object should be re-created */
- sync = new BlenderSync(b_engine, b_data, b_depsgraph, b_scene, scene, !background, session->progress);
-
- /* for final render we will do full data sync per render layer, only
- * do some basic syncing here, no objects or materials for speed */
- BL::Object b_camera_override(b_engine.camera_override());
- sync->sync_view_layers(b_v3d, NULL);
- sync->sync_integrator();
- sync->sync_camera(b_render, b_camera_override, width, height, "");
+ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
@@ -258,6 +241,8 @@ static ShaderEvalType get_shader_type(const string& pass_type)
return SHADER_EVAL_NORMAL;
else if(strcmp(shader_type, "UV")==0)
return SHADER_EVAL_UV;
+ else if(strcmp(shader_type, "ROUGHNESS")==0)
+ return SHADER_EVAL_ROUGHNESS;
else if(strcmp(shader_type, "DIFFUSE_COLOR")==0)
return SHADER_EVAL_DIFFUSE_COLOR;
else if(strcmp(shader_type, "GLOSSY_COLOR")==0)
@@ -372,7 +357,7 @@ void BlenderSession::update_render_tile(RenderTile& rtile, bool highlight)
do_write_update_render_tile(rtile, false, false);
}
-void BlenderSession::render()
+void BlenderSession::render(BL::Depsgraph& b_depsgraph)
{
/* set callback to write out render results */
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
@@ -383,122 +368,109 @@ void BlenderSession::render()
BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
/* render each layer */
- BL::Scene::view_layers_iterator b_layer_iter;
- BL::RenderResult::views_iterator b_view_iter;
+ BL::ViewLayer b_view_layer = b_depsgraph.view_layer();
/* We do some special meta attributes when we only have single layer. */
const bool is_single_layer = (b_scene.view_layers.length() == 1);
- for(b_scene.view_layers.begin(b_layer_iter); b_layer_iter != b_scene.view_layers.end(); ++b_layer_iter) {
- b_rlay_name = b_layer_iter->name();
-
- /* temporary render result to find needed passes and views */
- BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str(), NULL);
- BL::RenderResult::layers_iterator b_single_rlay;
- b_rr.layers.begin(b_single_rlay);
+ /* temporary render result to find needed passes and views */
+ BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
+ BL::RenderResult::layers_iterator b_single_rlay;
+ b_rr.layers.begin(b_single_rlay);
+ BL::RenderLayer b_rlay = *b_single_rlay;
- /* layer will be missing if it was disabled in the UI */
- if(b_single_rlay == b_rr.layers.end()) {
- end_render_result(b_engine, b_rr, true, true, false);
- continue;
- }
+ /* add passes */
+ array<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer, session_params);
+ buffer_params.passes = passes;
+
+ PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
+ bool use_denoising = get_boolean(crl, "use_denoising");
+ buffer_params.denoising_data_pass = use_denoising;
+ session->tile_manager.schedule_denoising = use_denoising;
+ session->params.use_denoising = use_denoising;
+ scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
+ scene->film->denoising_flags = 0;
+ if(!get_boolean(crl, "denoising_diffuse_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_DIR;
+ if(!get_boolean(crl, "denoising_diffuse_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_IND;
+ if(!get_boolean(crl, "denoising_glossy_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_DIR;
+ if(!get_boolean(crl, "denoising_glossy_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_IND;
+ if(!get_boolean(crl, "denoising_transmission_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_DIR;
+ if(!get_boolean(crl, "denoising_transmission_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_IND;
+ if(!get_boolean(crl, "denoising_subsurface_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_DIR;
+ if(!get_boolean(crl, "denoising_subsurface_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_IND;
+ scene->film->denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
+ buffer_params.denoising_clean_pass = scene->film->denoising_clean_pass;
+ session->params.denoising_radius = get_int(crl, "denoising_radius");
+ session->params.denoising_strength = get_float(crl, "denoising_strength");
+ session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength");
+ session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca");
+
+ scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold();
+ scene->film->tag_passes_update(scene, passes);
+ scene->film->tag_update(scene);
+ scene->integrator->tag_update(scene);
- BL::RenderLayer b_rlay = *b_single_rlay;
-
- /* add passes */
- array<Pass> passes = sync->sync_render_passes(b_rlay, *b_layer_iter, session_params);
- buffer_params.passes = passes;
-
- PointerRNA crl = RNA_pointer_get(&b_layer_iter->ptr, "cycles");
- bool use_denoising = get_boolean(crl, "use_denoising");
- buffer_params.denoising_data_pass = use_denoising;
- session->tile_manager.schedule_denoising = use_denoising;
- session->params.use_denoising = use_denoising;
- scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
- scene->film->denoising_flags = 0;
- if(!get_boolean(crl, "denoising_diffuse_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_DIR;
- if(!get_boolean(crl, "denoising_diffuse_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_IND;
- if(!get_boolean(crl, "denoising_glossy_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_DIR;
- if(!get_boolean(crl, "denoising_glossy_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_IND;
- if(!get_boolean(crl, "denoising_transmission_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_DIR;
- if(!get_boolean(crl, "denoising_transmission_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_IND;
- if(!get_boolean(crl, "denoising_subsurface_direct")) scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_DIR;
- if(!get_boolean(crl, "denoising_subsurface_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_IND;
- scene->film->denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
- buffer_params.denoising_clean_pass = scene->film->denoising_clean_pass;
- session->params.denoising_radius = get_int(crl, "denoising_radius");
- session->params.denoising_strength = get_float(crl, "denoising_strength");
- session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength");
- session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca");
-
- scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold();
- scene->film->tag_passes_update(scene, passes);
- scene->film->tag_update(scene);
- scene->integrator->tag_update(scene);
-
- int view_index = 0;
- for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) {
- b_rview_name = b_view_iter->name();
-
- /* set the current view */
- b_engine.active_view_set(b_rview_name.c_str());
-
- /* update scene */
- BL::Object b_camera_override(b_engine.camera_override());
- sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
- sync->sync_data(b_render,
- b_v3d,
- b_camera_override,
- width, height,
- &python_thread_state,
- b_rlay_name.c_str());
-
- /* Make sure all views have different noise patterns. - hardcoded value just to make it random */
- if(view_index != 0) {
- scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef));
- scene->integrator->tag_update(scene);
- }
+ BL::RenderResult::views_iterator b_view_iter;
+ int view_index = 0;
+ for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) {
+ b_rlay_name = b_view_layer.name();
+ b_rview_name = b_view_iter->name();
- /* Update number of samples per layer. */
- int samples = sync->get_layer_samples();
- bool bound_samples = sync->get_layer_bound_samples();
- int effective_layer_samples;
+ /* set the current view */
+ b_engine.active_view_set(b_rview_name.c_str());
- if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
- effective_layer_samples = samples;
- else
- effective_layer_samples = session_params.samples;
+ /* update scene */
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
+ sync->sync_data(b_render,
+ b_depsgraph,
+ b_v3d,
+ b_camera_override,
+ width, height,
+ &python_thread_state);
- /* Update tile manager if we're doing resumable render. */
- update_resumable_tile_manager(effective_layer_samples);
+ /* Make sure all views have different noise patterns. - hardcoded value just to make it random */
+ if(view_index != 0) {
+ scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef));
+ scene->integrator->tag_update(scene);
+ }
- /* Update session itself. */
- session->reset(buffer_params, effective_layer_samples);
+ /* Update number of samples per layer. */
+ int samples = sync->get_layer_samples();
+ bool bound_samples = sync->get_layer_bound_samples();
+ int effective_layer_samples;
- /* render */
- session->start();
- session->wait();
+ if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
+ effective_layer_samples = samples;
+ else
+ effective_layer_samples = session_params.samples;
- if(session->progress.get_cancel())
- break;
- }
+ /* Update tile manager if we're doing resumable render. */
+ update_resumable_tile_manager(effective_layer_samples);
- if(is_single_layer) {
- BL::RenderResult b_rr = b_engine.get_result();
- string num_aa_samples = string_printf("%d", session->params.samples);
- b_rr.stamp_data_add_field("Cycles Samples", num_aa_samples.c_str());
- /* TODO(sergey): Report whether we're doing resumable render
- * and also start/end sample if so.
- */
- }
+ /* Update session itself. */
+ session->reset(buffer_params, effective_layer_samples);
- /* free result without merging */
- end_render_result(b_engine, b_rr, true, true, false);
+ /* render */
+ session->start();
+ session->wait();
if(session->progress.get_cancel())
break;
}
+ if(is_single_layer) {
+ BL::RenderResult b_rr = b_engine.get_result();
+ string num_aa_samples = string_printf("%d", session->params.samples);
+ b_rr.stamp_data_add_field("Cycles Samples", num_aa_samples.c_str());
+ /* TODO(sergey): Report whether we're doing resumable render
+ * and also start/end sample if so.
+ */
+ }
+
+ /* free result without merging */
+ end_render_result(b_engine, b_rr, true, true, false);
+
double total_time, render_time;
session->progress.get_time(total_time, render_time);
VLOG(1) << "Total render time: " << total_time;
@@ -508,6 +480,8 @@ void BlenderSession::render()
session->write_render_tile_cb = function_null;
session->update_render_tile_cb = function_null;
+ /* TODO: find a way to clear this data for persistent data render */
+#if 0
/* free all memory used (host and device), so we wouldn't leave render
* engine with extra memory allocated
*/
@@ -516,6 +490,7 @@ void BlenderSession::render()
delete sync;
sync = NULL;
+#endif
}
static void populate_bake_data(BakeData *data, const
@@ -564,7 +539,8 @@ static int bake_pass_filter_get(const int pass_filter)
return flag;
}
-void BlenderSession::bake(BL::Object& b_object,
+void BlenderSession::bake(BL::Depsgraph& b_depsgraph,
+ BL::Object& b_object,
const string& pass_type,
const int pass_filter,
const int object_id,
@@ -605,11 +581,11 @@ void BlenderSession::bake(BL::Object& b_object,
BL::Object b_camera_override(b_engine.camera_override());
sync->sync_camera(b_render, b_camera_override, width, height, "");
sync->sync_data(b_render,
+ b_depsgraph,
b_v3d,
b_camera_override,
width, height,
- &python_thread_state,
- b_rlay_name.c_str());
+ &python_thread_state);
}
BakeData *bake_data = NULL;
@@ -743,7 +719,7 @@ void BlenderSession::update_render_result(BL::RenderResult& b_rr,
do_write_update_render_result(b_rr, b_rlay, rtile, true);
}
-void BlenderSession::synchronize()
+void BlenderSession::synchronize(BL::Depsgraph& b_depsgraph)
{
/* only used for viewport render */
if(!b_v3d)
@@ -786,11 +762,11 @@ void BlenderSession::synchronize()
/* data and camera synchronize */
BL::Object b_camera_override(b_engine.camera_override());
sync->sync_data(b_render,
+ b_depsgraph,
b_v3d,
b_camera_override,
width, height,
- &python_thread_state,
- b_rlay_name.c_str());
+ &python_thread_state);
if(b_rv3d)
sync->sync_view(b_v3d, b_rv3d, width, height);
@@ -1023,20 +999,11 @@ int BlenderSession::builtin_image_frame(const string &builtin_name)
void BlenderSession::builtin_image_info(const string &builtin_name,
void *builtin_data,
- bool &is_float,
- int &width,
- int &height,
- int &depth,
- int &channels,
- bool& free_cache)
+ ImageMetaData& metadata)
{
/* empty image */
- is_float = false;
- width = 1;
- height = 1;
- depth = 0;
- channels = 0;
- free_cache = false;
+ metadata.width = 1;
+ metadata.height = 1;
if(!builtin_data)
return;
@@ -1050,33 +1017,34 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
/* image data */
BL::Image b_image(b_id);
- free_cache = !b_image.has_data();
- is_float = b_image.is_float();
- width = b_image.size()[0];
- height = b_image.size()[1];
- depth = 1;
- channels = b_image.channels();
+ metadata.builtin_free_cache = !b_image.has_data();
+ metadata.is_float = b_image.is_float();
+ metadata.width = b_image.size()[0];
+ metadata.height = b_image.size()[1];
+ metadata.depth = 1;
+ metadata.channels = b_image.channels();
}
else if(b_id.is_a(&RNA_Object)) {
/* smoke volume data */
BL::Object b_ob(b_id);
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
- is_float = true;
- depth = 1;
- channels = 1;
+ metadata.is_float = true;
+ metadata.depth = 1;
+ metadata.channels = 1;
if(!b_domain)
return;
if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) ||
builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) ||
- builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT))
- channels = 1;
+ builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) ||
+ builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE))
+ metadata.channels = 1;
else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
- channels = 4;
+ metadata.channels = 4;
else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY))
- channels = 3;
+ metadata.channels = 3;
else
return;
@@ -1090,9 +1058,9 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
amplify = 1;
}
- width = resolution.x * amplify;
- height = resolution.y * amplify;
- depth = resolution.z * amplify;
+ metadata.width = resolution.x * amplify;
+ metadata.height = resolution.y * amplify;
+ metadata.depth = resolution.z * amplify;
}
else {
/* TODO(sergey): Check we're indeed in shader node tree. */
@@ -1101,9 +1069,11 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
BL::Node b_node(ptr);
if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
- channels = 4;
- width = height = depth = b_point_density_node.resolution();
- is_float = true;
+ metadata.channels = 4;
+ metadata.width = b_point_density_node.resolution();
+ metadata.height = metadata.width;
+ metadata.depth = metadata.width;
+ metadata.is_float = true;
}
}
}
@@ -1292,6 +1262,13 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
return true;
}
}
+ else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
+ SmokeDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
+ if(length == num_pixels) {
+ SmokeDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
+ return true;
+ }
+ }
else {
fprintf(stderr,
"Cycles error: unknown volume attribute %s, skipping\n",
@@ -1303,6 +1280,11 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
}
else {
+ /* TODO: fix point density to work with new view layer depsgraph */
+#if 0
+ /* We originally were passing view_layer here but in reality we need a whole EvaluationContext or at the
+ * very least a dpesgraph to pass to the RE_point_density_minmax() function.
+ */
/* TODO(sergey): Check we're indeed in shader node tree. */
PointerRNA ptr;
RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
@@ -1311,8 +1293,9 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
int length;
int settings = background ? 1 : 0; /* 1 - render settings, 0 - vewport settings. */
- b_point_density_node.calc_point_density(b_scene, b_view_layer, settings, &length, &pixels);
+ b_point_density_node.calc_point_density(b_depsgraph, settings, &length, &pixels);
}
+#endif
}
return false;
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index 8694c9499b8..77a64031da1 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -26,6 +26,7 @@
CCL_NAMESPACE_BEGIN
+class ImageMetaData;
class Scene;
class Session;
class RenderBuffers;
@@ -36,13 +37,11 @@ public:
BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
- BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene);
BlenderSession(BL::RenderEngine& b_engine,
BL::UserPreferences& b_userpref,
BL::BlendData& b_data,
- BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
BL::SpaceView3D& b_v3d,
BL::RegionView3D& b_rv3d,
@@ -60,9 +59,10 @@ public:
BL::Scene& b_scene);
/* offline render */
- void render();
+ void render(BL::Depsgraph& b_depsgraph);
- void bake(BL::Object& b_object,
+ void bake(BL::Depsgraph& b_depsgrah,
+ BL::Object& b_object,
const string& pass_type,
const int custom_flag,
const int object_id,
@@ -84,7 +84,7 @@ public:
void update_render_tile(RenderTile& rtile, bool highlight);
/* interactive updates */
- void synchronize();
+ void synchronize(BL::Depsgraph& b_depsgraph);
/* drawing */
bool draw(int w, int h);
@@ -106,9 +106,7 @@ public:
BL::UserPreferences b_userpref;
BL::BlendData b_data;
BL::RenderSettings b_render;
- BL::Depsgraph b_depsgraph;
BL::Scene b_scene;
- BL::ViewLayer b_view_layer;
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
string b_rlay_name;
@@ -156,12 +154,7 @@ protected:
int builtin_image_frame(const string &builtin_name);
void builtin_image_info(const string &builtin_name,
void *builtin_data,
- bool &is_float,
- int &width,
- int &height,
- int &depth,
- int &channels,
- bool &free_cache);
+ ImageMetaData& metadata);
bool builtin_image_pixels(const string &builtin_name,
void *builtin_data,
unsigned char *pixels,
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 131e76d106e..d6e3f33fa9d 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -234,8 +234,8 @@ static void get_tex_mapping(TextureMapping *mapping,
static ShaderNode *add_node(Scene *scene,
BL::RenderEngine& b_engine,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
- BL::ViewLayer b_view_layer,
const bool background,
ShaderGraph *graph,
BL::ShaderNodeTree& b_ntree,
@@ -560,6 +560,10 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
node = new AbsorptionVolumeNode();
}
+ else if(b_node.is_a(&RNA_ShaderNodeVolumePrincipled)) {
+ PrincipledVolumeNode *principled = new PrincipledVolumeNode();
+ node = principled;
+ }
else if(b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
node = new GeometryNode();
}
@@ -831,6 +835,7 @@ static ShaderNode *add_node(Scene *scene,
node = uvm;
}
else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ /* TODO: fix point density to work with new view layer depsgraph */
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
PointDensityTextureNode *point_density = new PointDensityTextureNode();
point_density->filename = b_point_density_node.name();
@@ -843,7 +848,7 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Use more proper update flag. */
if(true) {
- b_point_density_node.cache_point_density(b_scene, b_view_layer, settings);
+ b_point_density_node.cache_point_density(b_depsgraph, settings);
scene->image_manager->tag_reload_image(
point_density->filename.string(),
point_density->builtin_data,
@@ -861,7 +866,7 @@ static ShaderNode *add_node(Scene *scene,
BL::Object b_ob(b_point_density_node.object());
if(b_ob) {
float3 loc, size;
- point_density_texture_space(b_scene, b_view_layer,
+ point_density_texture_space(b_depsgraph,
b_point_density_node,
settings,
loc,
@@ -1001,8 +1006,8 @@ static BL::ShaderNode find_output_node(BL::ShaderNodeTree& b_ntree)
static void add_nodes(Scene *scene,
BL::RenderEngine& b_engine,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
- BL::ViewLayer& b_view_layer,
const bool background,
ShaderGraph *graph,
BL::ShaderNodeTree& b_ntree,
@@ -1028,6 +1033,10 @@ static void add_nodes(Scene *scene,
for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
BL::NodeSocket to_socket(b_link->to_socket());
SocketType::Type to_socket_type = convert_socket_type(to_socket);
+ if (to_socket_type == SocketType::UNDEFINED) {
+ continue;
+ }
+
ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true);
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
@@ -1051,6 +1060,10 @@ static void add_nodes(Scene *scene,
*/
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
SocketType::Type input_type = convert_socket_type(*b_input);
+ if (input_type == SocketType::UNDEFINED) {
+ continue;
+ }
+
ConvertNode *proxy = new ConvertNode(input_type, input_type, true);
graph->add(proxy);
@@ -1063,6 +1076,10 @@ static void add_nodes(Scene *scene,
}
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
SocketType::Type output_type = convert_socket_type(*b_output);
+ if (output_type == SocketType::UNDEFINED) {
+ continue;
+ }
+
ConvertNode *proxy = new ConvertNode(output_type, output_type, true);
graph->add(proxy);
@@ -1076,8 +1093,8 @@ static void add_nodes(Scene *scene,
add_nodes(scene,
b_engine,
b_data,
+ b_depsgraph,
b_scene,
- b_view_layer,
background,
graph,
b_group_ntree,
@@ -1124,8 +1141,8 @@ static void add_nodes(Scene *scene,
node = add_node(scene,
b_engine,
b_data,
+ b_depsgraph,
b_scene,
- b_view_layer,
background,
graph,
b_ntree,
@@ -1188,8 +1205,8 @@ static void add_nodes(Scene *scene,
static void add_nodes(Scene *scene,
BL::RenderEngine& b_engine,
BL::BlendData& b_data,
+ BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
- BL::ViewLayer& b_view_layer,
const bool background,
ShaderGraph *graph,
BL::ShaderNodeTree& b_ntree)
@@ -1198,8 +1215,8 @@ static void add_nodes(Scene *scene,
add_nodes(scene,
b_engine,
b_data,
+ b_depsgraph,
b_scene,
- b_view_layer,
background,
graph,
b_ntree,
@@ -1209,7 +1226,7 @@ static void add_nodes(Scene *scene,
/* Sync Materials */
-void BlenderSync::sync_materials(bool update_all)
+void BlenderSync::sync_materials(BL::Depsgraph& b_depsgraph, bool update_all)
{
shader_map.set_default(scene->default_surface);
@@ -1238,7 +1255,7 @@ void BlenderSync::sync_materials(bool update_all)
if(b_mat->use_nodes() && b_mat->node_tree()) {
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, b_view_layer, !preview, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, !preview, graph, b_ntree);
}
else {
DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
@@ -1294,7 +1311,7 @@ void BlenderSync::sync_materials(bool update_all)
/* Sync World */
-void BlenderSync::sync_world(bool update_all)
+void BlenderSync::sync_world(BL::Depsgraph& b_depsgraph, bool update_all)
{
Background *background = scene->background;
Background prevbackground = *background;
@@ -1309,7 +1326,7 @@ void BlenderSync::sync_world(bool update_all)
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
BL::ShaderNodeTree b_ntree(b_world.node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, b_view_layer, !preview, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, !preview, graph, b_ntree);
/* volume */
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
@@ -1386,7 +1403,7 @@ void BlenderSync::sync_world(bool update_all)
/* Sync Lamps */
-void BlenderSync::sync_lamps(bool update_all)
+void BlenderSync::sync_lamps(BL::Depsgraph& b_depsgraph, bool update_all)
{
shader_map.set_default(scene->default_light);
@@ -1411,7 +1428,7 @@ void BlenderSync::sync_lamps(bool update_all)
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, b_view_layer, !preview, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, !preview, graph, b_ntree);
}
else {
float strength = 1.0f;
@@ -1438,7 +1455,7 @@ void BlenderSync::sync_lamps(bool update_all)
}
}
-void BlenderSync::sync_shaders()
+void BlenderSync::sync_shaders(BL::Depsgraph& b_depsgraph)
{
/* for auto refresh images */
bool auto_refresh_update = false;
@@ -1451,9 +1468,9 @@ void BlenderSync::sync_shaders()
shader_map.pre_sync();
- sync_world(auto_refresh_update);
- sync_lamps(auto_refresh_update);
- sync_materials(auto_refresh_update);
+ sync_world(b_depsgraph, auto_refresh_update);
+ sync_lamps(b_depsgraph, auto_refresh_update);
+ sync_materials(b_depsgraph, auto_refresh_update);
/* false = don't delete unused shaders, not supported */
shader_map.post_sync(false);
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 08d76582f03..bf35f61f07b 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -44,16 +44,13 @@ CCL_NAMESPACE_BEGIN
BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
BL::BlendData& b_data,
- BL::Depsgraph& b_depsgraph,
BL::Scene& b_scene,
Scene *scene,
bool preview,
Progress &progress)
: b_engine(b_engine),
b_data(b_data),
- b_depsgraph(b_depsgraph),
b_scene(b_scene),
- b_view_layer(b_engine.view_layer()),
shader_map(&scene->shaders),
object_map(&scene->objects),
mesh_map(&scene->meshes),
@@ -192,16 +189,18 @@ bool BlenderSync::sync_recalc()
}
void BlenderSync::sync_data(BL::RenderSettings& b_render,
+ BL::Depsgraph& b_depsgraph,
BL::SpaceView3D& b_v3d,
BL::Object& b_override,
int width, int height,
- void **python_thread_state,
- const char *layer)
+ void **python_thread_state)
{
- sync_view_layers(b_v3d, layer);
+ BL::ViewLayer b_view_layer = b_depsgraph.view_layer();
+
+ sync_view_layer(b_v3d, b_view_layer);
sync_integrator();
sync_film();
- sync_shaders();
+ sync_shaders(b_depsgraph);
sync_images();
sync_curve_settings();
@@ -211,9 +210,10 @@ void BlenderSync::sync_data(BL::RenderSettings& b_render,
scene->need_motion() == Scene::MOTION_NONE ||
scene->camera->motion_position == Camera::MOTION_POSITION_CENTER)
{
- sync_objects();
+ sync_objects(b_depsgraph);
}
sync_motion(b_render,
+ b_depsgraph,
b_override,
width, height,
python_thread_state);
@@ -372,47 +372,31 @@ void BlenderSync::sync_film()
/* Render Layer */
-void BlenderSync::sync_view_layers(BL::SpaceView3D& b_v3d, const char *layer)
+void BlenderSync::sync_view_layer(BL::SpaceView3D& /*b_v3d*/, BL::ViewLayer& b_view_layer)
{
- string layername;
-
- /* 3d view */
- if(b_v3d) {
- layername = b_scene.view_layers.active().name();
- layer = layername.c_str();
- }
-
/* render layer */
- BL::Scene::view_layers_iterator b_view_layer;
- bool first_layer = true;
uint layer_override = get_layer(b_engine.layer_override());
uint view_layers = layer_override ? layer_override : get_layer(b_scene.layers());
- for(b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end(); ++b_view_layer) {
- if((!layer && first_layer) || (layer && b_view_layer->name() == layer)) {
- view_layer.name = b_view_layer->name();
+ view_layer.name = b_view_layer.name();
- view_layer.holdout_layer = 0;
- view_layer.exclude_layer = 0;
+ view_layer.holdout_layer = 0;
+ view_layer.exclude_layer = 0;
- view_layer.view_layer = view_layers & ~view_layer.exclude_layer;
- view_layer.view_layer |= view_layer.exclude_layer & view_layer.holdout_layer;
+ view_layer.view_layer = view_layers & ~view_layer.exclude_layer;
+ view_layer.view_layer |= view_layer.exclude_layer & view_layer.holdout_layer;
- view_layer.layer = (1 << 20) - 1;
- view_layer.layer |= view_layer.holdout_layer;
+ view_layer.layer = (1 << 20) - 1;
+ view_layer.layer |= view_layer.holdout_layer;
- view_layer.material_override = PointerRNA_NULL;
- view_layer.use_background_shader = b_view_layer->use_sky();
- view_layer.use_background_ao = b_view_layer->use_ao();
- view_layer.use_surfaces = b_view_layer->use_solid();
- view_layer.use_hair = b_view_layer->use_strand();
+ view_layer.material_override = PointerRNA_NULL;
+ view_layer.use_background_shader = b_view_layer.use_sky();
+ view_layer.use_background_ao = b_view_layer.use_ao();
+ view_layer.use_surfaces = b_view_layer.use_solid();
+ view_layer.use_hair = b_view_layer.use_strand();
- view_layer.bound_samples = false;
- view_layer.samples = 0;
- }
-
- first_layer = false;
- }
+ view_layer.bound_samples = false;
+ view_layer.samples = 0;
}
/* Images */
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index c4dd17714be..2ea86ba1133 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -52,7 +52,6 @@ class BlenderSync {
public:
BlenderSync(BL::RenderEngine& b_engine,
BL::BlendData& b_data,
- BL::Depsgraph& b_graph,
BL::Scene& b_scene,
Scene *scene,
bool preview,
@@ -62,12 +61,12 @@ public:
/* sync */
bool sync_recalc();
void sync_data(BL::RenderSettings& b_render,
+ BL::Depsgraph& b_depsgraph,
BL::SpaceView3D& b_v3d,
BL::Object& b_override,
int width, int height,
- void **python_thread_state,
- const char *layer = 0);
- void sync_view_layers(BL::SpaceView3D& b_v3d, const char *layer);
+ void **python_thread_state);
+ void sync_view_layer(BL::SpaceView3D& b_v3d, BL::ViewLayer& b_view_layer);
array<Pass> sync_render_passes(BL::RenderLayer& b_render_layer,
BL::ViewLayer& b_view_layer,
const SessionParams &session_params);
@@ -101,30 +100,34 @@ public:
private:
/* sync */
- void sync_lamps(bool update_all);
- void sync_materials(bool update_all);
- void sync_objects(float motion_time = 0.0f);
+ void sync_lamps(BL::Depsgraph& b_depsgraph, bool update_all);
+ void sync_materials(BL::Depsgraph& b_depsgraph, bool update_all);
+ void sync_objects(BL::Depsgraph& b_depsgraph, float motion_time = 0.0f);
void sync_motion(BL::RenderSettings& b_render,
+ BL::Depsgraph& b_depsgraph,
BL::Object& b_override,
int width, int height,
void **python_thread_state);
void sync_film();
void sync_view();
- void sync_world(bool update_all);
- void sync_shaders();
+ void sync_world(BL::Depsgraph& b_depsgraph, bool update_all);
+ void sync_shaders(BL::Depsgraph& b_depsgraph);
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree& b_ntree);
- Mesh *sync_mesh(BL::Object& b_ob,
+ Mesh *sync_mesh(BL::Depsgraph& b_depsgrpah,
+ BL::Object& b_ob,
BL::Object& b_ob_instance,
bool object_updated,
bool hide_tris);
- void sync_curves(Mesh *mesh,
+ void sync_curves(BL::Depsgraph& b_depsgraph,
+ Mesh *mesh,
BL::Mesh& b_mesh,
BL::Object& b_ob,
bool motion,
- int time_index = 0);
- Object *sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter,
+ int motion_step = 0);
+ Object *sync_object(BL::Depsgraph& b_depsgraph,
+ BL::Depsgraph::duplis_iterator& b_dupli_iter,
uint layer_flag,
float motion_time,
bool hide_tris,
@@ -138,7 +141,8 @@ private:
Transform& tfm,
bool *use_portal);
void sync_background_light(bool use_portal);
- void sync_mesh_motion(BL::Object& b_ob,
+ void sync_mesh_motion(BL::Depsgraph& b_depsgraph,
+ BL::Object& b_ob,
Object *object,
float motion_time);
void sync_camera_motion(BL::RenderSettings& b_render,
@@ -163,9 +167,7 @@ private:
/* variables */
BL::RenderEngine b_engine;
BL::BlendData b_data;
- BL::Depsgraph b_depsgraph;
BL::Scene b_scene;
- BL::ViewLayer b_view_layer;
id_map<void*, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp
index 3b06fb720de..637f3632a49 100644
--- a/intern/cycles/blender/blender_texture.cpp
+++ b/intern/cycles/blender/blender_texture.cpp
@@ -34,7 +34,7 @@ void density_texture_space_invert(float3& loc,
} /* namespace */
-void point_density_texture_space(BL::Scene& b_scene, BL::ViewLayer& b_view_layer,
+void point_density_texture_space(BL::Depsgraph& b_depsgraph,
BL::ShaderNodeTexPointDensity& b_point_density_node,
int settings,
float3& loc,
@@ -47,8 +47,7 @@ void point_density_texture_space(BL::Scene& b_scene, BL::ViewLayer& b_view_layer
return;
}
float3 min, max;
- b_point_density_node.calc_point_density_minmax(b_scene,
- b_view_layer,
+ b_point_density_node.calc_point_density_minmax(b_depsgraph,
settings,
&min[0],
&max[0]);
diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h
index 3d4b8739d49..9c921d1e9f8 100644
--- a/intern/cycles/blender/blender_texture.h
+++ b/intern/cycles/blender/blender_texture.h
@@ -22,7 +22,7 @@
CCL_NAMESPACE_BEGIN
-void point_density_texture_space(BL::Scene& b_scene, BL::ViewLayer& b_view_layer,
+void point_density_texture_space(BL::Depsgraph& b_depsgraph,
BL::ShaderNodeTexPointDensity& b_point_density_node,
const int settings,
float3& loc,
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index a813a09f38a..5b67ff85a9b 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -248,14 +248,15 @@ static inline float *image_get_float_pixels_for_frame(BL::Image& image,
static inline Transform get_transform(const BL::Array<float, 16>& array)
{
- Transform tfm;
+ ProjectionTransform projection;
- /* we assume both types to be just 16 floats, and transpose because blender
- * use column major matrix order while we use row major */
- memcpy(&tfm, &array, sizeof(float)*16);
- tfm = transform_transpose(tfm);
+ /* We assume both types to be just 16 floats, and transpose because blender
+ * use column major matrix order while we use row major. */
+ memcpy(&projection, &array, sizeof(float)*16);
+ projection = projection_transpose(projection);
- return tfm;
+ /* Drop last row, matrix is assumed to be affine transform. */
+ return projection_to_transform(projection);
}
static inline float2 get_float2(const BL::Array<float, 2>& array)
@@ -484,33 +485,34 @@ static inline void mesh_texture_space(BL::Mesh& b_mesh,
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
}
-/* object used for motion blur */
-static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
+/* Object motion steps, returns 0 if no motion blur needed. */
+static inline uint object_motion_steps(BL::Object& b_parent, BL::Object& b_ob)
{
+ /* Get motion enabled and steps from object itself. */
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
bool use_motion = get_boolean(cobject, "use_motion_blur");
- /* If motion blur is enabled for the object we also check
- * whether it's enabled for the parent object as well.
- *
- * This way we can control motion blur from the dupligroup
- * duplicator much easier.
- */
- if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
+ if(!use_motion) {
+ return 0;
+ }
+
+ uint steps = max(1, get_int(cobject, "motion_steps"));
+
+ /* Also check parent object, so motion blur and steps can be
+ * controlled by dupligroup duplicator for linked groups. */
+ if(b_parent.ptr.data != b_ob.ptr.data) {
PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
use_motion &= get_boolean(parent_cobject, "use_motion_blur");
- }
- return use_motion;
-}
-/* object motion steps */
-static inline uint object_motion_steps(BL::Object& b_ob)
-{
- PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
- uint steps = get_int(cobject, "motion_steps");
+ if(!use_motion) {
+ return 0;
+ }
+
+ steps = max(steps, get_int(parent_cobject, "motion_steps"));
+ }
- /* use uneven number of steps so we get one keyframe at the current frame,
- * and ue 2^(steps - 1) so objects with more/fewer steps still have samples
- * at the same times, to avoid sampling at many different times */
+ /* Use uneven number of steps so we get one keyframe at the current frame,
+ * and use 2^(steps - 1) so objects with more/fewer steps still have samples
+ * at the same times, to avoid sampling at many different times. */
return (2 << (steps - 1)) + 1;
}
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index df88b91f5ac..8d04025e6fd 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -30,7 +30,7 @@ if(NOT CYCLES_STANDALONE_REPOSITORY)
set(GLEW_INCLUDE_DIR "${GLEW_INCLUDE_PATH}")
endif()
-if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
+if(WITH_CYCLES_STANDALONE)
set(CYCLES_APP_GLEW_LIBRARY ${BLENDER_GLEW_LIBRARIES})
endif()
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
index a3a8fa5f382..37aae211e93 100644
--- a/intern/cycles/graph/node_type.cpp
+++ b/intern/cycles/graph/node_type.cpp
@@ -77,7 +77,7 @@ size_t SocketType::max_size()
void *SocketType::zero_default_value()
{
- static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+ static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
return &zero_transform;
}
diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
index d26b3b2c2c8..f4599e22d40 100644
--- a/intern/cycles/graph/node_xml.cpp
+++ b/intern/cycles/graph/node_xml.cpp
@@ -196,7 +196,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
case SocketType::TRANSFORM:
{
array<Transform> value;
- xml_read_float_array<16>(value, attr);
+ xml_read_float_array<12>(value, attr);
if(value.size() == 1) {
node->set(socket, value[0]);
}
@@ -205,7 +205,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
case SocketType::TRANSFORM_ARRAY:
{
array<Transform> value;
- xml_read_float_array<16>(value, attr);
+ xml_read_float_array<12>(value, attr);
node->set(socket, value);
break;
}
@@ -400,12 +400,10 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
{
Transform tfm = node->get_transform(socket);
std::stringstream ss;
- for(int i = 0; i < 4; i++) {
- ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
- if(i != 3) {
- ss << " ";
- }
+ for(int i = 0; i < 3; i++) {
+ ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
}
+ ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
attr = ss.str().c_str();
break;
}
@@ -416,11 +414,12 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
for(size_t j = 0; j < value.size(); j++) {
const Transform& tfm = value[j];
- for(int i = 0; i < 4; i++) {
- ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
- if(j != value.size() - 1 || i != 3) {
- ss << " ";
- }
+ for(int i = 0; i < 3; i++) {
+ ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
+ }
+ ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
+ if(j != value.size() - 1) {
+ ss << " ";
}
}
attr = ss.str().c_str();
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 50ea03a1f8f..9b7f4e00084 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -254,6 +254,7 @@ set(SRC_UTIL_HEADERS
../util/util_math_int3.h
../util/util_math_int4.h
../util/util_math_matrix.h
+ ../util/util_projection.h
../util/util_rect.h
../util/util_static_assert.h
../util/util_transform.h
diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h
index 6c33dad5426..060b3934a41 100644
--- a/intern/cycles/kernel/bvh/bvh_nodes.h
+++ b/intern/cycles/kernel/bvh/bvh_nodes.h
@@ -25,7 +25,6 @@ ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *k
space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1);
space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2);
space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3);
- space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return space;
}
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index efd6798ca51..cfc567ff9ca 100644
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -276,7 +276,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
shader = __float_as_int(str.z);
}
#endif
- int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+ int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
/* if no transparent shadows, all light is blocked */
if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
index 522213f30ca..46fd178aed6 100644
--- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
@@ -358,7 +358,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
shader = __float_as_int(str.z);
}
#endif
- int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+ int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
/* if no transparent shadows, all light is blocked */
if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
diff --git a/intern/cycles/kernel/closure/bsdf_transparent.h b/intern/cycles/kernel/closure/bsdf_transparent.h
index 22ca7f3847e..79ee9dc4537 100644
--- a/intern/cycles/kernel/closure/bsdf_transparent.h
+++ b/intern/cycles/kernel/closure/bsdf_transparent.h
@@ -35,21 +35,38 @@
CCL_NAMESPACE_BEGIN
-ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight)
+ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight, int path_flag)
{
if(sd->flag & SD_TRANSPARENT) {
sd->closure_transparent_extinction += weight;
+
+ for(int i = 0; i < sd->num_closure; i++) {
+ ShaderClosure *sc = &sd->closure[i];
+
+ if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) {
+ sc->weight += weight;
+ sc->sample_weight += fabsf(average(weight));
+ break;
+ }
+ }
}
else {
sd->flag |= SD_BSDF|SD_TRANSPARENT;
sd->closure_transparent_extinction = weight;
- }
- ShaderClosure *bsdf = bsdf_alloc(sd, sizeof(ShaderClosure), weight);
+ if(path_flag & PATH_RAY_TERMINATE) {
+ /* In this case the number of closures is set to zero to disable
+ * all others, but we still want to get transparency so increase
+ * the number just for this. */
+ sd->num_closure_left = 1;
+ }
+
+ ShaderClosure *bsdf = bsdf_alloc(sd, sizeof(ShaderClosure), weight);
- if(bsdf) {
- bsdf->N = sd->N;
- bsdf->type = CLOSURE_BSDF_TRANSPARENT_ID;
+ if(bsdf) {
+ bsdf->N = sd->N;
+ bsdf->type = CLOSURE_BSDF_TRANSPARENT_ID;
+ }
}
}
diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
index c72595eed10..42c053704d5 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/geom_attribute.h
@@ -53,9 +53,7 @@ ccl_device_inline AttributeDescriptor attribute_not_found()
ccl_device_inline uint object_attribute_map_offset(KernelGlobals *kg, int object)
{
- int offset = object*OBJECT_SIZE + 15;
- float4 f = kernel_tex_fetch(__objects, offset);
- return __float_as_uint(f.y);
+ return kernel_tex_fetch(__objects, object).attribute_map_offset;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
@@ -105,7 +103,6 @@ ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderD
tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
- tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
return tfm;
}
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h
index faf3e3cdf2b..46c3f408f0b 100644
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ b/intern/cycles/kernel/geom/geom_curve_intersect.h
@@ -170,8 +170,7 @@ ccl_device_forceinline bool cardinal_curve_intersect(
htfm = make_transform(
dir.z / d, 0, -dir.x /d, 0,
-dir.x * dir.y /d, d, -dir.y * dir.z /d, 0,
- dir.x, dir.y, dir.z, 0,
- 0, 0, 0, 1);
+ dir.x, dir.y, dir.z, 0);
float4 v00 = kernel_tex_fetch(__curves, prim);
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index 32aa2007f5d..800649abf38 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -28,62 +28,44 @@ CCL_NAMESPACE_BEGIN
enum ObjectTransform {
OBJECT_TRANSFORM = 0,
- OBJECT_INVERSE_TRANSFORM = 4,
- OBJECT_TRANSFORM_MOTION_PRE = 0,
- OBJECT_TRANSFORM_MOTION_MID = 4,
- OBJECT_TRANSFORM_MOTION_POST = 8,
- OBJECT_PROPERTIES = 12,
- OBJECT_DUPLI = 13
+ OBJECT_INVERSE_TRANSFORM = 1,
};
enum ObjectVectorTransform {
- OBJECT_VECTOR_MOTION_PRE = 0,
- OBJECT_VECTOR_MOTION_POST = 3
+ OBJECT_PASS_MOTION_PRE = 0,
+ OBJECT_PASS_MOTION_POST = 1
};
/* Object to world space transformation */
ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
{
- int offset = object*OBJECT_SIZE + (int)type;
-
- Transform tfm;
- tfm.x = kernel_tex_fetch(__objects, offset + 0);
- tfm.y = kernel_tex_fetch(__objects, offset + 1);
- tfm.z = kernel_tex_fetch(__objects, offset + 2);
- tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
- return tfm;
+ if(type == OBJECT_INVERSE_TRANSFORM) {
+ return kernel_tex_fetch(__objects, object).itfm;
+ }
+ else {
+ return kernel_tex_fetch(__objects, object).tfm;
+ }
}
/* Lamp to world space transformation */
ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse)
{
- int offset = lamp*LIGHT_SIZE + (inverse? 8 : 5);
-
- Transform tfm;
- tfm.x = kernel_tex_fetch(__light_data, offset + 0);
- tfm.y = kernel_tex_fetch(__light_data, offset + 1);
- tfm.z = kernel_tex_fetch(__light_data, offset + 2);
- tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
- return tfm;
+ if(inverse) {
+ return kernel_tex_fetch(__lights, lamp).itfm;
+ }
+ else {
+ return kernel_tex_fetch(__lights, lamp).tfm;
+ }
}
/* Object to world space transformation for motion vectors */
-ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
+ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
{
- int offset = object*OBJECT_VECTOR_SIZE + (int)type;
-
- Transform tfm;
- tfm.x = kernel_tex_fetch(__objects_vector, offset + 0);
- tfm.y = kernel_tex_fetch(__objects_vector, offset + 1);
- tfm.z = kernel_tex_fetch(__objects_vector, offset + 2);
- tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
- return tfm;
+ int offset = object*OBJECT_MOTION_PASS_SIZE + (int)type;
+ return kernel_tex_fetch(__object_motion_pass, offset);
}
/* Motion blurred object transformations */
@@ -91,27 +73,12 @@ ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int
#ifdef __OBJECT_MOTION__
ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int object, float time)
{
- MotionTransform motion;
-
- int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE;
-
- motion.pre.x = kernel_tex_fetch(__objects, offset + 0);
- motion.pre.y = kernel_tex_fetch(__objects, offset + 1);
- motion.pre.z = kernel_tex_fetch(__objects, offset + 2);
- motion.pre.w = kernel_tex_fetch(__objects, offset + 3);
-
- motion.mid.x = kernel_tex_fetch(__objects, offset + 4);
- motion.mid.y = kernel_tex_fetch(__objects, offset + 5);
- motion.mid.z = kernel_tex_fetch(__objects, offset + 6);
- motion.mid.w = kernel_tex_fetch(__objects, offset + 7);
-
- motion.post.x = kernel_tex_fetch(__objects, offset + 8);
- motion.post.y = kernel_tex_fetch(__objects, offset + 9);
- motion.post.z = kernel_tex_fetch(__objects, offset + 10);
- motion.post.w = kernel_tex_fetch(__objects, offset + 11);
+ const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
+ const ccl_global DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
+ const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
Transform tfm;
- transform_motion_interpolate(&tfm, &motion, time);
+ transform_motion_array_interpolate(&tfm, motion, num_steps, time);
return tfm;
}
@@ -237,9 +204,7 @@ ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd
ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
{
- int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
- float4 f = kernel_tex_fetch(__objects, offset);
- return f.x;
+ return kernel_tex_fetch(__objects, object).surface_area;
}
/* Pass ID number of object */
@@ -249,9 +214,7 @@ ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0.0f;
- int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
- float4 f = kernel_tex_fetch(__objects, offset);
- return f.y;
+ return kernel_tex_fetch(__objects, object).pass_id;
}
/* Per lamp random number for shader variation */
@@ -261,8 +224,7 @@ ccl_device_inline float lamp_random_number(KernelGlobals *kg, int lamp)
if(lamp == LAMP_NONE)
return 0.0f;
- float4 f = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 4);
- return f.y;
+ return kernel_tex_fetch(__lights, lamp).random;
}
/* Per object random number for shader variation */
@@ -272,9 +234,7 @@ ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0.0f;
- int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
- float4 f = kernel_tex_fetch(__objects, offset);
- return f.z;
+ return kernel_tex_fetch(__objects, object).random_number;
}
/* Particle ID from which this object was generated */
@@ -284,9 +244,7 @@ ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0;
- int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
- float4 f = kernel_tex_fetch(__objects, offset);
- return __float_as_uint(f.w);
+ return kernel_tex_fetch(__objects, object).particle_index;
}
/* Generated texture coordinate on surface from where object was instanced */
@@ -296,9 +254,10 @@ ccl_device_inline float3 object_dupli_generated(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
- int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
- float4 f = kernel_tex_fetch(__objects, offset);
- return make_float3(f.x, f.y, f.z);
+ const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ return make_float3(kobject->dupli_generated[0],
+ kobject->dupli_generated[1],
+ kobject->dupli_generated[2]);
}
/* UV texture coordinate on surface from where object was instanced */
@@ -308,27 +267,24 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
- int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
- float4 f = kernel_tex_fetch(__objects, offset + 1);
- return make_float3(f.x, f.y, 0.0f);
+ const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ return make_float3(kobject->dupli_uv[0],
+ kobject->dupli_uv[1],
+ 0.0f);
}
/* Information about mesh for motion blurred triangles and curves */
ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
{
- int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-
if(numkeys) {
- float4 f = kernel_tex_fetch(__objects, offset);
- *numkeys = __float_as_int(f.w);
+ *numkeys = kernel_tex_fetch(__objects, object).numkeys;
}
- float4 f = kernel_tex_fetch(__objects, offset + 1);
if(numsteps)
- *numsteps = __float_as_int(f.z);
+ *numsteps = kernel_tex_fetch(__objects, object).numsteps;
if(numverts)
- *numverts = __float_as_int(f.w);
+ *numverts = kernel_tex_fetch(__objects, object).numverts;
}
/* Offset to an objects patch map */
@@ -338,76 +294,56 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0;
- int offset = object*OBJECT_SIZE + 15;
- float4 f = kernel_tex_fetch(__objects, offset);
- return __float_as_uint(f.x);
+ return kernel_tex_fetch(__objects, object).patch_map_offset;
}
/* Pass ID for shader */
ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
{
- return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE + 1);
+ return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
}
/* Particle data from which object was instanced */
ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f = kernel_tex_fetch(__particles, offset + 0);
- return __float_as_uint(f.x);
+ return kernel_tex_fetch(__particles, particle).index;
}
ccl_device float particle_age(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f = kernel_tex_fetch(__particles, offset + 0);
- return f.y;
+ return kernel_tex_fetch(__particles, particle).age;
}
ccl_device float particle_lifetime(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f = kernel_tex_fetch(__particles, offset + 0);
- return f.z;
+ return kernel_tex_fetch(__particles, particle).lifetime;
}
ccl_device float particle_size(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f = kernel_tex_fetch(__particles, offset + 0);
- return f.w;
+ return kernel_tex_fetch(__particles, particle).size;
}
ccl_device float4 particle_rotation(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f = kernel_tex_fetch(__particles, offset + 1);
- return f;
+ return kernel_tex_fetch(__particles, particle).rotation;
}
ccl_device float3 particle_location(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f = kernel_tex_fetch(__particles, offset + 2);
- return make_float3(f.x, f.y, f.z);
+ return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
}
ccl_device float3 particle_velocity(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f2 = kernel_tex_fetch(__particles, offset + 2);
- float4 f3 = kernel_tex_fetch(__particles, offset + 3);
- return make_float3(f2.w, f3.x, f3.y);
+ return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
}
ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
{
- int offset = particle*PARTICLE_SIZE;
- float4 f3 = kernel_tex_fetch(__particles, offset + 3);
- float4 f4 = kernel_tex_fetch(__particles, offset + 4);
- return make_float3(f3.z, f3.w, f4.x);
+ return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
}
/* Object intersection in BVH */
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index 60a1e483b84..c159be92885 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -193,10 +193,10 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
* transformation was set match the world/object space of motion_pre/post */
Transform tfm;
- tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
+ tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
motion_pre = transform_point(&tfm, motion_pre);
- tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
+ tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
motion_post = transform_point(&tfm, motion_post);
float3 motion_center;
@@ -204,14 +204,14 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
/* camera motion, for perspective/orthographic motion.pre/post will be a
* world-to-raster matrix, for panorama it's world-to-camera */
if(kernel_data.cam.type != CAMERA_PANORAMA) {
- tfm = kernel_data.cam.worldtoraster;
- motion_center = transform_perspective(&tfm, center);
+ ProjectionTransform projection = kernel_data.cam.worldtoraster;
+ motion_center = transform_perspective(&projection, center);
- tfm = kernel_data.cam.motion.pre;
- motion_pre = transform_perspective(&tfm, motion_pre);
+ projection = kernel_data.cam.perspective_pre;
+ motion_pre = transform_perspective(&projection, motion_pre);
- tfm = kernel_data.cam.motion.post;
- motion_post = transform_perspective(&tfm, motion_post);
+ projection = kernel_data.cam.perspective_post;
+ motion_post = transform_perspective(&projection, motion_post);
}
else {
tfm = kernel_data.cam.worldtocamera;
@@ -220,13 +220,13 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
motion_center.x *= kernel_data.cam.width;
motion_center.y *= kernel_data.cam.height;
- tfm = kernel_data.cam.motion.pre;
+ tfm = kernel_data.cam.motion_pass_pre;
motion_pre = normalize(transform_point(&tfm, motion_pre));
motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
motion_pre.x *= kernel_data.cam.width;
motion_pre.y *= kernel_data.cam.height;
- tfm = kernel_data.cam.motion.post;
+ tfm = kernel_data.cam.motion_pass_post;
motion_post = normalize(transform_point(&tfm, motion_post));
motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
motion_post.x *= kernel_data.cam.width;
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index 6be448c4fa4..a4e47384b25 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -68,7 +68,13 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
- return float4_to_float3(r);
+ if(r.w > 1e-8f && r.w != 1.0f) {
+ /* For RGBA colors, unpremultiply after interpolation. */
+ return float4_to_float3(r) / r.w;
+ }
+ else {
+ return float4_to_float3(r);
+ }
}
#endif
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 8788e89c40e..79e6d1b4862 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -51,7 +51,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
path_state_init(kg, &emission_sd, &state, rng_hash, sample, NULL);
/* evaluate surface shader */
- shader_eval_surface(kg, sd, &state, state.flag, kernel_data.integrator.max_closures);
+ shader_eval_surface(kg, sd, &state, state.flag);
/* TODO, disable more closures we don't need besides transparent */
shader_bsdf_disable_transparency(kg, sd);
@@ -228,12 +228,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
}
else {
/* surface color of the pass only */
- shader_eval_surface(kg, sd, state, 0, kernel_data.integrator.max_closures);
+ shader_eval_surface(kg, sd, state, 0);
return kernel_bake_shader_bsdf(kg, sd, type);
}
}
else {
- shader_eval_surface(kg, sd, state, 0, kernel_data.integrator.max_closures);
+ shader_eval_surface(kg, sd, state, 0);
color = kernel_bake_shader_bsdf(kg, sd, type);
}
@@ -330,15 +330,30 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
switch(type) {
/* data passes */
case SHADER_EVAL_NORMAL:
+ case SHADER_EVAL_ROUGHNESS:
+ case SHADER_EVAL_EMISSION:
{
- float3 N = sd.N;
- if((sd.flag & SD_HAS_BUMP)) {
- shader_eval_surface(kg, &sd, &state, 0, kernel_data.integrator.max_closures);
- N = shader_bsdf_average_normal(kg, &sd);
+ if(type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) {
+ int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0;
+ shader_eval_surface(kg, &sd, &state, path_flag);
}
- /* encoding: normal = (2 * color) - 1 */
- out = N * 0.5f + make_float3(0.5f, 0.5f, 0.5f);
+ if(type == SHADER_EVAL_NORMAL) {
+ float3 N = sd.N;
+ if(sd.flag & SD_HAS_BUMP) {
+ N = shader_bsdf_average_normal(kg, &sd);
+ }
+
+ /* encoding: normal = (2 * color) - 1 */
+ out = N * 0.5f + make_float3(0.5f, 0.5f, 0.5f);
+ }
+ else if(type == SHADER_EVAL_ROUGHNESS) {
+ float roughness = shader_bsdf_average_roughness(&sd);
+ out = make_float3(roughness, roughness, roughness);
+ }
+ else {
+ out = shader_emissive_eval(kg, &sd);
+ }
break;
}
case SHADER_EVAL_UV:
@@ -346,13 +361,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
out = primitive_uv(kg, &sd);
break;
}
- case SHADER_EVAL_EMISSION:
- {
- shader_eval_surface(kg, &sd, &state, 0, 0);
- out = shader_emissive_eval(kg, &sd);
- break;
- }
-
#ifdef __PASSES__
/* light passes */
case SHADER_EVAL_AO:
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index 96cdb04d955..b73ad47dad3 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -42,7 +42,7 @@ ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u
ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
/* create ray form raster position */
- Transform rastertocamera = kernel_data.cam.rastertocamera;
+ ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
float3 raster = make_float3(raster_x, raster_y, 0.0f);
float3 Pcamera = transform_perspective(&rastertocamera, raster);
@@ -54,13 +54,13 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
* interpolated field of view.
*/
if(ray->time < 0.5f) {
- Transform rastertocamera_pre = kernel_data.cam.perspective_motion.pre;
+ ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
float3 Pcamera_pre =
transform_perspective(&rastertocamera_pre, raster);
Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
}
else {
- Transform rastertocamera_post = kernel_data.cam.perspective_motion.post;
+ ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
float3 Pcamera_post =
transform_perspective(&rastertocamera_post, raster);
Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
@@ -91,17 +91,12 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
Transform cameratoworld = kernel_data.cam.cameratoworld;
#ifdef __CAMERA_MOTION__
- if(kernel_data.cam.have_motion) {
-# ifdef __KERNEL_OPENCL__
- const MotionTransform tfm = kernel_data.cam.motion;
- transform_motion_interpolate(&cameratoworld,
- &tfm,
- ray->time);
-# else
- transform_motion_interpolate(&cameratoworld,
- &kernel_data.cam.motion,
- ray->time);
-# endif
+ if(kernel_data.cam.num_motion_steps) {
+ transform_motion_array_interpolate(
+ &cameratoworld,
+ kernel_tex_array(__camera_motion),
+ kernel_data.cam.num_motion_steps,
+ ray->time);
}
#endif
@@ -175,7 +170,7 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
/* create ray form raster position */
- Transform rastertocamera = kernel_data.cam.rastertocamera;
+ ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
float3 P;
@@ -203,17 +198,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
Transform cameratoworld = kernel_data.cam.cameratoworld;
#ifdef __CAMERA_MOTION__
- if(kernel_data.cam.have_motion) {
-# ifdef __KERNEL_OPENCL__
- const MotionTransform tfm = kernel_data.cam.motion;
- transform_motion_interpolate(&cameratoworld,
- &tfm,
- ray->time);
-# else
- transform_motion_interpolate(&cameratoworld,
- &kernel_data.cam.motion,
- ray->time);
-# endif
+ if(kernel_data.cam.num_motion_steps) {
+ transform_motion_array_interpolate(
+ &cameratoworld,
+ kernel_tex_array(__camera_motion),
+ kernel_data.cam.num_motion_steps,
+ ray->time);
}
#endif
@@ -239,11 +229,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
/* Panorama Camera */
ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
+ const ccl_global DecomposedTransform *cam_motion,
float raster_x, float raster_y,
float lens_u, float lens_v,
ccl_addr_space Ray *ray)
{
- Transform rastertocamera = cam->rastertocamera;
+ ProjectionTransform rastertocamera = cam->rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
/* create ray form raster position */
@@ -281,17 +272,12 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
Transform cameratoworld = cam->cameratoworld;
#ifdef __CAMERA_MOTION__
- if(cam->have_motion) {
-# ifdef __KERNEL_OPENCL__
- const MotionTransform tfm = cam->motion;
- transform_motion_interpolate(&cameratoworld,
- &tfm,
- ray->time);
-# else
- transform_motion_interpolate(&cameratoworld,
- &cam->motion,
- ray->time);
-# endif
+ if(cam->num_motion_steps) {
+ transform_motion_array_interpolate(
+ &cameratoworld,
+ cam_motion,
+ cam->num_motion_steps,
+ ray->time);
}
#endif
@@ -410,12 +396,16 @@ ccl_device_inline void camera_sample(KernelGlobals *kg,
#endif
/* sample */
- if(kernel_data.cam.type == CAMERA_PERSPECTIVE)
+ if(kernel_data.cam.type == CAMERA_PERSPECTIVE) {
camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
- else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ }
+ else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
- else
- camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
+ }
+ else {
+ const ccl_global DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
+ camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
+ }
}
/* Utilities */
@@ -460,7 +450,7 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
if(sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
P += camera_position(kg);
- Transform tfm = kernel_data.cam.worldtondc;
+ ProjectionTransform tfm = kernel_data.cam.worldtondc;
return transform_perspective(&tfm, P);
}
else {
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index 61cd90e9d2a..d26b668cb11 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -118,6 +118,7 @@ template<typename T> struct texture {
#define kernel_tex_fetch_ssef(tex, index) (kg->tex.fetch_ssef(index))
#define kernel_tex_fetch_ssei(tex, index) (kg->tex.fetch_ssei(index))
#define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
+#define kernel_tex_array(tex) (kg->tex.data)
#define kernel_data (kg->__data)
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 9bd7a572f5f..ac63bcf7ac9 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -137,6 +137,7 @@ ccl_device_inline uint ccl_num_groups(uint d)
/* Use arrays for regular data. */
#define kernel_tex_fetch(t, index) t[(index)]
+#define kernel_tex_array(t) (t)
#define kernel_data __data
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index b02e3bc576d..671c47e2225 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -144,7 +144,8 @@
/* data lookup defines */
#define kernel_data (*kg->data)
-#define kernel_tex_fetch(tex, index) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))[(index)]
+#define kernel_tex_array(tex) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))
+#define kernel_tex_fetch(tex, index) kernel_tex_array(tex)[(index)]
/* define NULL */
#define NULL 0
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 94b0a37ce62..a5556c3be8f 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -29,7 +29,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
/* setup shading at emitter */
float3 eval;
- int shader_flag = kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE);
+ int shader_flag = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).flags;
#ifdef __BACKGROUND_MIS__
if(ls->type == LIGHT_BACKGROUND) {
@@ -51,9 +51,9 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
#endif
if(shader_flag & SD_HAS_CONSTANT_EMISSION)
{
- eval.x = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 2));
- eval.y = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 3));
- eval.z = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 4));
+ eval.x = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[0];
+ eval.y = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[1];
+ eval.z = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[2];
if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
ls->Ng = -ls->Ng;
}
@@ -67,13 +67,13 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ls->Ng = emission_sd->Ng;
- /* no path flag, we're evaluating this for all closures. that's weak but
- * we'd have to do multiple evaluations otherwise */
+ /* No proper path flag, we're evaluating this for all closures. that's
+ * weak but we'd have to do multiple evaluations otherwise. */
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, emission_sd, state, 0, 0);
+ shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION);
path_state_modify_bounce(state, false);
- /* evaluate emissive closure */
+ /* Evaluate emissive closure. */
eval = shader_emissive_eval(kg, emission_sd);
}
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index dfa3150dc92..efab69ee37d 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -255,11 +255,11 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals
float3 *lightpos,
float3 *dir)
{
- float4 data0 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
- float4 data3 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
+ int portal = kernel_data.integrator.portal_offset + index;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
- *lightpos = make_float3(data0.y, data0.z, data0.w);
- *dir = make_float3(data3.y, data3.z, data3.w);
+ *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
/* Check whether portal is on the right side. */
if(dot(*dir, P - *lightpos) > 1e-4f)
@@ -291,11 +291,10 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg,
}
num_possible++;
- float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
- float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
-
- float3 axisu = make_float3(data1.y, data1.z, data1.w);
- float3 axisv = make_float3(data2.y, data2.z, data2.w);
+ int portal = kernel_data.integrator.portal_offset + p;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL))
continue;
@@ -346,10 +345,10 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg,
if(portal == 0) {
/* p is the portal to be sampled. */
- float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
- float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
- float3 axisu = make_float3(data1.y, data1.z, data1.w);
- float3 axisv = make_float3(data2.y, data2.z, data2.w);
+ int portal = kernel_data.integrator.portal_offset + p;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+ float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
*pdf = area_light_sample(P, &lightpos,
axisu, axisv,
@@ -479,14 +478,10 @@ ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, flo
return disk_light_sample(normalize(P - center), randu, randv)*radius;
}
-ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
+ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls)
{
- float3 dir = make_float3(data2.y, data2.z, data2.w);
float3 I = ls->Ng;
- float spot_angle = data1.w;
- float spot_smooth = data2.x;
-
float attenuation = dot(dir, I);
if(attenuation <= spot_angle) {
@@ -518,12 +513,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
float3 P,
LightSample *ls)
{
- float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
- float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
-
- LightType type = (LightType)__float_as_int(data0.x);
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ LightType type = (LightType)klight->type;
ls->type = type;
- ls->shader = __float_as_int(data1.x);
+ ls->shader = klight->shader_id;
ls->object = PRIM_NONE;
ls->prim = PRIM_NONE;
ls->lamp = lamp;
@@ -532,10 +525,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
if(type == LIGHT_DISTANT) {
/* distant light */
- float3 lightD = make_float3(data0.y, data0.z, data0.w);
+ float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
float3 D = lightD;
- float radius = data1.y;
- float invarea = data1.w;
+ float radius = klight->distant.radius;
+ float invarea = klight->distant.invarea;
if(radius > 0.0f)
D = distant_light_sample(D, radius, randu, randv);
@@ -562,10 +555,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
}
#endif
else {
- ls->P = make_float3(data0.y, data0.z, data0.w);
+ ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
if(type == LIGHT_POINT || type == LIGHT_SPOT) {
- float radius = data1.y;
+ float radius = klight->spot.radius;
if(radius > 0.0f)
/* sphere light */
@@ -574,14 +567,19 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
ls->D = normalize_len(ls->P - P, &ls->t);
ls->Ng = -ls->D;
- float invarea = data1.z;
+ float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
ls->pdf = invarea;
if(type == LIGHT_SPOT) {
/* spot light attenuation */
- float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
- ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+ float3 dir = make_float3(klight->spot.dir[0],
+ klight->spot.dir[1],
+ klight->spot.dir[2]);
+ ls->eval_fac *= spot_light_attenuation(dir,
+ klight->spot.spot_angle,
+ klight->spot.spot_smooth,
+ ls);
if(ls->eval_fac == 0.0f) {
return false;
}
@@ -594,12 +592,15 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
}
else {
/* area light */
- float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
- float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
-
- float3 axisu = make_float3(data1.y, data1.z, data1.w);
- float3 axisv = make_float3(data2.y, data2.z, data2.w);
- float3 D = make_float3(data3.y, data3.z, data3.w);
+ float3 axisu = make_float3(klight->area.axisu[0],
+ klight->area.axisu[1],
+ klight->area.axisu[2]);
+ float3 axisv = make_float3(klight->area.axisv[0],
+ klight->area.axisv[1],
+ klight->area.axisv[2]);
+ float3 D = make_float3(klight->area.dir[0],
+ klight->area.dir[1],
+ klight->area.dir[2]);
if(dot(ls->P - P, D) > 0.0f) {
return false;
@@ -618,7 +619,7 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
ls->Ng = D;
ls->D = normalize_len(ls->P - P, &ls->t);
- float invarea = data2.x;
+ float invarea = klight->area.invarea;
ls->eval_fac = 0.25f*invarea;
}
}
@@ -630,12 +631,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
{
- float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
- float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
-
- LightType type = (LightType)__float_as_int(data0.x);
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ LightType type = (LightType)klight->type;
ls->type = type;
- ls->shader = __float_as_int(data1.x);
+ ls->shader = klight->shader_id;
ls->object = PRIM_NONE;
ls->prim = PRIM_NONE;
ls->lamp = lamp;
@@ -648,7 +647,7 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
if(type == LIGHT_DISTANT) {
/* distant light */
- float radius = data1.y;
+ float radius = klight->distant.radius;
if(radius == 0.0f)
return false;
@@ -670,9 +669,9 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
* P
*/
- float3 lightD = make_float3(data0.y, data0.z, data0.w);
+ float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
float costheta = dot(-lightD, D);
- float cosangle = data1.z;
+ float cosangle = klight->distant.cosangle;
if(costheta < cosangle)
return false;
@@ -683,13 +682,14 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
ls->t = FLT_MAX;
/* compute pdf */
- float invarea = data1.w;
+ float invarea = klight->distant.invarea;
ls->pdf = invarea/(costheta*costheta*costheta);
ls->eval_fac = ls->pdf;
}
else if(type == LIGHT_POINT || type == LIGHT_SPOT) {
- float3 lightP = make_float3(data0.y, data0.z, data0.w);
- float radius = data1.y;
+ float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ float radius = klight->spot.radius;
/* sphere light */
if(radius == 0.0f)
@@ -704,14 +704,19 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
ls->Ng = -D;
ls->D = D;
- float invarea = data1.z;
+ float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
ls->pdf = invarea;
if(type == LIGHT_SPOT) {
/* spot light attenuation */
- float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
- ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+ float3 dir = make_float3(klight->spot.dir[0],
+ klight->spot.dir[1],
+ klight->spot.dir[2]);
+ ls->eval_fac *= spot_light_attenuation(dir,
+ klight->spot.spot_angle,
+ klight->spot.spot_smooth,
+ ls);
if(ls->eval_fac == 0.0f)
return false;
@@ -726,22 +731,25 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
}
else if(type == LIGHT_AREA) {
/* area light */
- float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
- float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
-
- float invarea = data2.x;
+ float invarea = klight->area.invarea;
if(invarea == 0.0f)
return false;
- float3 axisu = make_float3(data1.y, data1.z, data1.w);
- float3 axisv = make_float3(data2.y, data2.z, data2.w);
- float3 Ng = make_float3(data3.y, data3.z, data3.w);
+ float3 axisu = make_float3(klight->area.axisu[0],
+ klight->area.axisu[1],
+ klight->area.axisu[2]);
+ float3 axisv = make_float3(klight->area.axisv[0],
+ klight->area.axisv[1],
+ klight->area.axisv[2]);
+ float3 Ng = make_float3(klight->area.dir[0],
+ klight->area.dir[1],
+ klight->area.dir[2]);
/* one sided */
if(dot(D, Ng) >= 0.0f)
return false;
- float3 light_P = make_float3(data0.y, data0.z, data0.w);
+ float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
if(!ray_quad_intersect(P, D, 0.0f, t, light_P,
axisu, axisv, Ng,
@@ -784,7 +792,8 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
#ifdef __INSTANCING__
if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
# ifdef __OBJECT_MOTION__
- Transform tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
+ float object_time = (time >= 0.0f) ? time : 0.5f;
+ Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
# else
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
# endif
@@ -1040,7 +1049,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
int half_len = len >> 1;
int middle = first + half_len;
- if(r < kernel_tex_fetch(__light_distribution, middle).x) {
+ if(r < kernel_tex_fetch(__light_distribution, middle).totarea) {
len = half_len;
}
else {
@@ -1055,8 +1064,8 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
/* Rescale to reuse random number. this helps the 2D samples within
* each area light be stratified as well. */
- float distr_min = kernel_tex_fetch(__light_distribution, index).x;
- float distr_max = kernel_tex_fetch(__light_distribution, index+1).x;
+ float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
+ float distr_max = kernel_tex_fetch(__light_distribution, index+1).totarea;
*randu = (r - distr_min)/(distr_max - distr_min);
return index;
@@ -1066,8 +1075,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, int bounce)
{
- float4 data4 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 4);
- return (bounce > __float_as_int(data4.x));
+ return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
}
ccl_device_noinline bool light_sample(KernelGlobals *kg,
@@ -1082,12 +1090,12 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
int index = light_distribution_sample(kg, &randu);
/* fetch light data */
- float4 l = kernel_tex_fetch(__light_distribution, index);
- int prim = __float_as_int(l.y);
+ const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
+ int prim = kdistribution->prim;
if(prim >= 0) {
- int object = __float_as_int(l.w);
- int shader_flag = __float_as_int(l.z);
+ int object = kdistribution->mesh_light.object_id;
+ int shader_flag = kdistribution->mesh_light.shader_flag;
triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
ls->shader |= shader_flag;
@@ -1106,8 +1114,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
ccl_device int light_select_num_samples(KernelGlobals *kg, int index)
{
- float4 data3 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 3);
- return __float_as_int(data3.x);
+ return kernel_tex_fetch(__lights, index).samples;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h
index bd0e23b7705..96391db7649 100644
--- a/intern/cycles/kernel/kernel_math.h
+++ b/intern/cycles/kernel/kernel_math.h
@@ -21,6 +21,7 @@
#include "util/util_math.h"
#include "util/util_math_fast.h"
#include "util/util_math_intersect.h"
+#include "util/util_projection.h"
#include "util/util_texture.h"
#include "util/util_transform.h"
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index dbbb80ca37f..b0f53aef2d5 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -400,6 +400,13 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
PathState *state,
PathRadiance *L)
{
+#ifdef __SUBSURFACE__
+ SubsurfaceIndirectRays ss_indirect;
+ kernel_path_subsurface_init_indirect(&ss_indirect);
+
+ for(;;) {
+#endif /* __SUBSURFACE__ */
+
/* path iteration */
for(;;) {
/* Find intersection with objects in scene. */
@@ -438,12 +445,16 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
break;
}
- /* Setup and evaluate shader. */
- shader_setup_from_ray(kg,
- sd,
- &isect,
- ray);
- shader_eval_surface(kg, sd, state, state->flag, kernel_data.integrator.max_closures);
+ /* Setup shader data. */
+ shader_setup_from_ray(kg, sd, &isect, ray);
+
+ /* Skip most work for volume bounding surface. */
+#ifdef __VOLUME__
+ if(!(sd->flag & SD_HAS_ONLY_VOLUME)) {
+#endif
+
+ /* Evaluate shader. */
+ shader_eval_surface(kg, sd, state, state->flag);
shader_prepare_closures(sd, state);
/* Apply shadow catcher, holdout, emission. */
@@ -485,29 +496,21 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
#endif /* __AO__ */
+
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
* the closures with a diffuse BSDF */
if(sd->flag & SD_BSSRDF) {
- float bssrdf_u, bssrdf_v;
- path_state_rng_2D(kg,
- state,
- PRNG_BSDF_U,
- &bssrdf_u, &bssrdf_v);
-
- const ShaderClosure *sc = shader_bssrdf_pick(sd, &throughput, &bssrdf_u);
-
- /* do bssrdf scatter step if we picked a bssrdf closure */
- if(sc) {
- uint lcg_state = lcg_state_init(state, 0x68bc21eb);
-
- subsurface_scatter_step(kg,
- sd,
- state,
- sc,
- &lcg_state,
- bssrdf_u, bssrdf_v,
- false);
+ if(kernel_path_subsurface_scatter(kg,
+ sd,
+ emission_sd,
+ L,
+ state,
+ ray,
+ &throughput,
+ &ss_indirect))
+ {
+ break;
}
}
#endif /* __SUBSURFACE__ */
@@ -527,9 +530,31 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
#endif /* defined(__EMISSION__) */
+#ifdef __VOLUME__
+ }
+#endif
+
if(!kernel_path_surface_bounce(kg, sd, &throughput, state, &L->state, ray))
break;
}
+
+#ifdef __SUBSURFACE__
+ /* Trace indirect subsurface rays by restarting the loop. this uses less
+ * stack memory than invoking kernel_path_indirect.
+ */
+ if(ss_indirect.num_rays) {
+ kernel_path_subsurface_setup_indirect(kg,
+ &ss_indirect,
+ state,
+ ray,
+ L,
+ &throughput);
+ }
+ else {
+ break;
+ }
+ }
+#endif /* __SUBSURFACE__ */
}
#endif /* defined(__BRANCHED_PATH__) || defined(__BAKING__) */
@@ -591,9 +616,16 @@ ccl_device_forceinline void kernel_path_integrate(
break;
}
- /* Setup and evaluate shader. */
+ /* Setup shader data. */
shader_setup_from_ray(kg, &sd, &isect, ray);
- shader_eval_surface(kg, &sd, state, state->flag, kernel_data.integrator.max_closures);
+
+ /* Skip most work for volume bounding surface. */
+#ifdef __VOLUME__
+ if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
+#endif
+
+ /* Evaluate shader. */
+ shader_eval_surface(kg, &sd, state, state->flag);
shader_prepare_closures(&sd, state);
/* Apply shadow catcher, holdout, emission. */
@@ -655,6 +687,10 @@ ccl_device_forceinline void kernel_path_integrate(
/* direct lighting */
kernel_path_surface_connect_light(kg, &sd, emission_sd, throughput, state, L);
+#ifdef __VOLUME__
+ }
+#endif
+
/* compute direct lighting and next bounce */
if(!kernel_path_surface_bounce(kg, &sd, &throughput, state, &L->state, ray))
break;
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index 6fb55bda08d..d43d418db29 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -480,7 +480,13 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
/* Setup and evaluate shader. */
shader_setup_from_ray(kg, &sd, &isect, &ray);
- shader_eval_surface(kg, &sd, &state, state.flag, kernel_data.integrator.max_closures);
+
+ /* Skip most work for volume bounding surface. */
+#ifdef __VOLUME__
+ if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
+#endif
+
+ shader_eval_surface(kg, &sd, &state, state.flag);
shader_merge_closures(&sd);
/* Apply shadow catcher, holdout, emission. */
@@ -533,37 +539,46 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
}
#endif /* __SUBSURFACE__ */
- if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
- PathState hit_state = state;
+ PathState hit_state = state;
#ifdef __EMISSION__
- /* direct light */
- if(kernel_data.integrator.use_direct_light) {
- int all = (kernel_data.integrator.sample_all_lights_direct) ||
- (state.flag & PATH_RAY_SHADOW_CATCHER);
- kernel_branched_path_surface_connect_light(kg,
- &sd, emission_sd, &hit_state, throughput, 1.0f, L, all);
- }
+ /* direct light */
+ if(kernel_data.integrator.use_direct_light) {
+ int all = (kernel_data.integrator.sample_all_lights_direct) ||
+ (state.flag & PATH_RAY_SHADOW_CATCHER);
+ kernel_branched_path_surface_connect_light(kg,
+ &sd, emission_sd, &hit_state, throughput, 1.0f, L, all);
+ }
#endif /* __EMISSION__ */
- /* indirect light */
- kernel_branched_path_surface_indirect_light(kg,
- &sd, &indirect_sd, emission_sd, throughput, 1.0f, &hit_state, L);
+ /* indirect light */
+ kernel_branched_path_surface_indirect_light(kg,
+ &sd, &indirect_sd, emission_sd, throughput, 1.0f, &hit_state, L);
- /* continue in case of transparency */
- throughput *= shader_bsdf_transparency(kg, &sd);
+ /* continue in case of transparency */
+ throughput *= shader_bsdf_transparency(kg, &sd);
- if(is_zero(throughput))
- break;
- }
+ if(is_zero(throughput))
+ break;
/* Update Path State */
path_state_next(kg, &state, LABEL_TRANSPARENT);
+#ifdef __VOLUME__
+ }
+ else {
+ /* For volume bounding meshes we pass through without counting transparent
+ * bounces, only sanity check in case self intersection gets us stuck. */
+ state.volume_bounds_bounce++;
+ if (state.volume_bounds_bounce > VOLUME_BOUNDS_MAX) {
+ break;
+ }
+ }
+#endif
+
ray.P = ray_offset(sd.P, -sd.Ng);
ray.t -= sd.ray_length; /* clipping works through transparent */
-
#ifdef __RAY_DIFFERENTIALS__
ray.dP = sd.dP;
ray.dD.dx = -sd.dI.dx;
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index a16c20cbee6..ff7d1307a6c 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -55,6 +55,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg,
#ifdef __VOLUME__
state->volume_bounce = 0;
+ state->volume_bounds_bounce = 0;
if(kernel_data.integrator.use_volumes) {
/* Initialize volume stack with volume we are inside of. */
@@ -75,6 +76,9 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
if(label & LABEL_TRANSPARENT) {
state->flag |= PATH_RAY_TRANSPARENT;
state->transparent_bounce++;
+ if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
+ state->flag |= PATH_RAY_TERMINATE_IMMEDIATE;
+ }
if(!kernel_data.integrator.transparent_shadows)
state->flag |= PATH_RAY_MIS_SKIP;
@@ -86,6 +90,10 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
}
state->bounce++;
+ if(state->bounce >= kernel_data.integrator.max_bounce) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+
state->flag &= ~(PATH_RAY_ALL_VISIBILITY|PATH_RAY_MIS_SKIP);
#ifdef __VOLUME__
@@ -95,6 +103,9 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
state->volume_bounce++;
+ if(state->volume_bounce >= kernel_data.integrator.max_volume_bounce) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
}
else
#endif
@@ -104,10 +115,18 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
state->flag |= PATH_RAY_REFLECT;
state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND;
- if(label & LABEL_DIFFUSE)
+ if(label & LABEL_DIFFUSE) {
state->diffuse_bounce++;
- else
+ if(state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ }
+ else {
state->glossy_bounce++;
+ if(state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ }
}
else {
kernel_assert(label & LABEL_TRANSMIT);
@@ -119,6 +138,9 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
}
state->transmission_bounce++;
+ if(state->transmission_bounce >= kernel_data.integrator.max_transmission_bounce) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
}
/* diffuse/glossy/singular */
@@ -162,13 +184,13 @@ ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg,
ccl_addr_space PathState *state,
const float3 throughput)
{
- if(state->flag & PATH_RAY_TRANSPARENT) {
- /* Transparent rays are treated separately with own max bounces. */
- if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
- return 0.0f;
- }
+ if(state->flag & PATH_RAY_TERMINATE_IMMEDIATE) {
+ /* Ray is to be terminated immediately. */
+ return 0.0f;
+ }
+ else if(state->flag & PATH_RAY_TRANSPARENT) {
/* Do at least one bounce without RR. */
- else if(state->transparent_bounce <= 1) {
+ if(state->transparent_bounce <= 1) {
return 1.0f;
}
#ifdef __SHADOW_TRICKS__
@@ -179,19 +201,8 @@ ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg,
#endif
}
else {
- /* Test max bounces for various ray types. */
- if((state->bounce >= kernel_data.integrator.max_bounce) ||
- (state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) ||
- (state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) ||
-#ifdef __VOLUME__
- (state->volume_bounce >= kernel_data.integrator.max_volume_bounce) ||
-#endif
- (state->transmission_bounce >= kernel_data.integrator.max_transmission_bounce))
- {
- return 0.0f;
- }
/* Do at least one bounce without RR. */
- else if(state->bounce <= 1) {
+ if(state->bounce <= 1) {
return 1.0f;
}
#ifdef __SHADOW_TRICKS__
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 7b566b01b04..bca346d5ee0 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -329,10 +329,12 @@ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg,
}
#ifdef __VOLUME__
else if(sd->flag & SD_HAS_ONLY_VOLUME) {
- /* no surface shader but have a volume shader? act transparent */
-
- /* update path state, count as transparent */
- path_state_next(kg, state, LABEL_TRANSPARENT);
+ /* For volume bounding meshes we pass through without counting transparent
+ * bounces, only sanity check in case self intersection gets us stuck. */
+ state->volume_bounds_bounce++;
+ if (state->volume_bounds_bounce > VOLUME_BOUNDS_MAX) {
+ return false;
+ }
if(state->bounce == 0)
ray->t -= sd->ray_length; /* clipping works through transparent */
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index b6a856baf24..6275d0d6562 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -99,6 +99,23 @@ bool kernel_path_volume_bounce(
/* update path state */
path_state_next(kg, state, label);
+ /* Russian roulette termination of volume ray scattering. */
+ float probability = path_state_continuation_probability(kg, state, *throughput);
+
+ if(probability == 0.0f) {
+ return false;
+ }
+ else if(probability != 1.0f) {
+ /* Use dimension from the previous bounce, has not been used yet. */
+ float terminate = path_state_rng_1D(kg, state, PRNG_TERMINATE - PRNG_BOUNCE_NUM);
+
+ if(terminate >= probability) {
+ return false;
+ }
+
+ *throughput /= probability;
+ }
+
/* setup ray */
ray->P = sd->P;
ray->D = phase_omega_in;
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 5f2f00c5ceb..937a50cba8b 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -114,7 +114,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
sd->I = -ray->D;
- sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+ sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
#ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
@@ -199,7 +199,7 @@ void shader_setup_from_subsurface(
motion_triangle_shader_setup(kg, sd, isect, ray, true);
}
- sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+ sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
# ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
@@ -276,7 +276,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
sd->time = time;
sd->ray_length = t;
- sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag = 0;
if(sd->object != OBJECT_NONE) {
sd->object_flag |= kernel_tex_fetch(__object_flag,
@@ -386,7 +386,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
sd->Ng = -ray->D;
sd->I = -ray->D;
sd->shader = kernel_data.background.surface_shader;
- sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag = 0;
sd->time = ray->time;
sd->ray_length = 0.0f;
@@ -763,6 +763,26 @@ ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd,
return label;
}
+ccl_device float shader_bsdf_average_roughness(ShaderData *sd)
+{
+ float roughness = 0.0f;
+ float sum_weight = 0.0f;
+
+ for(int i = 0; i < sd->num_closure; i++) {
+ ShaderClosure *sc = &sd->closure[i];
+
+ if(CLOSURE_IS_BSDF(sc->type)) {
+ /* sqrt once to undo the squaring from multiplying roughness on the
+ * two axes, and once for the squared roughness convention. */
+ float weight = fabsf(average(sc->weight));
+ roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc)));
+ sum_weight += weight;
+ }
+ }
+
+ return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f;
+}
+
ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
{
for(int i = 0; i < sd->num_closure; i++) {
@@ -875,7 +895,7 @@ ccl_device float3 shader_bsdf_average_normal(KernelGlobals *kg, ShaderData *sd)
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type))
- N += sc->N*average(sc->weight);
+ N += sc->N*fabsf(average(sc->weight));
}
return (is_zero(N))? sd->N : normalize(N);
@@ -892,11 +912,11 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
eval += sc->weight*ao_factor;
- N += bsdf->N*average(sc->weight);
+ N += bsdf->N*fabsf(average(sc->weight));
}
else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) {
eval += sc->weight;
- N += sd->N*average(sc->weight);
+ N += sd->N*fabsf(average(sc->weight));
}
}
@@ -966,10 +986,21 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
/* Surface Evaluation */
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
- ccl_addr_space PathState *state, int path_flag, int max_closure)
+ ccl_addr_space PathState *state, int path_flag)
{
+ /* If path is being terminated, we are tracing a shadow ray or evaluating
+ * emission, then we don't need to store closures. The emission and shadow
+ * shader data also do not have a closure array to save GPU memory. */
+ int max_closures;
+ if(path_flag & (PATH_RAY_TERMINATE|PATH_RAY_SHADOW|PATH_RAY_EMISSION)) {
+ max_closures = 0;
+ }
+ else {
+ max_closures = kernel_data.integrator.max_closures;
+ }
+
sd->num_closure = 0;
- sd->num_closure_left = max_closure;
+ sd->num_closure_left = max_closures;
#ifdef __OSL__
if(kg->osl)
@@ -983,8 +1014,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd,
sizeof(DiffuseBsdf),
make_float3(0.8f, 0.8f, 0.8f));
- bsdf->N = sd->N;
- sd->flag |= bsdf_diffuse_setup(bsdf);
+ if (bsdf != NULL) {
+ bsdf->N = sd->N;
+ sd->flag |= bsdf_diffuse_setup(bsdf);
+ }
#endif
}
@@ -1140,13 +1173,23 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
ShaderData *sd,
ccl_addr_space PathState *state,
ccl_addr_space VolumeStack *stack,
- int path_flag,
- int max_closure)
+ int path_flag)
{
+ /* If path is being terminated, we are tracing a shadow ray or evaluating
+ * emission, then we don't need to store closures. The emission and shadow
+ * shader data also do not have a closure array to save GPU memory. */
+ int max_closures;
+ if(path_flag & (PATH_RAY_TERMINATE|PATH_RAY_SHADOW|PATH_RAY_EMISSION)) {
+ max_closures = 0;
+ }
+ else {
+ max_closures = kernel_data.integrator.max_closures;
+ }
+
/* reset closures once at the start, we will be accumulating the closures
* for all volumes in the stack into a single array of closures */
sd->num_closure = 0;
- sd->num_closure_left = max_closure;
+ sd->num_closure_left = max_closures;
sd->flag = 0;
sd->object_flag = 0;
@@ -1158,7 +1201,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
sd->shader = stack[i].shader;
sd->flag &= ~SD_SHADER_FLAGS;
- sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+ sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag &= ~SD_OBJECT_FLAGS;
if(sd->object != OBJECT_NONE) {
@@ -1231,7 +1274,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
shader = __float_as_int(str.z);
}
#endif
- int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+ int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
return (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index ab364d3037a..8a0da6c3b13 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -86,8 +86,7 @@ ccl_device_forceinline bool shadow_handle_transparent_isect(
shader_eval_surface(kg,
shadow_sd,
state,
- PATH_RAY_SHADOW,
- 0);
+ PATH_RAY_SHADOW);
path_state_modify_bounce(state, false);
*throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h
index 80dda31c61e..e8553d84547 100644
--- a/intern/cycles/kernel/kernel_subsurface.h
+++ b/intern/cycles/kernel/kernel_subsurface.h
@@ -69,44 +69,42 @@ ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd,
}
/* replace closures with a single diffuse bsdf closure after scatter step */
-ccl_device void subsurface_scatter_setup_diffuse_bsdf(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float3 weight, bool hit, float3 N)
+ccl_device void subsurface_scatter_setup_diffuse_bsdf(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float3 weight, float3 N)
{
sd->flag &= ~SD_CLOSURE_FLAGS;
sd->num_closure = 0;
sd->num_closure_left = kernel_data.integrator.max_closures;
- if(hit) {
- Bssrdf *bssrdf = (Bssrdf *)sc;
+ Bssrdf *bssrdf = (Bssrdf *)sc;
#ifdef __PRINCIPLED__
- if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID ||
- bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
- {
- PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight);
-
- if(bsdf) {
- bsdf->N = N;
- bsdf->roughness = bssrdf->roughness;
- sd->flag |= bsdf_principled_diffuse_setup(bsdf);
-
- /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes
- * can recognize it as not being a regular Disney principled diffuse closure */
- bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID;
- }
+ if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID ||
+ bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
+ {
+ PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight);
+
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->roughness = bssrdf->roughness;
+ sd->flag |= bsdf_principled_diffuse_setup(bsdf);
+
+ /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes
+ * can recognize it as not being a regular Disney principled diffuse closure */
+ bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID;
}
- else if(CLOSURE_IS_BSDF_BSSRDF(bssrdf->type) ||
- CLOSURE_IS_BSSRDF(bssrdf->type))
+ }
+ else if(CLOSURE_IS_BSDF_BSSRDF(bssrdf->type) ||
+ CLOSURE_IS_BSSRDF(bssrdf->type))
#endif /* __PRINCIPLED__ */
- {
- DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
+ {
+ DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
- if(bsdf) {
- bsdf->N = N;
- sd->flag |= bsdf_diffuse_setup(bsdf);
+ if(bsdf) {
+ bsdf->N = N;
+ sd->flag |= bsdf_diffuse_setup(bsdf);
- /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
- * can recognize it as not being a regular diffuse closure */
- bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
- }
+ /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
+ * can recognize it as not being a regular diffuse closure */
+ bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
}
}
}
@@ -148,7 +146,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg,
if(bump || texture_blur > 0.0f) {
/* average color and normal at incoming point */
- shader_eval_surface(kg, sd, state, state->flag, kernel_data.integrator.max_closures);
+ shader_eval_surface(kg, sd, state, state->flag);
float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL);
/* we simply divide out the average color and multiply with the average
@@ -334,104 +332,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup(
subsurface_color_bump_blur(kg, sd, state, &weight, &N);
/* Setup diffuse BSDF. */
- subsurface_scatter_setup_diffuse_bsdf(kg, sd, sc, weight, true, N);
-}
-
-/* subsurface scattering step, from a point on the surface to another nearby point on the same object */
-ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state,
- const ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all)
-{
- float3 eval = make_float3(0.0f, 0.0f, 0.0f);
-
- /* pick random axis in local frame and point on disk */
- float3 disk_N, disk_T, disk_B;
- float pick_pdf_N, pick_pdf_T, pick_pdf_B;
-
- disk_N = sd->Ng;
- make_orthonormals(disk_N, &disk_T, &disk_B);
-
- if(disk_v < 0.5f) {
- pick_pdf_N = 0.5f;
- pick_pdf_T = 0.25f;
- pick_pdf_B = 0.25f;
- disk_v *= 2.0f;
- }
- else if(disk_v < 0.75f) {
- float3 tmp = disk_N;
- disk_N = disk_T;
- disk_T = tmp;
- pick_pdf_N = 0.25f;
- pick_pdf_T = 0.5f;
- pick_pdf_B = 0.25f;
- disk_v = (disk_v - 0.5f)*4.0f;
- }
- else {
- float3 tmp = disk_N;
- disk_N = disk_B;
- disk_B = tmp;
- pick_pdf_N = 0.25f;
- pick_pdf_T = 0.25f;
- pick_pdf_B = 0.5f;
- disk_v = (disk_v - 0.75f)*4.0f;
- }
-
- /* sample point on disk */
- float phi = M_2PI_F * disk_v;
- float disk_height, disk_r;
-
- bssrdf_sample(sc, disk_u, &disk_r, &disk_height);
-
- float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B;
-
- /* create ray */
- Ray ray;
- ray.P = sd->P + disk_N*disk_height + disk_P;
- ray.D = -disk_N;
- ray.t = 2.0f*disk_height;
- ray.dP = sd->dP;
- ray.dD = differential3_zero();
- ray.time = sd->time;
-
- /* intersect with the same object. if multiple intersections are
- * found it will randomly pick one of them */
- LocalIntersection ss_isect;
- scene_intersect_local(kg, ray, &ss_isect, sd->object, lcg_state, 1);
-
- /* evaluate bssrdf */
- if(ss_isect.num_hits > 0) {
- float3 origP = sd->P;
-
- /* Workaround for AMD GPU OpenCL compiler. Most probably cache bypass issue. */
-#if defined(__SPLIT_KERNEL__) && defined(__KERNEL_OPENCL_AMD__) && defined(__KERNEL_GPU__)
- kernel_split_params.dummy_sd_flag = sd->flag;
-#endif
- /* setup new shading point */
- shader_setup_from_subsurface(kg, sd, &ss_isect.hits[0], &ray);
-
- /* Probability densities for local frame axes. */
- float pdf_N = pick_pdf_N * fabsf(dot(disk_N, sd->Ng));
- float pdf_T = pick_pdf_T * fabsf(dot(disk_T, sd->Ng));
- float pdf_B = pick_pdf_B * fabsf(dot(disk_B, sd->Ng));
-
- /* Multiple importance sample between 3 axes, power heuristic
- * found to be slightly better than balance heuristic. pdf_N
- * in the MIS weight and denominator cancelled out. */
- float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
- w *= ss_isect.num_hits;
-
- /* Real distance to sampled point. */
- float r = len(sd->P - origP);
-
- /* Evaluate profiles. */
- eval = subsurface_scatter_eval(sd, sc, disk_r, r, all) * w;
- }
-
- /* optionally blur colors and bump mapping */
- float3 N = sd->N;
- subsurface_color_bump_blur(kg, sd, state, &eval, &N);
-
- /* setup diffuse bsdf */
- subsurface_scatter_setup_diffuse_bsdf(kg, sd, sc, eval, (ss_isect.num_hits > 0), N);
+ subsurface_scatter_setup_diffuse_bsdf(kg, sd, sc, weight, N);
}
/* Random walk subsurface scattering.
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 74b659557e5..9047b93a0b2 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -31,8 +31,13 @@ KERNEL_TEX(uint, __object_node)
KERNEL_TEX(float2, __prim_time)
/* objects */
-KERNEL_TEX(float4, __objects)
-KERNEL_TEX(float4, __objects_vector)
+KERNEL_TEX(KernelObject, __objects)
+KERNEL_TEX(Transform, __object_motion_pass)
+KERNEL_TEX(DecomposedTransform, __object_motion)
+KERNEL_TEX(uint, __object_flag)
+
+/* cameras */
+KERNEL_TEX(DecomposedTransform, __camera_motion)
/* triangles */
KERNEL_TEX(uint, __tri_shader)
@@ -55,18 +60,17 @@ KERNEL_TEX(float4, __attributes_float3)
KERNEL_TEX(uchar4, __attributes_uchar4)
/* lights */
-KERNEL_TEX(float4, __light_distribution)
-KERNEL_TEX(float4, __light_data)
+KERNEL_TEX(KernelLightDistribution, __light_distribution)
+KERNEL_TEX(KernelLight, __lights)
KERNEL_TEX(float2, __light_background_marginal_cdf)
KERNEL_TEX(float2, __light_background_conditional_cdf)
/* particles */
-KERNEL_TEX(float4, __particles)
+KERNEL_TEX(KernelParticle, __particles)
/* shaders */
KERNEL_TEX(uint4, __svm_nodes)
-KERNEL_TEX(uint, __shader_flag)
-KERNEL_TEX(uint, __object_flag)
+KERNEL_TEX(KernelShader, __shaders)
/* lookup tables */
KERNEL_TEX(float, __lookup_table)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index aeb63b4a65e..11657003259 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -35,20 +35,18 @@
CCL_NAMESPACE_BEGIN
/* Constants */
-#define OBJECT_SIZE 16
-#define OBJECT_VECTOR_SIZE 6
-#define LIGHT_SIZE 11
-#define FILTER_TABLE_SIZE 1024
-#define RAMP_TABLE_SIZE 256
-#define SHUTTER_TABLE_SIZE 256
-#define PARTICLE_SIZE 5
-#define SHADER_SIZE 5
+#define OBJECT_MOTION_PASS_SIZE 2
+#define FILTER_TABLE_SIZE 1024
+#define RAMP_TABLE_SIZE 256
+#define SHUTTER_TABLE_SIZE 256
#define BSSRDF_MIN_RADIUS 1e-8f
#define BSSRDF_MAX_HITS 4
#define BSSRDF_MAX_BOUNCES 256
#define LOCAL_MAX_HITS 4
+#define VOLUME_BOUNDS_MAX 1024
+
#define BECKMANN_TABLE_SIZE 256
#define SHADER_NONE (~0)
@@ -265,6 +263,7 @@ typedef enum ShaderEvalType {
/* data passes */
SHADER_EVAL_NORMAL,
SHADER_EVAL_UV,
+ SHADER_EVAL_ROUGHNESS,
SHADER_EVAL_DIFFUSE_COLOR,
SHADER_EVAL_GLOSSY_COLOR,
SHADER_EVAL_TRANSMISSION_COLOR,
@@ -347,12 +346,31 @@ enum PathRayFlag {
PATH_RAY_ALL_VISIBILITY = ((1 << 14)-1),
- PATH_RAY_MIS_SKIP = (1 << 15),
- PATH_RAY_DIFFUSE_ANCESTOR = (1 << 16),
- PATH_RAY_SINGLE_PASS_DONE = (1 << 17),
- PATH_RAY_SHADOW_CATCHER = (1 << 18),
- PATH_RAY_STORE_SHADOW_INFO = (1 << 19),
- PATH_RAY_TRANSPARENT_BACKGROUND = (1 << 20),
+ /* Don't apply multiple importance sampling weights to emission from
+ * lamp or surface hits, because they were not direct light sampled. */
+ PATH_RAY_MIS_SKIP = (1 << 14),
+ /* Diffuse bounce earlier in the path, skip SSS to improve performance
+ * and avoid branching twice with disk sampling SSS. */
+ PATH_RAY_DIFFUSE_ANCESTOR = (1 << 15),
+ /* Single pass has been written. */
+ PATH_RAY_SINGLE_PASS_DONE = (1 << 16),
+ /* Ray is behind a shadow catcher .*/
+ PATH_RAY_SHADOW_CATCHER = (1 << 17),
+ /* Store shadow data for shadow catcher or denoising. */
+ PATH_RAY_STORE_SHADOW_INFO = (1 << 18),
+ /* Zero background alpha, for camera or transparent glass rays. */
+ PATH_RAY_TRANSPARENT_BACKGROUND = (1 << 19),
+ /* Terminate ray immediately at next bounce. */
+ PATH_RAY_TERMINATE_IMMEDIATE = (1 << 20),
+ /* Ray is to be terminated, but continue with transparent bounces and
+ * emission as long as we encounter them. This is required to make the
+ * MIS between direct and indirect light rays match, as shadow rays go
+ * through transparent surfaces to reach emisison too. */
+ PATH_RAY_TERMINATE_AFTER_TRANSPARENT = (1 << 21),
+ /* Ray is to be terminated. */
+ PATH_RAY_TERMINATE = (PATH_RAY_TERMINATE_IMMEDIATE|PATH_RAY_TERMINATE_AFTER_TRANSPARENT),
+ /* Path and shader is being evaluated for direct lighting emission. */
+ PATH_RAY_EMISSION = (1 << 22)
};
/* Closure Label */
@@ -779,6 +797,7 @@ typedef enum AttributeStandard {
ATTR_STD_VOLUME_COLOR,
ATTR_STD_VOLUME_FLAME,
ATTR_STD_VOLUME_HEAT,
+ ATTR_STD_VOLUME_TEMPERATURE,
ATTR_STD_VOLUME_VELOCITY,
ATTR_STD_POINTINESS,
ATTR_STD_NUM,
@@ -903,21 +922,24 @@ enum ShaderDataFlag {
SD_HAS_BUMP = (1 << 25),
/* Has true displacement. */
SD_HAS_DISPLACEMENT = (1 << 26),
- /* Has constant emission (value stored in __shader_flag) */
+ /* Has constant emission (value stored in __shaders) */
SD_HAS_CONSTANT_EMISSION = (1 << 27),
+ /* Needs to access attributes */
+ SD_NEED_ATTRIBUTES = (1 << 28),
SD_SHADER_FLAGS = (SD_USE_MIS |
SD_HAS_TRANSPARENT_SHADOW |
SD_HAS_VOLUME |
SD_HAS_ONLY_VOLUME |
- SD_HETEROGENEOUS_VOLUME|
+ SD_HETEROGENEOUS_VOLUME |
SD_HAS_BSSRDF_BUMP |
SD_VOLUME_EQUIANGULAR |
SD_VOLUME_MIS |
SD_VOLUME_CUBIC |
SD_HAS_BUMP |
SD_HAS_DISPLACEMENT |
- SD_HAS_CONSTANT_EMISSION)
+ SD_HAS_CONSTANT_EMISSION |
+ SD_NEED_ATTRIBUTES)
};
/* Object flags. */
@@ -938,6 +960,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6),
/* object is used to catch shadows */
SD_OBJECT_SHADOW_CATCHER = (1 << 7),
+ /* object has volume attributes */
+ SD_OBJECT_HAS_VOLUME_ATTRIBUTES = (1 << 8),
SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK |
SD_OBJECT_MOTION |
@@ -945,7 +969,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_NEGATIVE_SCALE_APPLIED |
SD_OBJECT_HAS_VOLUME |
SD_OBJECT_INTERSECTS_VOLUME |
- SD_OBJECT_SHADOW_CATCHER)
+ SD_OBJECT_SHADOW_CATCHER |
+ SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
};
typedef ccl_addr_space struct ShaderData {
@@ -1081,6 +1106,7 @@ typedef struct PathState {
/* volume rendering */
#ifdef __VOLUME__
int volume_bounce;
+ int volume_bounds_bounce;
uint rng_congruential;
VolumeStack volume_stack[VOLUME_STACK_SIZE];
#endif
@@ -1134,7 +1160,7 @@ typedef struct KernelCamera {
/* matrices */
Transform cameratoworld;
- Transform rastertocamera;
+ ProjectionTransform rastertocamera;
/* differentials */
float4 dx;
@@ -1148,7 +1174,7 @@ typedef struct KernelCamera {
/* motion blur */
float shuttertime;
- int have_motion, have_perspective_motion;
+ int num_motion_steps, have_perspective_motion;
/* clipping */
float nearclip;
@@ -1168,22 +1194,22 @@ typedef struct KernelCamera {
int is_inside_volume;
/* more matrices */
- Transform screentoworld;
- Transform rastertoworld;
- /* work around cuda sm 2.0 crash, this seems to
- * cross some limit in combination with motion
- * Transform ndctoworld; */
- Transform worldtoscreen;
- Transform worldtoraster;
- Transform worldtondc;
+ ProjectionTransform screentoworld;
+ ProjectionTransform rastertoworld;
+ ProjectionTransform ndctoworld;
+ ProjectionTransform worldtoscreen;
+ ProjectionTransform worldtoraster;
+ ProjectionTransform worldtondc;
Transform worldtocamera;
- MotionTransform motion;
+ /* Stores changes in the projeciton matrix. Use for camera zoom motion
+ * blur and motion pass output for perspective camera. */
+ ProjectionTransform perspective_pre;
+ ProjectionTransform perspective_post;
- /* Denotes changes in the projective matrix, namely in rastertocamera.
- * Used for camera zoom motion blur,
- */
- PerspectiveMotionTransform perspective_motion;
+ /* Transforms for motion pass. */
+ Transform motion_pass_pre;
+ Transform motion_pass_post;
int shutter_table_offset;
@@ -1405,6 +1431,110 @@ typedef struct KernelData {
} KernelData;
static_assert_align(KernelData, 16);
+/* Kernel data structures. */
+
+typedef struct KernelObject {
+ Transform tfm;
+ Transform itfm;
+
+ float surface_area;
+ float pass_id;
+ float random_number;
+ int particle_index;
+
+ float dupli_generated[3];
+ float dupli_uv[2];
+
+ int numkeys;
+ int numsteps;
+ int numverts;
+
+ uint patch_map_offset;
+ uint attribute_map_offset;
+ uint motion_offset;
+ uint pad;
+} KernelObject;;
+static_assert_align(KernelObject, 16);
+
+typedef struct KernelSpotLight {
+ float radius;
+ float invarea;
+ float spot_angle;
+ float spot_smooth;
+ float dir[3];
+} KernelSpotLight;
+
+/* PointLight is SpotLight with only radius and invarea being used. */
+
+typedef struct KernelAreaLight {
+ float axisu[3];
+ float invarea;
+ float axisv[3];
+ float dir[3];
+} KernelAreaLight;
+
+typedef struct KernelDistantLight {
+ float radius;
+ float cosangle;
+ float invarea;
+} KernelDistantLight;
+
+typedef struct KernelLight {
+ int type;
+ float co[3];
+ int shader_id;
+ int samples;
+ float max_bounces;
+ float random;
+ Transform tfm;
+ Transform itfm;
+ union {
+ KernelSpotLight spot;
+ KernelAreaLight area;
+ KernelDistantLight distant;
+ };
+} KernelLight;
+static_assert_align(KernelLight, 16);
+
+typedef struct KernelLightDistribution {
+ float totarea;
+ int prim;
+ union {
+ struct {
+ int shader_flag;
+ int object_id;
+ } mesh_light;
+ struct {
+ float pad;
+ float size;
+ } lamp;
+ };
+} KernelLightDistribution;
+static_assert_align(KernelLightDistribution, 16);
+
+typedef struct KernelParticle {
+ int index;
+ float age;
+ float lifetime;
+ float size;
+ float4 rotation;
+ /* Only xyz are used of the following. float4 instead of float3 are used
+ * to ensure consistent padding/alignment across devices. */
+ float4 location;
+ float4 velocity;
+ float4 angular_velocity;
+} KernelParticle;
+static_assert_align(KernelParticle, 16);
+
+typedef struct KernelShader {
+ float constant_emission[3];
+ float pad1;
+ int flags;
+ int pass_id;
+ int pad2, pad3;
+} KernelShader;
+static_assert_align(KernelShader, 16);
+
/* Declarations required for split kernel */
/* Macro for queues */
@@ -1471,8 +1601,10 @@ enum RayState {
RAY_ACTIVE,
/* Denotes ray has completed processing all samples and is inactive. */
RAY_INACTIVE,
- /* Denoted ray has exited path-iteration and needs to update output buffer. */
+ /* Denotes ray has exited path-iteration and needs to update output buffer. */
RAY_UPDATE_BUFFER,
+ /* Denotes ray needs to skip most surface shader work. */
+ RAY_HAS_ONLY_VOLUME,
/* Donotes ray has hit background */
RAY_HIT_BACKGROUND,
/* Denotes ray has to be regenerated */
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 7b67a37adc5..88360e5f1ae 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -45,7 +45,7 @@ ccl_device_inline bool volume_shader_extinction_sample(KernelGlobals *kg,
float3 *extinction)
{
sd->P = P;
- shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW, 0);
+ shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW);
if(sd->flag & SD_EXTINCTION) {
*extinction = sd->closure_transparent_extinction;
@@ -64,7 +64,7 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
VolumeShaderCoefficients *coeff)
{
sd->P = P;
- shader_eval_volume(kg, sd, state, state->volume_stack, state->flag, kernel_data.integrator.max_closures);
+ shader_eval_volume(kg, sd, state, state->volume_stack, state->flag);
if(!(sd->flag & (SD_EXTINCTION|SD_SCATTER|SD_EMISSION)))
return false;
@@ -76,18 +76,11 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
make_float3(0.0f, 0.0f, 0.0f);
if(sd->flag & SD_SCATTER) {
- if(state->bounce < kernel_data.integrator.max_bounce &&
- state->volume_bounce < kernel_data.integrator.max_volume_bounce) {
- for(int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i < sd->num_closure; i++) {
+ const ShaderClosure *sc = &sd->closure[i];
- if(CLOSURE_IS_VOLUME(sc->type))
- coeff->sigma_s += sc->weight;
- }
- }
- else {
- /* When at the max number of bounces, clear scattering. */
- sd->flag &= ~SD_SCATTER;
+ if(CLOSURE_IS_VOLUME(sc->type))
+ coeff->sigma_s += sc->weight;
}
}
@@ -111,10 +104,23 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel)
ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space VolumeStack *stack)
{
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
- int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
+ int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
- if(shader_flag & SD_HETEROGENEOUS_VOLUME)
+ if(shader_flag & SD_HETEROGENEOUS_VOLUME) {
return true;
+ }
+ else if(shader_flag & SD_NEED_ATTRIBUTES) {
+ /* We want to render world or objects without any volume grids
+ * as homogenous, but can only verify this at runtime since other
+ * heterogenous volume objects may be using the same shader. */
+ int object = stack[i].object;
+ if(object != OBJECT_NONE) {
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ if(object_flag & SD_OBJECT_HAS_VOLUME_ATTRIBUTES) {
+ return true;
+ }
+ }
+ }
}
return false;
@@ -128,7 +134,7 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
int method = -1;
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
- int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
+ int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
if(shader_flag & SD_VOLUME_MIS) {
return SD_VOLUME_MIS;
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index d0c357580fd..ee16ddaf0fd 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -705,7 +705,7 @@ public:
void setup(ShaderData *sd, int path_flag, float3 weight)
{
- bsdf_transparent_setup(sd, weight);
+ bsdf_transparent_setup(sd, weight, path_flag);
}
};
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index ae4c521659c..0c5e5e30e47 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -62,11 +62,17 @@ CCL_NAMESPACE_BEGIN
/* RenderServices implementation */
-#define COPY_MATRIX44(m1, m2) { \
- CHECK_TYPE(m1, OSL::Matrix44*); \
- CHECK_TYPE(m2, Transform*); \
- memcpy(m1, m2, sizeof(*m2)); \
-} (void)0
+static void copy_matrix(OSL::Matrix44& m, const Transform& tfm)
+{
+ ProjectionTransform t = projection_transpose(ProjectionTransform(tfm));
+ memcpy(&m, &t, sizeof(m));
+}
+
+static void copy_matrix(OSL::Matrix44& m, const ProjectionTransform& tfm)
+{
+ ProjectionTransform t = projection_transpose(tfm);
+ memcpy(&m, &t, sizeof(m));
+}
/* static ustrings */
ustring OSLRenderServices::u_distance("distance");
@@ -167,14 +173,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
#else
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
#endif
- tfm = transform_transpose(tfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, tfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
- Transform tfm = transform_transpose(sd->ob_tfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, sd->ob_tfm);
return true;
}
@@ -203,14 +207,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
#else
Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
#endif
- itfm = transform_transpose(itfm);
- COPY_MATRIX44(&result, &itfm);
+ copy_matrix(result, itfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
- Transform tfm = transform_transpose(sd->ob_itfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, sd->ob_itfm);
return true;
}
@@ -224,23 +226,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
KernelGlobals *kg = kernel_globals;
if(from == u_ndc) {
- Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.ndctoworld);
return true;
}
else if(from == u_raster) {
- Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.rastertoworld);
return true;
}
else if(from == u_screen) {
- Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.screentoworld);
return true;
}
else if(from == u_camera) {
- Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.cameratoworld);
return true;
}
else if(from == u_world) {
@@ -256,23 +254,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
KernelGlobals *kg = kernel_globals;
if(to == u_ndc) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtondc);
return true;
}
else if(to == u_raster) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtoraster);
return true;
}
else if(to == u_screen) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtoscreen);
return true;
}
else if(to == u_camera) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtocamera);
return true;
}
else if(to == u_world) {
@@ -298,14 +292,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
KernelGlobals *kg = sd->osl_globals;
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
#endif
- tfm = transform_transpose(tfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, tfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
- Transform tfm = transform_transpose(sd->ob_tfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, sd->ob_tfm);
return true;
}
@@ -329,14 +321,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
KernelGlobals *kg = sd->osl_globals;
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
#endif
- tfm = transform_transpose(tfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, tfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
- Transform tfm = transform_transpose(sd->ob_itfm);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, sd->ob_itfm);
return true;
}
@@ -350,23 +340,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
KernelGlobals *kg = kernel_globals;
if(from == u_ndc) {
- Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.ndctoworld);
return true;
}
else if(from == u_raster) {
- Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.rastertoworld);
return true;
}
else if(from == u_screen) {
- Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.screentoworld);
return true;
}
else if(from == u_camera) {
- Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.cameratoworld);
return true;
}
@@ -378,23 +364,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
KernelGlobals *kg = kernel_globals;
if(to == u_ndc) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtondc);
return true;
}
else if(to == u_raster) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtoraster);
return true;
}
else if(to == u_screen) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtoscreen);
return true;
}
else if(to == u_camera) {
- Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
- COPY_MATRIX44(&result, &tfm);
+ copy_matrix(result, kernel_data.cam.worldtocamera);
return true;
}
@@ -570,8 +552,7 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
{
if(type == TypeDesc::TypeMatrix) {
- Transform transpose = transform_transpose(tfm);
- memcpy(val, &transpose, sizeof(Transform));
+ copy_matrix(*(OSL::Matrix44*)val, tfm);
return true;
}
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 19b7769200e..6ec651a96d8 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRC_OSL
node_hair_info.osl
node_scatter_volume.osl
node_absorption_volume.osl
+ node_principled_volume.osl
node_holdout.osl
node_hsv.osl
node_image_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
index bef6d7e8809..21e28ece65d 100644
--- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
@@ -33,27 +33,28 @@ shader node_anisotropic_bsdf(
T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
/* compute roughness */
- float RoughnessU, RoughnessV;
+ float roughness = Roughness * Roughness;
+ float roughness_u, roughness_v;
float aniso = clamp(Anisotropy, -0.99, 0.99);
if (aniso < 0.0) {
- RoughnessU = Roughness / (1.0 + aniso);
- RoughnessV = Roughness * (1.0 + aniso);
+ roughness_u = roughness / (1.0 + aniso);
+ roughness_v = roughness * (1.0 + aniso);
}
else {
- RoughnessU = Roughness * (1.0 - aniso);
- RoughnessV = Roughness / (1.0 - aniso);
+ roughness_u = roughness * (1.0 - aniso);
+ roughness_v = roughness / (1.0 - aniso);
}
if (distribution == "sharp")
BSDF = Color * reflection(Normal);
else if (distribution == "beckmann")
- BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV);
+ BSDF = Color * microfacet_beckmann_aniso(Normal, T, roughness_u, roughness_v);
else if (distribution == "GGX")
- BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV);
+ BSDF = Color * microfacet_ggx_aniso(Normal, T, roughness_u, roughness_v);
else if (distribution == "Multiscatter GGX")
- BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color);
+ BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color);
else
- BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV);
+ BSDF = Color * ashikhmin_shirley(Normal, T, roughness_u, roughness_v);
}
diff --git a/intern/cycles/kernel/shaders/node_bevel.osl b/intern/cycles/kernel/shaders/node_bevel.osl
index a5b185b6b4c..9c4ca15be17 100644
--- a/intern/cycles/kernel/shaders/node_bevel.osl
+++ b/intern/cycles/kernel/shaders/node_bevel.osl
@@ -23,9 +23,9 @@ shader node_bevel(
output normal NormalOut = N)
{
/* Abuse texture call with special @bevel token. */
- NormalOut = (normal)(color)texture("@bevel", samples, Radius);
+ vector bevel_N = (normal)(color)texture("@bevel", samples, Radius);
/* Preserve input normal. */
- NormalOut = normalize(N + (NormalOut - NormalIn));
+ NormalOut = normalize(NormalIn + (bevel_N - N));
}
diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
index a9723a8300a..2e713861c58 100644
--- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
@@ -29,16 +29,17 @@ shader node_glass_bsdf(
float eta = backfacing() ? 1.0 / f : f;
float cosi = dot(I, Normal);
float Fr = fresnel_dielectric_cos(cosi, eta);
+ float roughness = Roughness * Roughness;
if (distribution == "sharp")
BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta));
else if (distribution == "beckmann")
- BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) +
- (1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta));
+ BSDF = Color * (Fr * microfacet_beckmann(Normal, roughness) +
+ (1.0 - Fr) * microfacet_beckmann_refraction(Normal, roughness, eta));
else if (distribution == "Multiscatter GGX")
- BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color);
+ BSDF = Color * microfacet_multi_ggx_glass(Normal, roughness, eta, Color);
else if (distribution == "GGX")
- BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) +
- (1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta));
+ BSDF = Color * (Fr * microfacet_ggx(Normal, roughness) +
+ (1.0 - Fr) * microfacet_ggx_refraction(Normal, roughness, eta));
}
diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
index f4ea7e7dc6a..7415211b56d 100644
--- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
@@ -24,16 +24,18 @@ shader node_glossy_bsdf(
normal Normal = N,
output closure color BSDF = 0)
{
+ float roughness = Roughness * Roughness;
+
if (distribution == "sharp")
BSDF = Color * reflection(Normal);
else if (distribution == "beckmann")
- BSDF = Color * microfacet_beckmann(Normal, Roughness);
+ BSDF = Color * microfacet_beckmann(Normal, roughness);
else if (distribution == "GGX")
- BSDF = Color * microfacet_ggx(Normal, Roughness);
+ BSDF = Color * microfacet_ggx(Normal, roughness);
else if (distribution == "Multiscatter GGX")
- BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color);
+ BSDF = Color * microfacet_multi_ggx(Normal, roughness, Color);
else
- BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness);
+ BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), roughness, roughness);
}
diff --git a/intern/cycles/kernel/shaders/node_principled_volume.osl b/intern/cycles/kernel/shaders/node_principled_volume.osl
new file mode 100644
index 00000000000..ea8d6ab12c5
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_principled_volume.osl
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_principled_volume(
+ color Color = color(0.5, 0.5, 0.5),
+ float Density = 1.0,
+ float Anisotropy = 0.0,
+ color AbsorptionColor = color(0.0, 0.0, 0.0),
+ float EmissionStrength = 0.0,
+ color EmissionColor = color(1.0, 1.0, 1.0),
+ float BlackbodyIntensity = 0.0,
+ color BlackbodyTint = color(1.0, 1.0, 1.0),
+ float Temperature = 1500.0,
+ string DensityAttribute = "geom:density",
+ string ColorAttribute = "geom:color",
+ string TemperatureAttribute = "geom:temperature",
+ output closure color Volume = 0)
+{
+ /* Compute density. */
+ float primitive_density = 1.0;
+ float density = max(Density, 0.0);
+
+ if(density > 1e-5) {
+ if(getattribute(DensityAttribute, primitive_density)) {
+ density = max(density * primitive_density, 0.0);
+ }
+ }
+
+ if(density > 1e-5) {
+ /* Compute scattering color. */
+ color scatter_color = Color;
+ color primitive_color;
+ if(getattribute(ColorAttribute, primitive_color)) {
+ scatter_color *= primitive_color;
+ }
+
+ /* Add scattering and absorption closures. */
+ color scatter_coeff = scatter_color;
+ color absorption_color = sqrt(max(AbsorptionColor, 0.0));
+ color absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color, 0.0);
+ Volume = scatter_coeff * density * henyey_greenstein(Anisotropy) +
+ absorption_coeff * density * absorption();
+ }
+
+ /* Compute emission. */
+ float emission_strength = max(EmissionStrength, 0.0);
+ float blackbody_intensity = BlackbodyIntensity;
+
+ if(emission_strength > 1e-5) {
+ Volume += emission_strength * EmissionColor * emission();
+ }
+
+ if(blackbody_intensity > 1e-3) {
+ float T = Temperature;
+
+ /* Add temperature from attribute if available. */
+ float temperature;
+ if(getattribute(TemperatureAttribute, temperature)) {
+ T *= max(temperature, 0.0);
+ }
+
+ T = max(T, 0.0);
+
+ /* Stefan-Boltzman law. */
+ float T4 = (T * T) * (T * T);
+ float sigma = 5.670373e-8 * 1e-6 / M_PI;
+ float intensity = sigma * mix(1.0, T4, blackbody_intensity);
+
+ if(intensity > 1e-5) {
+ color bb = blackbody(T);
+ float l = luminance(bb);
+
+ if(l != 0.0) {
+ bb *= BlackbodyTint * intensity / l;
+ Volume += bb * emission();
+ }
+ }
+ }
+}
+
diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
index 828becf1818..eaab7282243 100644
--- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
@@ -26,12 +26,13 @@ shader node_refraction_bsdf(
{
float f = max(IOR, 1e-5);
float eta = backfacing() ? 1.0 / f : f;
+ float roughness = Roughness * Roughness;
if (distribution == "sharp")
BSDF = Color * refraction(Normal, eta);
else if (distribution == "beckmann")
- BSDF = Color * microfacet_beckmann_refraction(Normal, Roughness, eta);
+ BSDF = Color * microfacet_beckmann_refraction(Normal, roughness, eta);
else if (distribution == "GGX")
- BSDF = Color * microfacet_ggx_refraction(Normal, Roughness, eta);
+ BSDF = Color * microfacet_ggx_refraction(Normal, roughness, eta);
}
diff --git a/intern/cycles/kernel/split/kernel_indirect_subsurface.h b/intern/cycles/kernel/split/kernel_indirect_subsurface.h
index e9fe5552e8c..236c94e983c 100644
--- a/intern/cycles/kernel/split/kernel_indirect_subsurface.h
+++ b/intern/cycles/kernel/split/kernel_indirect_subsurface.h
@@ -38,7 +38,6 @@ ccl_device void kernel_indirect_subsurface(KernelGlobals *kg)
1);
#ifdef __SUBSURFACE__
-
if(ray_index == QUEUE_EMPTY_SLOT) {
return;
}
@@ -49,31 +48,23 @@ ccl_device void kernel_indirect_subsurface(KernelGlobals *kg)
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
-#ifdef __BRANCHED_PATH__
- if(!kernel_data.integrator.branched) {
-#endif
- if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) {
- ccl_addr_space SubsurfaceIndirectRays *ss_indirect = &kernel_split_state.ss_rays[ray_index];
+ if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) {
+ ccl_addr_space SubsurfaceIndirectRays *ss_indirect = &kernel_split_state.ss_rays[ray_index];
- /* Trace indirect subsurface rays by restarting the loop. this uses less
- * stack memory than invoking kernel_path_indirect.
- */
- if(ss_indirect->num_rays) {
- kernel_path_subsurface_setup_indirect(kg,
- ss_indirect,
- state,
- ray,
- L,
- throughput);
- ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED);
- }
+ /* Trace indirect subsurface rays by restarting the loop. this uses less
+ * stack memory than invoking kernel_path_indirect.
+ */
+ if(ss_indirect->num_rays) {
+ kernel_path_subsurface_setup_indirect(kg,
+ ss_indirect,
+ state,
+ ray,
+ L,
+ throughput);
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED);
}
-#ifdef __BRANCHED_PATH__
}
-#endif
-
#endif /* __SUBSURFACE__ */
-
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
index 81024f0cf99..8092419e796 100644
--- a/intern/cycles/kernel/split/kernel_next_iteration_setup.h
+++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
@@ -53,39 +53,52 @@ ccl_device_inline void kernel_split_branched_indirect_light_init(KernelGlobals *
ADD_RAY_FLAG(kernel_split_state.ray_state, ray_index, RAY_BRANCHED_LIGHT_INDIRECT);
}
-ccl_device void kernel_split_branched_indirect_light_end(KernelGlobals *kg, int ray_index)
+ccl_device void kernel_split_branched_transparent_bounce(KernelGlobals *kg, int ray_index)
{
- kernel_split_branched_path_indirect_loop_end(kg, ray_index);
-
ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
ShaderData *sd = kernel_split_sd(sd, ray_index);
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
- /* continue in case of transparency */
- *throughput *= shader_bsdf_transparency(kg, sd);
+# ifdef __VOLUME__
+ if(!(sd->flag & SD_HAS_ONLY_VOLUME)) {
+# endif
+ /* continue in case of transparency */
+ *throughput *= shader_bsdf_transparency(kg, sd);
+
+ if(is_zero(*throughput)) {
+ kernel_split_path_end(kg, ray_index);
+ return;
+ }
- if(is_zero(*throughput)) {
- kernel_split_path_end(kg, ray_index);
- }
- else {
/* Update Path State */
path_state_next(kg, state, LABEL_TRANSPARENT);
+# ifdef __VOLUME__
+ }
+ else {
+ /* For volume bounding meshes we pass through without counting transparent
+ * bounces, only sanity check in case self intersection gets us stuck. */
+ state->volume_bounds_bounce++;
+ if (state->volume_bounds_bounce > VOLUME_BOUNDS_MAX) {
+ kernel_split_path_end(kg, ray_index);
+ return;
+ }
+ }
+# endif
- ray->P = ray_offset(sd->P, -sd->Ng);
- ray->t -= sd->ray_length; /* clipping works through transparent */
+ ray->P = ray_offset(sd->P, -sd->Ng);
+ ray->t -= sd->ray_length; /* clipping works through transparent */
# ifdef __RAY_DIFFERENTIALS__
- ray->dP = sd->dP;
- ray->dD.dx = -sd->dI.dx;
- ray->dD.dy = -sd->dI.dy;
+ ray->dP = sd->dP;
+ ray->dD.dx = -sd->dI.dx;
+ ray->dD.dy = -sd->dI.dy;
# endif /* __RAY_DIFFERENTIALS__ */
# ifdef __VOLUME__
- /* enter/exit volume */
- kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);
+ /* enter/exit volume */
+ kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);
# endif /* __VOLUME__ */
- }
}
#endif /* __BRANCHED_PATH__ */
@@ -121,6 +134,13 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg,
ccl_global char *ray_state = kernel_split_state.ray_state;
+# ifdef __VOLUME__
+ /* Reactivate only volume rays here, most surface work was skipped. */
+ if(IS_STATE(ray_state, ray_index, RAY_HAS_ONLY_VOLUME)) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_ACTIVE);
+ }
+# endif
+
bool active = IS_STATE(ray_state, ray_index, RAY_ACTIVE);
if(active) {
ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
@@ -138,6 +158,9 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg,
}
#ifdef __BRANCHED_PATH__
}
+ else if(sd->flag & SD_HAS_ONLY_VOLUME) {
+ kernel_split_branched_transparent_bounce(kg, ray_index);
+ }
else {
kernel_split_branched_indirect_light_init(kg, ray_index);
@@ -151,7 +174,8 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg,
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED);
}
else {
- kernel_split_branched_indirect_light_end(kg, ray_index);
+ kernel_split_branched_path_indirect_loop_end(kg, ray_index);
+ kernel_split_branched_transparent_bounce(kg, ray_index);
}
}
#endif /* __BRANCHED_PATH__ */
@@ -196,7 +220,8 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg,
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED);
}
else {
- kernel_split_branched_indirect_light_end(kg, ray_index);
+ kernel_split_branched_path_indirect_loop_end(kg, ray_index);
+ kernel_split_branched_transparent_bounce(kg, ray_index);
}
}
diff --git a/intern/cycles/kernel/split/kernel_queue_enqueue.h b/intern/cycles/kernel/split/kernel_queue_enqueue.h
index 66ce2dfb6f1..df67fabab19 100644
--- a/intern/cycles/kernel/split/kernel_queue_enqueue.h
+++ b/intern/cycles/kernel/split/kernel_queue_enqueue.h
@@ -56,6 +56,7 @@ ccl_device void kernel_queue_enqueue(KernelGlobals *kg,
queue_number = QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS;
}
else if(IS_STATE(kernel_split_state.ray_state, ray_index, RAY_ACTIVE) ||
+ IS_STATE(kernel_split_state.ray_state, ray_index, RAY_HAS_ONLY_VOLUME) ||
IS_STATE(kernel_split_state.ray_state, ray_index, RAY_REGENERATED)) {
queue_number = QUEUE_ACTIVE_AND_REGENERATED_RAYS;
}
diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h
index 2409d1ba28b..2bc2d300699 100644
--- a/intern/cycles/kernel/split/kernel_shader_eval.h
+++ b/intern/cycles/kernel/split/kernel_shader_eval.h
@@ -50,7 +50,7 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg)
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
- shader_eval_surface(kg, kernel_split_sd(sd, ray_index), state, state->flag, kernel_data.integrator.max_closures);
+ shader_eval_surface(kg, kernel_split_sd(sd, ray_index), state, state->flag);
#ifdef __BRANCHED_PATH__
if(kernel_data.integrator.branched) {
shader_merge_closures(kernel_split_sd(sd, ray_index));
diff --git a/intern/cycles/kernel/split/kernel_shader_setup.h b/intern/cycles/kernel/split/kernel_shader_setup.h
index 9d428ee8139..ea3ec2ec83f 100644
--- a/intern/cycles/kernel/split/kernel_shader_setup.h
+++ b/intern/cycles/kernel/split/kernel_shader_setup.h
@@ -59,12 +59,20 @@ ccl_device void kernel_shader_setup(KernelGlobals *kg,
if(IS_STATE(kernel_split_state.ray_state, ray_index, RAY_ACTIVE)) {
Intersection isect = kernel_split_state.isect[ray_index];
Ray ray = kernel_split_state.ray[ray_index];
+ ShaderData *sd = kernel_split_sd(sd, ray_index);
shader_setup_from_ray(kg,
- kernel_split_sd(sd, ray_index),
+ sd,
&isect,
&ray);
+
+#ifdef __VOLUME__
+ if(sd->flag & SD_HAS_ONLY_VOLUME) {
+ ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_HAS_ONLY_VOLUME);
+ }
+#endif
}
+
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h
index 21886ee62ee..b52e7bddc82 100644
--- a/intern/cycles/kernel/split/kernel_split_common.h
+++ b/intern/cycles/kernel/split/kernel_split_common.h
@@ -59,7 +59,12 @@ ccl_device_inline void kernel_split_path_end(KernelGlobals *kg, int ray_index)
ccl_global char *ray_state = kernel_split_state.ray_state;
#ifdef __BRANCHED_PATH__
- if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT_SHARED)) {
+ ccl_addr_space SubsurfaceIndirectRays *ss_indirect = &kernel_split_state.ss_rays[ray_index];
+
+ if(ss_indirect->num_rays) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ }
+ else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT_SHARED)) {
int orig_ray = kernel_split_state.branched_state[ray_index].original_ray;
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
diff --git a/intern/cycles/kernel/split/kernel_subsurface_scatter.h b/intern/cycles/kernel/split/kernel_subsurface_scatter.h
index e50d63ea3bc..af0303d8608 100644
--- a/intern/cycles/kernel/split/kernel_subsurface_scatter.h
+++ b/intern/cycles/kernel/split/kernel_subsurface_scatter.h
@@ -228,7 +228,9 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg)
if(sd->flag & SD_BSSRDF) {
#ifdef __BRANCHED_PATH__
- if(!kernel_data.integrator.branched) {
+ if(!kernel_data.integrator.branched ||
+ IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT))
+ {
#endif
if(kernel_path_subsurface_scatter(kg,
sd,
@@ -243,27 +245,6 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg)
}
#ifdef __BRANCHED_PATH__
}
- else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) {
- float bssrdf_u, bssrdf_v;
- path_state_rng_2D(kg,
- state,
- PRNG_BSDF_U,
- &bssrdf_u, &bssrdf_v);
-
- const ShaderClosure *sc = shader_bssrdf_pick(sd, throughput, &bssrdf_u);
-
- /* do bssrdf scatter step if we picked a bssrdf closure */
- if(sc) {
- uint lcg_state = lcg_state_init_addrspace(state, 0x68bc21eb);
- subsurface_scatter_step(kg,
- sd,
- state,
- sc,
- &lcg_state,
- bssrdf_u, bssrdf_v,
- false);
- }
- }
else {
kernel_split_branched_path_subsurface_indirect_light_init(kg, ray_index);
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index fae9f783483..39cd5da7b12 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -334,7 +334,10 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
break;
# if NODES_FEATURE(NODE_FEATURE_VOLUME)
case NODE_CLOSURE_VOLUME:
- svm_node_closure_volume(kg, sd, stack, node, type, path_flag);
+ svm_node_closure_volume(kg, sd, stack, node, type);
+ break;
+ case NODE_PRINCIPLED_VOLUME:
+ svm_node_principled_volume(kg, sd, stack, node, type, path_flag, &offset);
break;
# endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */
# ifdef __EXTRA_NODES__
diff --git a/intern/cycles/kernel/svm/svm_bevel.h b/intern/cycles/kernel/svm/svm_bevel.h
index dcfe4ad71b8..6d5a10db98f 100644
--- a/intern/cycles/kernel/svm/svm_bevel.h
+++ b/intern/cycles/kernel/svm/svm_bevel.h
@@ -216,7 +216,7 @@ ccl_device void svm_node_bevel(
if(stack_valid(normal_offset)) {
/* Preserve input normal. */
float3 ref_N = stack_load_float3(stack, normal_offset);
- bevel_N = normalize(sd->N + (bevel_N - ref_N));
+ bevel_N = normalize(ref_N + (bevel_N - sd->N));;
}
stack_store_float3(stack, out_offset, bevel_N);
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 5398f36c267..886a1333fa3 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -449,7 +449,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
}
case CLOSURE_BSDF_TRANSPARENT_ID: {
float3 weight = sd->svm_closure_weight * mix_weight;
- bsdf_transparent_setup(sd, weight);
+ bsdf_transparent_setup(sd, weight, path_flag);
break;
}
case CLOSURE_BSDF_REFLECTION_ID:
@@ -468,10 +468,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
break;
}
+ float roughness = sqr(param1);
+
bsdf->N = N;
bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_x = param1;
- bsdf->alpha_y = param1;
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
bsdf->ior = 0.0f;
bsdf->extra = NULL;
@@ -525,8 +527,9 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sd->flag |= bsdf_refraction_setup(bsdf);
}
else {
- bsdf->alpha_x = param1;
- bsdf->alpha_y = param1;
+ float roughness = sqr(param1);
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
bsdf->ior = eta;
if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
@@ -557,7 +560,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
/* fresnel */
float cosNO = dot(N, sd->I);
float fresnel = fresnel_dielectric_cos(cosNO, eta);
- float roughness = param1;
+ float roughness = sqr(param1);
/* reflection */
#ifdef __CAUSTICS_TRICKS__
@@ -611,8 +614,9 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
bsdf->extra = extra;
bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- bsdf->alpha_x = param1;
- bsdf->alpha_y = param1;
+ float roughness = sqr(param1);
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
float eta = fmaxf(param2, 1e-5f);
bsdf->ior = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
@@ -648,7 +652,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
/* compute roughness */
- float roughness = param1;
+ float roughness = sqr(param1);
float anisotropy = clamp(param2, -0.99f, 0.99f);
if(anisotropy < 0.0f) {
@@ -728,7 +732,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
* the throughput can blow up after multiple bounces. we
* better figure out a way to skip backfaces from rays
* spawned by transmission from the front */
- bsdf_transparent_setup(sd, make_float3(1.0f, 1.0f, 1.0f));
+ bsdf_transparent_setup(sd, make_float3(1.0f, 1.0f, 1.0f), path_flag);
}
else {
HairBsdf *bsdf = (HairBsdf*)bsdf_alloc(sd, sizeof(HairBsdf), weight);
@@ -794,7 +798,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
}
}
-ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ShaderType shader_type, int path_flag)
+ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ShaderType shader_type)
{
#ifdef __VOLUME__
/* Only sum extinction for volumes, variable is shared with surface transparency. */
@@ -802,19 +806,20 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
return;
}
- uint type, param1_offset, param2_offset;
+ uint type, density_offset, anisotropy_offset;
uint mix_weight_offset;
- decode_node_uchar4(node.y, &type, &param1_offset, &param2_offset, &mix_weight_offset);
+ decode_node_uchar4(node.y, &type, &density_offset, &anisotropy_offset, &mix_weight_offset);
float mix_weight = (stack_valid(mix_weight_offset)? stack_load_float(stack, mix_weight_offset): 1.0f);
- if(mix_weight == 0.0f)
+ if(mix_weight == 0.0f) {
return;
+ }
- float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __uint_as_float(node.z);
+ float density = (stack_valid(density_offset))? stack_load_float(stack, density_offset): __uint_as_float(node.z);
+ density = mix_weight * fmaxf(density, 0.0f);
/* Compute scattering coefficient. */
- float density = mix_weight * fmaxf(param1, 0.0f);
float3 weight = sd->svm_closure_weight;
if(type == CLOSURE_VOLUME_ABSORPTION_ID) {
@@ -825,11 +830,11 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
/* Add closure for volume scattering. */
if(type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
- float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w);
HenyeyGreensteinVolume *volume = (HenyeyGreensteinVolume*)bsdf_alloc(sd, sizeof(HenyeyGreensteinVolume), weight);
if(volume) {
- volume->g = param2; /* g */
+ float anisotropy = (stack_valid(anisotropy_offset))? stack_load_float(stack, anisotropy_offset): __uint_as_float(node.w);
+ volume->g = anisotropy; /* g */
sd->flag |= volume_henyey_greenstein_setup(volume);
}
}
@@ -839,6 +844,106 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
#endif
}
+ccl_device void svm_node_principled_volume(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ShaderType shader_type, int path_flag, int *offset)
+{
+#ifdef __VOLUME__
+ uint4 value_node = read_node(kg, offset);
+ uint4 attr_node = read_node(kg, offset);
+
+ /* Only sum extinction for volumes, variable is shared with surface transparency. */
+ if(shader_type != SHADER_TYPE_VOLUME) {
+ return;
+ }
+
+ uint density_offset, anisotropy_offset, absorption_color_offset, mix_weight_offset;
+ decode_node_uchar4(node.y, &density_offset, &anisotropy_offset, &absorption_color_offset, &mix_weight_offset);
+ float mix_weight = (stack_valid(mix_weight_offset)? stack_load_float(stack, mix_weight_offset): 1.0f);
+
+ if(mix_weight == 0.0f) {
+ return;
+ }
+
+ /* Compute density. */
+ float primitive_density = 1.0f;
+ float density = (stack_valid(density_offset))? stack_load_float(stack, density_offset): __uint_as_float(value_node.x);
+ density = mix_weight * fmaxf(density, 0.0f);
+
+ if(density > CLOSURE_WEIGHT_CUTOFF) {
+ /* Density and color attribute lookup if available. */
+ const AttributeDescriptor attr_density = find_attribute(kg, sd, attr_node.x);
+ if(attr_density.offset != ATTR_STD_NOT_FOUND) {
+ primitive_density = primitive_attribute_float(kg, sd, attr_density, NULL, NULL);
+ density = fmaxf(density * primitive_density, 0.0f);
+ }
+ }
+
+ if(density > CLOSURE_WEIGHT_CUTOFF) {
+ /* Compute scattering color. */
+ float3 color = sd->svm_closure_weight;
+
+ const AttributeDescriptor attr_color = find_attribute(kg, sd, attr_node.y);
+ if(attr_color.offset != ATTR_STD_NOT_FOUND) {
+ color *= primitive_attribute_float3(kg, sd, attr_color, NULL, NULL);
+ }
+
+ /* Add closure for volume scattering. */
+ HenyeyGreensteinVolume *volume = (HenyeyGreensteinVolume*)bsdf_alloc(sd, sizeof(HenyeyGreensteinVolume), color * density);
+ if(volume) {
+ float anisotropy = (stack_valid(anisotropy_offset))? stack_load_float(stack, anisotropy_offset): __uint_as_float(value_node.y);
+ volume->g = anisotropy;
+ sd->flag |= volume_henyey_greenstein_setup(volume);
+ }
+
+ /* Add extinction weight. */
+ float3 zero = make_float3(0.0f, 0.0f, 0.0f);
+ float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ float3 absorption_color = max(sqrt(stack_load_float3(stack, absorption_color_offset)), zero);
+ float3 absorption = max(one - color, zero) * max(one - absorption_color, zero);
+ volume_extinction_setup(sd, (color + absorption) * density);
+ }
+
+ /* Compute emission. */
+ if(path_flag & PATH_RAY_SHADOW) {
+ /* Don't need emission for shadows. */
+ return;
+ }
+
+ uint emission_offset, emission_color_offset, blackbody_offset, temperature_offset;
+ decode_node_uchar4(node.z, &emission_offset, &emission_color_offset, &blackbody_offset, &temperature_offset);
+ float emission = (stack_valid(emission_offset))? stack_load_float(stack, emission_offset): __uint_as_float(value_node.z);
+ float blackbody = (stack_valid(blackbody_offset))? stack_load_float(stack, blackbody_offset): __uint_as_float(value_node.w);
+
+ if(emission > CLOSURE_WEIGHT_CUTOFF) {
+ float3 emission_color = stack_load_float3(stack, emission_color_offset);
+ emission_setup(sd, emission * emission_color);
+ }
+
+ if(blackbody > CLOSURE_WEIGHT_CUTOFF) {
+ float T = stack_load_float(stack, temperature_offset);
+
+ /* Add flame temperature from attribute if available. */
+ const AttributeDescriptor attr_temperature = find_attribute(kg, sd, attr_node.z);
+ if(attr_temperature.offset != ATTR_STD_NOT_FOUND) {
+ float temperature = primitive_attribute_float(kg, sd, attr_temperature, NULL, NULL);
+ T *= fmaxf(temperature, 0.0f);
+ }
+
+ T = fmaxf(T, 0.0f);
+
+ /* Stefan-Boltzmann law. */
+ float T4 = sqr(sqr(T));
+ float sigma = 5.670373e-8f * 1e-6f / M_PI_F;
+ float intensity = sigma * mix(1.0f, T4, blackbody);
+
+ if(intensity > CLOSURE_WEIGHT_CUTOFF) {
+ float3 blackbody_tint = stack_load_float3(stack, node.w);
+ float3 bb = blackbody_tint * intensity * svm_math_blackbody_color(T);
+ emission_setup(sd, bb);
+ }
+ }
+#endif
+}
+
ccl_device void svm_node_closure_emission(ShaderData *sd, float *stack, uint4 node)
{
uint mix_weight_offset = node.y;
diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h
index 0a890545af4..42a7ae9946f 100644
--- a/intern/cycles/kernel/svm/svm_mapping.h
+++ b/intern/cycles/kernel/svm/svm_mapping.h
@@ -26,7 +26,6 @@ ccl_device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
- tfm.w = read_node_float(kg, offset);
float3 r = transform_point(&tfm, v);
stack_store_float3(stack, out_offset, r);
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index c94327401f5..6ff39e5f587 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -42,7 +42,6 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
- tfm.w = read_node_float(kg, offset);
data = transform_point(&tfm, data);
}
break;
@@ -123,7 +122,6 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
- tfm.w = read_node_float(kg, offset);
data = transform_point(&tfm, data);
}
break;
@@ -207,7 +205,6 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
- tfm.w = read_node_float(kg, offset);
data = transform_point(&tfm, data);
}
break;
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 390d3255684..4c3a5975fb8 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -135,6 +135,7 @@ typedef enum ShaderNodeType {
NODE_BEVEL,
NODE_DISPLACEMENT,
NODE_VECTOR_DISPLACEMENT,
+ NODE_PRINCIPLED_VOLUME,
} ShaderNodeType;
typedef enum NodeAttributeType {
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
index d967516a5c9..43b433683e0 100644
--- a/intern/cycles/kernel/svm/svm_voxel.h
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -39,7 +39,6 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
- tfm.w = read_node_float(kg, offset);
co = transform_point(&tfm, co);
}
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 580d76e7777..b7248354abd 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -23,6 +23,7 @@ set(SRC
mesh.cpp
mesh_displace.cpp
mesh_subdivision.cpp
+ mesh_volume.cpp
nodes.cpp
object.cpp
osl.cpp
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index 2c22db8189d..8c77687d9cc 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -281,6 +281,8 @@ const char *Attribute::standard_name(AttributeStandard std)
return "flame";
case ATTR_STD_VOLUME_HEAT:
return "heat";
+ case ATTR_STD_VOLUME_TEMPERATURE:
+ return "temperature";
case ATTR_STD_VOLUME_VELOCITY:
return "velocity";
case ATTR_STD_POINTINESS:
@@ -296,9 +298,13 @@ const char *Attribute::standard_name(AttributeStandard std)
AttributeStandard Attribute::name_standard(const char *name)
{
- for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++)
- if(strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0)
- return (AttributeStandard)std;
+ if(name) {
+ for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) {
+ if(strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) {
+ return (AttributeStandard)std;
+ }
+ }
+ }
return ATTR_STD_NONE;
}
@@ -425,6 +431,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
case ATTR_STD_VOLUME_DENSITY:
case ATTR_STD_VOLUME_FLAME:
case ATTR_STD_VOLUME_HEAT:
+ case ATTR_STD_VOLUME_TEMPERATURE:
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
break;
case ATTR_STD_VOLUME_COLOR:
@@ -528,9 +535,23 @@ void AttributeSet::resize(bool reserve_only)
}
}
-void AttributeSet::clear()
+void AttributeSet::clear(bool preserve_voxel_data)
{
- attributes.clear();
+ if(preserve_voxel_data) {
+ list<Attribute>::iterator it;
+
+ for(it = attributes.begin(); it != attributes.end();) {
+ if(it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) {
+ it++;
+ }
+ else {
+ attributes.erase(it++);
+ }
+ }
+ }
+ else {
+ attributes.clear();
+ }
}
/* AttributeRequest */
@@ -612,9 +633,11 @@ bool AttributeRequestSet::modified(const AttributeRequestSet& other)
void AttributeRequestSet::add(ustring name)
{
- foreach(AttributeRequest& req, requests)
- if(req.name == name)
+ foreach(AttributeRequest& req, requests) {
+ if(req.name == name) {
return;
+ }
+ }
requests.push_back(AttributeRequest(name));
}
@@ -638,6 +661,22 @@ void AttributeRequestSet::add(AttributeRequestSet& reqs)
}
}
+void AttributeRequestSet::add_standard(ustring name)
+{
+ if(!name) {
+ return;
+ }
+
+ AttributeStandard std = Attribute::name_standard(name.c_str());
+
+ if(std) {
+ add(std);
+ }
+ else {
+ add(name);
+ }
+}
+
bool AttributeRequestSet::find(ustring name)
{
foreach(AttributeRequest& req, requests)
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index d15ee401a72..5cb6c75aab2 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -123,7 +123,7 @@ public:
void remove(Attribute *attribute);
void resize(bool reserve_only = false);
- void clear();
+ void clear(bool preserve_voxel_data = false);
};
/* AttributeRequest
@@ -159,6 +159,7 @@ public:
void add(ustring name);
void add(AttributeStandard std);
void add(AttributeRequestSet& reqs);
+ void add_standard(ustring name);
bool find(ustring name);
bool find(AttributeStandard std);
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 1fef7a0188f..927e04abc7f 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -247,7 +247,7 @@ void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
int BakeManager::aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type)
{
- if(type == SHADER_EVAL_UV) {
+ if(type == SHADER_EVAL_UV || type == SHADER_EVAL_ROUGHNESS) {
return 1;
}
else if(type == SHADER_EVAL_NORMAL) {
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index e4931a6317c..91b739741bb 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -21,7 +21,6 @@
#include "util/util_foreach.h"
#include "util/util_hash.h"
-#include "util/util_image.h"
#include "util/util_math.h"
#include "util/util_opengl.h"
#include "util/util_time.h"
@@ -452,37 +451,5 @@ bool DisplayBuffer::draw_ready()
return (draw_width != 0 && draw_height != 0);
}
-void DisplayBuffer::write(const string& filename)
-{
- int w = draw_width;
- int h = draw_height;
-
- if(w == 0 || h == 0)
- return;
-
- if(half_float)
- return;
-
- /* read buffer from device */
- uchar4 *pixels = rgba_byte.copy_from_device(0, w, h);
-
- /* write image */
- ImageOutput *out = ImageOutput::create(filename);
- ImageSpec spec(w, h, 4, TypeDesc::UINT8);
-
- out->open(filename, spec);
-
- /* conversion for different top/bottom convention */
- out->write_image(TypeDesc::UINT8,
- (uchar*)(pixels + (h-1)*w),
- AutoStride,
- -w*sizeof(uchar4),
- AutoStride);
-
- out->close();
-
- delete out;
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 028bfb83735..dfc98fe2061 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -113,7 +113,6 @@ public:
~DisplayBuffer();
void reset(BufferParams& params);
- void write(const string& filename);
void draw_set(int width, int height);
void draw(Device *device, const DeviceDrawParams& draw_params);
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index a2fda12ec85..38936ffc094 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -82,6 +82,7 @@ NODE_DEFINE(Camera)
SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
+ SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
@@ -151,9 +152,6 @@ Camera::Camera()
height = 512;
resolution = 1;
- motion.pre = transform_identity();
- motion.post = transform_identity();
- use_motion = false;
use_perspective_motion = false;
shutter_curve.resize(RAMP_TABLE_SIZE);
@@ -163,12 +161,12 @@ Camera::Camera()
compute_auto_viewplane();
- screentoworld = transform_identity();
- rastertoworld = transform_identity();
- ndctoworld = transform_identity();
- rastertocamera = transform_identity();
+ screentoworld = projection_identity();
+ rastertoworld = projection_identity();
+ ndctoworld = projection_identity();
+ rastertocamera = projection_identity();
cameratoworld = transform_identity();
- worldtoraster = transform_identity();
+ worldtoraster = projection_identity();
dx = make_float3(0.0f, 0.0f, 0.0f);
dy = make_float3(0.0f, 0.0f, 0.0f);
@@ -241,18 +239,18 @@ void Camera::update(Scene *scene)
Transform full_rastertoscreen = transform_inverse(full_screentoraster);
/* screen to camera */
- Transform cameratoscreen;
+ ProjectionTransform cameratoscreen;
if(type == CAMERA_PERSPECTIVE)
- cameratoscreen = transform_perspective(fov, nearclip, farclip);
+ cameratoscreen = projection_perspective(fov, nearclip, farclip);
else if(type == CAMERA_ORTHOGRAPHIC)
- cameratoscreen = transform_orthographic(nearclip, farclip);
+ cameratoscreen = projection_orthographic(nearclip, farclip);
else
- cameratoscreen = transform_identity();
+ cameratoscreen = projection_identity();
- Transform screentocamera = transform_inverse(cameratoscreen);
+ ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
rastertocamera = screentocamera * rastertoscreen;
- Transform full_rastertocamera = screentocamera * full_rastertoscreen;
+ ProjectionTransform full_rastertocamera = screentocamera * full_rastertoscreen;
cameratoraster = screentoraster * cameratoscreen;
cameratoworld = matrix;
@@ -270,10 +268,10 @@ void Camera::update(Scene *scene)
/* differentials */
if(type == CAMERA_ORTHOGRAPHIC) {
- dx = transform_direction(&rastertocamera, make_float3(1, 0, 0));
- dy = transform_direction(&rastertocamera, make_float3(0, 1, 0));
- full_dx = transform_direction(&full_rastertocamera, make_float3(1, 0, 0));
- full_dy = transform_direction(&full_rastertocamera, make_float3(0, 1, 0));
+ dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
+ dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
+ full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
+ full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
}
else if(type == CAMERA_PERSPECTIVE) {
dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
@@ -302,23 +300,6 @@ void Camera::update(Scene *scene)
frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
}
- /* TODO(sergey): Support other types of camera. */
- if(type == CAMERA_PERSPECTIVE) {
- /* TODO(sergey): Move to an utility function and de-duplicate with
- * calculation above.
- */
- Transform screentocamera_pre =
- transform_inverse(transform_perspective(fov_pre,
- nearclip,
- farclip));
- Transform screentocamera_post =
- transform_inverse(transform_perspective(fov_post,
- nearclip,
- farclip));
- perspective_motion.pre = screentocamera_pre * rastertoscreen;
- perspective_motion.post = screentocamera_post * rastertoscreen;
- }
-
/* Compute kernel camera data. */
KernelCamera *kcam = &kernel_camera;
@@ -331,41 +312,65 @@ void Camera::update(Scene *scene)
kcam->worldtoscreen = worldtoscreen;
kcam->worldtoraster = worldtoraster;
kcam->worldtondc = worldtondc;
+ kcam->ndctoworld = ndctoworld;
/* camera motion */
- kcam->have_motion = 0;
+ kcam->num_motion_steps = 0;
kcam->have_perspective_motion = 0;
+ kernel_camera_motion.clear();
+
+ /* Test if any of the transforms are actually different. */
+ bool have_motion = false;
+ for(size_t i = 0; i < motion.size(); i++) {
+ have_motion = have_motion || motion[i] != matrix;
+ }
if(need_motion == Scene::MOTION_PASS) {
/* TODO(sergey): Support perspective (zoom, fov) motion. */
if(type == CAMERA_PANORAMA) {
- if(use_motion) {
- kcam->motion.pre = transform_inverse(motion.pre);
- kcam->motion.post = transform_inverse(motion.post);
+ if(have_motion) {
+ kcam->motion_pass_pre = transform_inverse(motion[0]);
+ kcam->motion_pass_post = transform_inverse(motion[motion.size()-1]);
}
else {
- kcam->motion.pre = kcam->worldtocamera;
- kcam->motion.post = kcam->worldtocamera;
+ kcam->motion_pass_pre = kcam->worldtocamera;
+ kcam->motion_pass_post = kcam->worldtocamera;
}
}
else {
- if(use_motion) {
- kcam->motion.pre = cameratoraster * transform_inverse(motion.pre);
- kcam->motion.post = cameratoraster * transform_inverse(motion.post);
+ if(have_motion) {
+ kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
+ kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size()-1]);
}
else {
- kcam->motion.pre = worldtoraster;
- kcam->motion.post = worldtoraster;
+ kcam->perspective_pre = worldtoraster;
+ kcam->perspective_post = worldtoraster;
}
}
}
else if(need_motion == Scene::MOTION_BLUR) {
- if(use_motion) {
- transform_motion_decompose(&kcam->motion, &motion, &matrix);
- kcam->have_motion = 1;
+ if(have_motion) {
+ kernel_camera_motion.resize(motion.size());
+ transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
+ kcam->num_motion_steps = motion.size();
}
- if(use_perspective_motion) {
- kcam->perspective_motion = perspective_motion;
+
+ /* TODO(sergey): Support other types of camera. */
+ if(use_perspective_motion && type == CAMERA_PERSPECTIVE) {
+ /* TODO(sergey): Move to an utility function and de-duplicate with
+ * calculation above.
+ */
+ ProjectionTransform screentocamera_pre =
+ projection_inverse(projection_perspective(fov_pre,
+ nearclip,
+ farclip));
+ ProjectionTransform screentocamera_post =
+ projection_inverse(projection_perspective(fov_post,
+ nearclip,
+ farclip));
+
+ kcam->perspective_pre = screentocamera_pre * rastertoscreen;
+ kcam->perspective_post = screentocamera_post * rastertoscreen;
kcam->have_perspective_motion = 1;
}
}
@@ -470,6 +475,16 @@ void Camera::device_update(Device * /* device */,
}
dscene->data.cam = kernel_camera;
+
+ size_t num_motion_steps = kernel_camera_motion.size();
+ if(num_motion_steps) {
+ DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
+ memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
+ dscene->camera_motion.copy_to_device();
+ }
+ else {
+ dscene->camera_motion.free();
+ }
}
void Camera::device_update_volume(Device * /*device*/,
@@ -496,10 +511,11 @@ void Camera::device_update_volume(Device * /*device*/,
}
void Camera::device_free(Device * /*device*/,
- DeviceScene * /*dscene*/,
+ DeviceScene *dscene,
Scene *scene)
{
scene->lookup_tables->remove_table(&shutter_table_offset);
+ dscene->camera_motion.free();
}
bool Camera::modified(const Camera& cam)
@@ -510,7 +526,6 @@ bool Camera::modified(const Camera& cam)
bool Camera::motion_modified(const Camera& cam)
{
return !((motion == cam.motion) &&
- (use_motion == cam.use_motion) &&
(use_perspective_motion == cam.use_perspective_motion));
}
@@ -606,7 +621,7 @@ float Camera::world_to_raster_size(float3 P)
res = min(len(full_dx), len(full_dy));
if(offscreen_dicing_scale > 1.0f) {
- float3 p = transform_perspective(&worldtocamera, P);
+ float3 p = transform_point(&worldtocamera, P);
float3 v = transform_perspective(&rastertocamera, make_float3(width, height, 0.0f));
/* Create point clamped to frustum */
@@ -707,17 +722,17 @@ float Camera::world_to_raster_size(float3 P)
* may be a better way to do this, but calculating differentials from the
* point directly ahead seems to produce good enough results. */
#if 0
- float2 dir = direction_to_panorama(&kernel_camera, normalize(D));
+ float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
float3 raster = transform_perspective(&cameratoraster, make_float3(dir.x, dir.y, 0.0f));
ray.t = 1.0f;
- camera_sample_panorama(&kernel_camera, raster.x, raster.y, 0.0f, 0.0f, &ray);
+ camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
if(ray.t == 0.0f) {
/* No differentials, just use from directly ahead. */
- camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
+ camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
}
#else
- camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
+ camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
#endif
differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist);
@@ -729,4 +744,27 @@ float Camera::world_to_raster_size(float3 P)
return res;
}
+bool Camera::use_motion() const
+{
+ return motion.size() > 1;
+}
+
+float Camera::motion_time(int step) const
+{
+ return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
+
+int Camera::motion_step(float time) const
+{
+ if(use_motion()) {
+ for(int step = 0; step < motion.size(); step++) {
+ if(time == motion_time(step)) {
+ return step;
+ }
+ }
+ }
+
+ return -1;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 4ec0fe3bc6e..37d05c01bd9 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -22,6 +22,7 @@
#include "graph/node.h"
#include "util/util_boundbox.h"
+#include "util/util_projection.h"
#include "util/util_transform.h"
#include "util/util_types.h"
@@ -140,24 +141,23 @@ public:
Transform matrix;
/* motion */
- MotionTransform motion;
- bool use_motion, use_perspective_motion;
+ array<Transform> motion;
+ bool use_perspective_motion;
float fov_pre, fov_post;
- PerspectiveMotionTransform perspective_motion;
/* computed camera parameters */
- Transform screentoworld;
- Transform rastertoworld;
- Transform ndctoworld;
+ ProjectionTransform screentoworld;
+ ProjectionTransform rastertoworld;
+ ProjectionTransform ndctoworld;
Transform cameratoworld;
- Transform worldtoraster;
- Transform worldtoscreen;
- Transform worldtondc;
+ ProjectionTransform worldtoraster;
+ ProjectionTransform worldtoscreen;
+ ProjectionTransform worldtondc;
Transform worldtocamera;
- Transform rastertocamera;
- Transform cameratoraster;
+ ProjectionTransform rastertocamera;
+ ProjectionTransform cameratoraster;
float3 dx;
float3 dy;
@@ -176,6 +176,7 @@ public:
/* Kernel camera data, copied here for dicing. */
KernelCamera kernel_camera;
+ array<DecomposedTransform> kernel_camera_motion;
/* functions */
Camera();
@@ -199,6 +200,11 @@ public:
/* Calculates the width of a pixel at point in world space. */
float world_to_raster_size(float3 P);
+ /* Motion blur. */
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+ bool use_motion() const;
+
private:
/* Private utility functions. */
float3 transform_raster_to_world(float raster_x, float raster_y);
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index 7ed292b5b96..2c134932b3c 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -156,6 +156,7 @@ public:
virtual bool has_bssrdf_bump() { return false; }
virtual bool has_spatial_varying() { return false; }
virtual bool has_object_dependency() { return false; }
+ virtual bool has_attribute_dependency() { return false; }
virtual bool has_integrator_dependency() { return false; }
virtual bool has_volume_support() { return false; }
virtual bool has_raytrace() { return false; }
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index dbe15a67b9e..9c5e32e8219 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -84,99 +84,119 @@ bool ImageManager::set_animation_frame_update(int frame)
return false;
}
-ImageDataType ImageManager::get_image_metadata(const string& filename,
- void *builtin_data,
- bool& is_linear,
- bool& builtin_free_cache)
+device_memory *ImageManager::image_memory(int flat_slot)
{
- bool is_float = false, is_half = false;
- is_linear = false;
- builtin_free_cache = false;
- int channels = 4;
+ ImageDataType type;
+ int slot = flattened_slot_to_type_index(flat_slot, &type);
+
+ Image *img = images[type][slot];
+
+ return img->mem;
+}
+
+bool ImageManager::get_image_metadata(const string& filename,
+ void *builtin_data,
+ ImageMetaData& metadata)
+{
+ memset(&metadata, 0, sizeof(metadata));
if(builtin_data) {
if(builtin_image_info_cb) {
- int width, height, depth;
- builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels, builtin_free_cache);
+ builtin_image_info_cb(filename, builtin_data, metadata);
+ }
+ else {
+ return false;
}
- if(is_float) {
- is_linear = true;
- return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
+ if(metadata.is_float) {
+ metadata.is_linear = true;
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
}
else {
- return (channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
}
+
+ return true;
}
/* Perform preliminary checks, with meaningful logging. */
if(!path_exists(filename)) {
VLOG(1) << "File '" << filename << "' does not exist.";
- return IMAGE_DATA_TYPE_BYTE4;
+ return false;
}
if(path_is_directory(filename)) {
VLOG(1) << "File '" << filename << "' is a directory, can't use as image.";
- return IMAGE_DATA_TYPE_BYTE4;
+ return false;
}
ImageInput *in = ImageInput::create(filename);
- if(in) {
- ImageSpec spec;
-
- if(in->open(filename, spec)) {
- /* check the main format, and channel formats;
- * if any take up more than one byte, we'll need a float texture slot */
- if(spec.format.basesize() > 1) {
- is_float = true;
- is_linear = true;
- }
+ if(!in) {
+ return false;
+ }
- for(size_t channel = 0; channel < spec.channelformats.size(); channel++) {
- if(spec.channelformats[channel].basesize() > 1) {
- is_float = true;
- is_linear = true;
- }
- }
+ ImageSpec spec;
+ if(!in->open(filename, spec)) {
+ delete in;
+ return false;
+ }
- /* check if it's half float */
- if(spec.format == TypeDesc::HALF)
- is_half = true;
+ metadata.width = spec.width;
+ metadata.height = spec.height;
+ metadata.depth = spec.depth;
- channels = spec.nchannels;
+ /* check the main format, and channel formats;
+ * if any take up more than one byte, we'll need a float texture slot */
+ if(spec.format.basesize() > 1) {
+ metadata.is_float = true;
+ metadata.is_linear = true;
+ }
- /* basic color space detection, not great but better than nothing
- * before we do OpenColorIO integration */
- if(is_float) {
- string colorspace = spec.get_string_attribute("oiio:ColorSpace");
+ for(size_t channel = 0; channel < spec.channelformats.size(); channel++) {
+ if(spec.channelformats[channel].basesize() > 1) {
+ metadata.is_float = true;
+ metadata.is_linear = true;
+ }
+ }
- is_linear = !(colorspace == "sRGB" ||
- colorspace == "GammaCorrected" ||
- (colorspace == "" &&
- (strcmp(in->format_name(), "png") == 0 ||
- strcmp(in->format_name(), "tiff") == 0 ||
- strcmp(in->format_name(), "dpx") == 0 ||
- strcmp(in->format_name(), "jpeg2000") == 0)));
- }
- else {
- is_linear = false;
- }
+ /* check if it's half float */
+ if(spec.format == TypeDesc::HALF)
+ metadata.is_half = true;
- in->close();
- }
+ /* basic color space detection, not great but better than nothing
+ * before we do OpenColorIO integration */
+ if(metadata.is_float) {
+ string colorspace = spec.get_string_attribute("oiio:ColorSpace");
- delete in;
+ metadata.is_linear = !(colorspace == "sRGB" ||
+ colorspace == "GammaCorrected" ||
+ (colorspace == "" &&
+ (strcmp(in->format_name(), "png") == 0 ||
+ strcmp(in->format_name(), "tiff") == 0 ||
+ strcmp(in->format_name(), "dpx") == 0 ||
+ strcmp(in->format_name(), "jpeg2000") == 0)));
+ }
+ else {
+ metadata.is_linear = false;
}
- if(is_half) {
- return (channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
+ /* set type and channels */
+ metadata.channels = spec.nchannels;
+
+ if(metadata.is_half) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
}
- else if(is_float) {
- return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
+ else if(metadata.is_float) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
}
else {
- return (channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
}
+
+ in->close();
+ delete in;
+
+ return true;
}
int ImageManager::max_flattened_slot(ImageDataType type)
@@ -237,23 +257,19 @@ int ImageManager::add_image(const string& filename,
void *builtin_data,
bool animated,
float frame,
- bool& is_float,
- bool& is_linear,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ bool use_alpha,
+ ImageMetaData& metadata)
{
Image *img;
size_t slot;
- bool builtin_free_cache;
- ImageDataType type = get_image_metadata(filename, builtin_data, is_linear, builtin_free_cache);
+ get_image_metadata(filename, builtin_data, metadata);
+ ImageDataType type = metadata.type;
thread_scoped_lock device_lock(device_mutex);
- /* Check whether it's a float texture. */
- is_float = (type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4);
-
/* No half textures on OpenCL, use full float instead. */
if(!has_half_images) {
if(type == IMAGE_DATA_TYPE_HALF4) {
@@ -313,7 +329,7 @@ int ImageManager::add_image(const string& filename,
img = new Image();
img->filename = filename;
img->builtin_data = builtin_data;
- img->builtin_free_cache = builtin_free_cache;
+ img->builtin_free_cache = metadata.builtin_free_cache;
img->need_load = true;
img->animated = animated;
img->frame = frame;
@@ -444,8 +460,13 @@ bool ImageManager::file_load_image_generic(Image *img,
if(!builtin_image_info_cb || !builtin_image_pixels_cb)
return false;
- bool is_float, free_cache;
- builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components, free_cache);
+ ImageMetaData metadata;
+ builtin_image_info_cb(img->filename, img->builtin_data, metadata);
+
+ width = metadata.width;
+ height = metadata.height;
+ depth = metadata.depth;
+ components = metadata.channels;
}
/* we only handle certain number of components */
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 6fca3ca20d3..5391490d993 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -31,6 +31,19 @@ class Device;
class Progress;
class Scene;
+class ImageMetaData {
+public:
+ /* Must be set by image file or builtin callback. */
+ bool is_float, is_half;
+ int channels;
+ size_t width, height, depth;
+ bool builtin_free_cache;
+
+ /* Automatically set. */
+ ImageDataType type;
+ bool is_linear;
+};
+
class ImageManager {
public:
explicit ImageManager(const DeviceInfo& info);
@@ -40,11 +53,10 @@ public:
void *builtin_data,
bool animated,
float frame,
- bool& is_float,
- bool& is_linear,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha);
+ bool use_alpha,
+ ImageMetaData& metadata);
void remove_image(int flat_slot);
void remove_image(const string& filename,
void *builtin_data,
@@ -56,10 +68,9 @@ public:
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha);
- ImageDataType get_image_metadata(const string& filename,
- void *builtin_data,
- bool& is_linear,
- bool& builtin_free_cache);
+ bool get_image_metadata(const string& filename,
+ void *builtin_data,
+ ImageMetaData& metadata);
void device_update(Device *device,
Scene *scene,
@@ -74,6 +85,8 @@ public:
void set_osl_texture_system(void *texture_system);
bool set_animation_frame_update(int frame);
+ device_memory *image_memory(int flat_slot);
+
bool need_update;
/* NOTE: Here pixels_size is a size of storage, which equals to
@@ -82,12 +95,7 @@ public:
*/
function<void(const string &filename,
void *data,
- bool &is_float,
- int &width,
- int &height,
- int &depth,
- int &channels,
- bool &free_cache)> builtin_image_info_cb;
+ ImageMetaData& metadata)> builtin_image_info_cb;
function<bool(const string &filename,
void *data,
unsigned char *pixels,
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index b62453cf5fc..8dec7e4ea64 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -288,7 +288,7 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
/* emission area */
- float4 *distribution = dscene->light_distribution.alloc(num_distribution + 1);
+ KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
float totarea = 0.0f;
/* triangles */
@@ -334,10 +334,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
: scene->default_surface;
if(shader->use_mis && shader->has_surface_emission) {
- distribution[offset].x = totarea;
- distribution[offset].y = __int_as_float(i + mesh->tri_offset);
- distribution[offset].z = __int_as_float(shader_flag);
- distribution[offset].w = __int_as_float(object_id);
+ distribution[offset].totarea = totarea;
+ distribution[offset].prim = i + mesh->tri_offset;
+ distribution[offset].mesh_light.shader_flag = shader_flag;
+ distribution[offset].mesh_light.object_id = object_id;
offset++;
Mesh::Triangle t = mesh->get_triangle(i);
@@ -372,10 +372,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
if(!light->is_enabled)
continue;
- distribution[offset].x = totarea;
- distribution[offset].y = __int_as_float(~light_index);
- distribution[offset].z = 1.0f;
- distribution[offset].w = light->size;
+ distribution[offset].totarea = totarea;
+ distribution[offset].prim = ~light_index;
+ distribution[offset].lamp.pad = 1.0f;
+ distribution[offset].lamp.size = light->size;
totarea += lightarea;
if(light->size > 0.0f && light->use_mis)
@@ -390,15 +390,15 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
}
/* normalize cumulative distribution functions */
- distribution[num_distribution].x = totarea;
- distribution[num_distribution].y = 0.0f;
- distribution[num_distribution].z = 0.0f;
- distribution[num_distribution].w = 0.0f;
+ distribution[num_distribution].totarea = totarea;
+ distribution[num_distribution].prim = 0.0f;
+ distribution[num_distribution].lamp.pad = 0.0f;
+ distribution[num_distribution].lamp.size = 0.0f;
if(totarea > 0.0f) {
for(size_t i = 0; i < num_distribution; i++)
- distribution[i].x /= totarea;
- distribution[num_distribution].x = 1.0f;
+ distribution[i].totarea /= totarea;
+ distribution[num_distribution].totarea = 1.0f;
}
if(progress.get_cancel()) return;
@@ -620,7 +620,7 @@ void LightManager::device_update_points(Device *,
}
}
- float4 *light_data = dscene->light_data.alloc(num_lights*LIGHT_SIZE);
+ KernelLight *klights = dscene->lights.alloc(num_lights);
if(num_lights == 0) {
VLOG(1) << "No effective light, ignoring points update.";
@@ -637,8 +637,8 @@ void LightManager::device_update_points(Device *,
float3 co = light->co;
Shader *shader = (light->shader) ? light->shader : scene->default_light;
int shader_id = scene->shader_manager->get_shader_id(shader);
- float samples = __int_as_float(light->samples);
- float max_bounces = __int_as_float(light->max_bounces);
+ int samples = light->samples;
+ int max_bounces = light->max_bounces;
float random = (float)light->random_id * (1.0f/(float)0xFFFFFFFF);
if(!light->cast_shadow)
@@ -661,6 +661,9 @@ void LightManager::device_update_points(Device *,
use_light_visibility = true;
}
+ klights[light_index].type = light->type;
+ klights[light_index].samples = samples;
+
if(light->type == LIGHT_POINT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -670,10 +673,12 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
- light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].spot.radius = radius;
+ klights[light_index].spot.invarea = invarea;
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -690,10 +695,13 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
- light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
- light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ klights[light_index].co[0] = dir.x;
+ klights[light_index].co[1] = dir.y;
+ klights[light_index].co[2] = dir.z;
+
+ klights[light_index].distant.invarea = invarea;
+ klights[light_index].distant.radius = radius;
+ klights[light_index].distant.cosangle = cosangle;
}
else if(light->type == LIGHT_BACKGROUND) {
uint visibility = scene->background->visibility;
@@ -717,11 +725,6 @@ void LightManager::device_update_points(Device *,
shader_id |= SHADER_EXCLUDE_SCATTER;
use_light_visibility = true;
}
-
- light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_AREA) {
float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -735,10 +738,20 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
- light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
- light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].area.axisu[0] = axisu.x;
+ klights[light_index].area.axisu[1] = axisu.y;
+ klights[light_index].area.axisu[2] = axisu.z;
+ klights[light_index].area.axisv[0] = axisv.x;
+ klights[light_index].area.axisv[1] = axisv.y;
+ klights[light_index].area.axisv[2] = axisv.z;
+ klights[light_index].area.invarea = invarea;
+ klights[light_index].area.dir[0] = dir.x;
+ klights[light_index].area.dir[1] = dir.y;
+ klights[light_index].area.dir[2] = dir.z;
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -754,18 +767,26 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
- light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
- light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].spot.radius = radius;
+ klights[light_index].spot.invarea = invarea;
+ klights[light_index].spot.spot_angle = spot_angle;
+ klights[light_index].spot.spot_smooth = spot_smooth;
+ klights[light_index].spot.dir[0] = dir.x;
+ klights[light_index].spot.dir[1] = dir.y;
+ klights[light_index].spot.dir[2] = dir.z;
}
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, random, 0.0f, 0.0f);
+ klights[light_index].shader_id = shader_id;
+
+ klights[light_index].max_bounces = max_bounces;
+ klights[light_index].random = random;
- Transform tfm = light->tfm;
- Transform itfm = transform_inverse(tfm);
- memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
- memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+ klights[light_index].tfm = light->tfm;
+ klights[light_index].itfm = transform_inverse(light->tfm);
light_index++;
}
@@ -782,21 +803,27 @@ void LightManager::device_update_points(Device *,
float3 axisu = light->axisu*(light->sizeu*light->size);
float3 axisv = light->axisv*(light->sizev*light->size);
float area = len(axisu)*len(axisv);
- float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+ float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
- light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[light_index*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
- light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
- light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
-
- Transform tfm = light->tfm;
- Transform itfm = transform_inverse(tfm);
- memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
- memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].area.axisu[0] = axisu.x;
+ klights[light_index].area.axisu[1] = axisu.y;
+ klights[light_index].area.axisu[2] = axisu.z;
+ klights[light_index].area.axisv[0] = axisv.x;
+ klights[light_index].area.axisv[1] = axisv.y;
+ klights[light_index].area.axisv[2] = axisv.z;
+ klights[light_index].area.invarea = invarea;
+ klights[light_index].area.dir[0] = dir.x;
+ klights[light_index].area.dir[1] = dir.y;
+ klights[light_index].area.dir[2] = dir.z;
+ klights[light_index].tfm = light->tfm;
+ klights[light_index].itfm = transform_inverse(light->tfm);
light_index++;
}
@@ -806,7 +833,7 @@ void LightManager::device_update_points(Device *,
VLOG(1) << "Number of lights without contribution: "
<< num_scene_lights - light_index;
- dscene->light_data.copy_to_device();
+ dscene->lights.copy_to_device();
}
void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -842,7 +869,7 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
void LightManager::device_free(Device *, DeviceScene *dscene)
{
dscene->light_distribution.free();
- dscene->light_data.free();
+ dscene->lights.free();
dscene->light_background_marginal_cdf.free();
dscene->light_background_conditional_cdf.free();
}
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 5bcb47deb65..7cfbb7b7c7d 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -446,6 +446,7 @@ Mesh::Mesh()
geometry_flags = GEOMETRY_NONE;
+ volume_isovalue = 0.001f;
has_volume = false;
has_surface_bssrdf = false;
@@ -533,7 +534,7 @@ void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners)
subd_attributes.resize(true);
}
-void Mesh::clear()
+void Mesh::clear(bool preserve_voxel_data)
{
/* clear all verts and triangles */
verts.clear();
@@ -556,15 +557,19 @@ void Mesh::clear()
subd_creases.clear();
- attributes.clear();
curve_attributes.clear();
subd_attributes.clear();
+ attributes.clear(preserve_voxel_data);
+
used_shaders.clear();
+ if(!preserve_voxel_data) {
+ geometry_flags = GEOMETRY_NONE;
+ }
+
transform_applied = false;
transform_negative_scaled = false;
transform_normal = transform_identity();
- geometry_flags = GEOMETRY_NONE;
delete patch_table;
patch_table = NULL;
@@ -872,15 +877,8 @@ void Mesh::add_undisplaced()
}
}
-void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
+void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
{
- Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
- if(attr_vN == NULL) {
- /* Happens on objects with just hair. */
- return;
- }
-
- float3 *vN = attr_vN->data_float3();
uint shader_id = 0;
uint last_shader = -1;
bool last_smooth = false;
@@ -888,10 +886,6 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
size_t triangles_size = num_triangles();
int *shader_ptr = shader.data();
- bool do_transform = transform_applied;
- Transform ntfm = transform_normal;
-
- /* save shader */
for(size_t i = 0; i < triangles_size; i++) {
if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
last_shader = shader_ptr[i];
@@ -903,7 +897,20 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
tri_shader[i] = shader_id;
}
+}
+void Mesh::pack_normals(float4 *vnormal)
+{
+ Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+ if(attr_vN == NULL) {
+ /* Happens on objects with just hair. */
+ return;
+ }
+
+ bool do_transform = transform_applied;
+ Transform ntfm = transform_normal;
+
+ float3 *vN = attr_vN->data_float3();
size_t verts_size = verts.size();
for(size_t i = 0; i < verts_size; i++) {
@@ -1112,6 +1119,32 @@ bool Mesh::has_true_displacement() const
return false;
}
+float Mesh::motion_time(int step) const
+{
+ return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
+}
+
+int Mesh::motion_step(float time) const
+{
+ if(motion_steps > 1) {
+ int attr_step = 0;
+
+ for(int step = 0; step < motion_steps; step++) {
+ float step_time = motion_time(step);
+ if(step_time == time) {
+ return attr_step;
+ }
+
+ /* Center step is stored in a separate attribute. */
+ if(step != motion_steps / 2) {
+ attr_step++;
+ }
+ }
+ }
+
+ return -1;
+}
+
bool Mesh::need_build_bvh() const
{
return !transform_applied || has_surface_bssrdf;
@@ -1440,11 +1473,11 @@ static void update_attribute_element_offset(Mesh *mesh,
Transform *tfm = mattr->data_transform();
offset = attr_float3_offset;
- assert(attr_float3.size() >= offset + size * 4);
- for(size_t k = 0; k < size*4; k++) {
+ assert(attr_float3.size() >= offset + size * 3);
+ for(size_t k = 0; k < size*3; k++) {
attr_float3[offset+k] = (&tfm->x)[k];
}
- attr_float3_offset += size * 4;
+ attr_float3_offset += size * 3;
}
else {
float4 *data = mattr->data_float4();
@@ -1742,9 +1775,9 @@ void MeshManager::device_update_mesh(Device *,
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
foreach(Mesh *mesh, scene->meshes) {
- mesh->pack_normals(scene,
- &tri_shader[mesh->tri_offset],
- &vnormal[mesh->vert_offset]);
+ mesh->pack_shaders(scene,
+ &tri_shader[mesh->tri_offset]);
+ mesh->pack_normals(&vnormal[mesh->vert_offset]);
mesh->pack_verts(tri_prim_index,
&tri_vindex[mesh->tri_offset],
&tri_patch[mesh->tri_offset],
@@ -1892,17 +1925,22 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
delete bvh;
}
-void MeshManager::device_update_flags(Device * /*device*/,
- DeviceScene * /*dscene*/,
- Scene * scene,
- Progress& /*progress*/)
+void MeshManager::device_update_preprocess(Device *device,
+ Scene *scene,
+ Progress& progress)
{
if(!need_update && !need_flags_update) {
return;
}
- /* update flags */
+
+ progress.set_status("Updating Meshes Flags");
+
+ /* Update flags. */
+ bool volume_images_updated = false;
+
foreach(Mesh *mesh, scene->meshes) {
mesh->has_volume = false;
+
foreach(const Shader *shader, mesh->used_shaders) {
if(shader->has_volume) {
mesh->has_volume = true;
@@ -1911,7 +1949,29 @@ void MeshManager::device_update_flags(Device * /*device*/,
mesh->has_surface_bssrdf = true;
}
}
+
+ if(need_update && mesh->has_volume) {
+ /* Create volume meshes if there is voxel data. */
+ bool has_voxel_attributes = false;
+
+ foreach(Attribute& attr, mesh->attributes.attributes) {
+ if(attr.element == ATTR_ELEMENT_VOXEL) {
+ has_voxel_attributes = true;
+ }
+ }
+
+ if(has_voxel_attributes) {
+ if(!volume_images_updated) {
+ progress.set_status("Updating Meshes Volume Bounds");
+ device_update_volume_images(device, scene, progress);
+ volume_images_updated = true;
+ }
+
+ create_volume_mesh(scene, mesh, progress);
+ }
+ }
}
+
need_flags_update = false;
}
@@ -1954,6 +2014,44 @@ void MeshManager::device_update_displacement_images(Device *device,
pool.wait_work();
}
+void MeshManager::device_update_volume_images(Device *device,
+ Scene *scene,
+ Progress& progress)
+{
+ progress.set_status("Updating Volume Images");
+ TaskPool pool;
+ ImageManager *image_manager = scene->image_manager;
+ set<int> volume_images;
+
+ foreach(Mesh *mesh, scene->meshes) {
+ if(!mesh->need_update) {
+ continue;
+ }
+
+ foreach(Attribute& attr, mesh->attributes.attributes) {
+ if(attr.element != ATTR_ELEMENT_VOXEL) {
+ continue;
+ }
+
+ VoxelAttribute *voxel = attr.data_voxel();
+
+ if(voxel->slot != -1) {
+ volume_images.insert(voxel->slot);
+ }
+ }
+ }
+
+ foreach(int slot, volume_images) {
+ pool.push(function_bind(&ImageManager::device_update_slot,
+ image_manager,
+ device,
+ scene,
+ slot,
+ &progress));
+ }
+ pool.wait_work();
+}
+
void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
if(!need_update)
@@ -1961,7 +2059,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
- /* Update normals. */
+ bool true_displacement_used = false;
+ size_t total_tess_needed = 0;
+
foreach(Mesh *mesh, scene->meshes) {
foreach(Shader *shader, mesh->used_shaders) {
if(shader->need_update_mesh)
@@ -1969,6 +2069,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
if(mesh->need_update) {
+ /* Update normals. */
mesh->add_face_normals();
mesh->add_vertex_normals();
@@ -1976,57 +2077,53 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
mesh->add_undisplaced();
}
+ /* Test if we need tesselation. */
+ if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+ mesh->num_subd_verts == 0 &&
+ mesh->subd_params)
+ {
+ total_tess_needed++;
+ }
+
+ /* Test if we need displacement. */
+ if(mesh->has_true_displacement()) {
+ true_displacement_used = true;
+ }
+
if(progress.get_cancel()) return;
}
}
/* Tessellate meshes that are using subdivision */
- size_t total_tess_needed = 0;
- foreach(Mesh *mesh, scene->meshes) {
- if(mesh->need_update &&
- mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
- mesh->num_subd_verts == 0 &&
- mesh->subd_params)
- {
- total_tess_needed++;
- }
- }
+ if(total_tess_needed) {
+ size_t i = 0;
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+ mesh->num_subd_verts == 0 &&
+ mesh->subd_params)
+ {
+ string msg = "Tessellating ";
+ if(mesh->name == "")
+ msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
+ else
+ msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
- size_t i = 0;
- foreach(Mesh *mesh, scene->meshes) {
- if(mesh->need_update &&
- mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
- mesh->num_subd_verts == 0 &&
- mesh->subd_params)
- {
- string msg = "Tessellating ";
- if(mesh->name == "")
- msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
- else
- msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
+ progress.set_status("Updating Mesh", msg);
- progress.set_status("Updating Mesh", msg);
+ DiagSplit dsplit(*mesh->subd_params);
+ mesh->tessellate(&dsplit);
- DiagSplit dsplit(*mesh->subd_params);
- mesh->tessellate(&dsplit);
+ i++;
- i++;
+ if(progress.get_cancel()) return;
+ }
- if(progress.get_cancel()) return;
}
}
/* Update images needed for true displacement. */
- bool true_displacement_used = false;
bool old_need_object_flags_update = false;
- foreach(Mesh *mesh, scene->meshes) {
- if(mesh->need_update &&
- mesh->has_true_displacement())
- {
- true_displacement_used = true;
- break;
- }
- }
if(true_displacement_used) {
VLOG(1) << "Updating images used for true displacement.";
device_update_displacement_images(device, scene, progress);
@@ -2052,11 +2149,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
/* Update displacement. */
bool displacement_done = false;
+ size_t num_bvh = 0;
+
foreach(Mesh *mesh, scene->meshes) {
- if(mesh->need_update &&
- displace(device, dscene, scene, mesh, progress))
- {
- displacement_done = true;
+ if(mesh->need_update) {
+ if(displace(device, dscene, scene, mesh, progress)) {
+ displacement_done = true;
+ }
+
+ if(mesh->need_build_bvh()) {
+ num_bvh++;
+ }
}
}
@@ -2071,17 +2174,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
if(progress.get_cancel()) return;
}
- /* Update bvh. */
- size_t num_bvh = 0;
- foreach(Mesh *mesh, scene->meshes) {
- if(mesh->need_update && mesh->need_build_bvh()) {
- num_bvh++;
- }
- }
-
TaskPool pool;
- i = 0;
+ size_t i = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
pool.push(function_bind(&Mesh::compute_bvh,
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 07d8bbdbf31..e370f8a2021 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -202,7 +202,8 @@ public:
array<int> triangle_patch; /* must be < 0 for non subd triangles */
array<float2> vert_patch_uv;
- bool has_volume; /* Set in the device_update_flags(). */
+ float volume_isovalue;
+ bool has_volume; /* Set in the device_update_flags(). */
bool has_surface_bssrdf; /* Set in the device_update_flags(). */
array<float3> curve_keys;
@@ -264,7 +265,7 @@ public:
void reserve_curves(int numcurves, int numkeys);
void resize_subd_faces(int numfaces, int num_ngons, int numcorners);
void reserve_subd_faces(int numfaces, int num_ngons, int numcorners);
- void clear();
+ void clear(bool preserve_voxel_data = false);
void add_vertex(float3 P);
void add_vertex_slow(float3 P);
void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
@@ -278,7 +279,8 @@ public:
void add_vertex_normals();
void add_undisplaced();
- void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
+ void pack_shaders(Scene *scene, uint *shader);
+ void pack_normals(float4 *vnormal);
void pack_verts(const vector<uint>& tri_prim_index,
uint4 *tri_vindex,
uint *tri_patch,
@@ -303,6 +305,11 @@ public:
bool has_motion_blur() const;
bool has_true_displacement() const;
+ /* Convert between normalized -1..1 motion time and index
+ * in the VERTEX_MOTION attribute. */
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+
/* Check whether the mesh should have own BVH built separately. Briefly,
* own BVH is needed for mesh, if:
*
@@ -335,13 +342,15 @@ public:
void update_osl_attributes(Device *device, Scene *scene, vector<AttributeRequestSet>& mesh_attributes);
void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes);
+ void device_update_preprocess(Device *device, Scene *scene, Progress& progress);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
+ void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress);
+
protected:
/* Calculate verts/triangles/curves offsets in global arrays. */
void mesh_calc_offset(Scene *scene);
@@ -370,6 +379,10 @@ protected:
void device_update_displacement_images(Device *device,
Scene *scene,
Progress& progress);
+
+ void device_update_volume_images(Device *device,
+ Scene *scene,
+ Progress& progress);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp
new file mode 100644
index 00000000000..3571beb40d6
--- /dev/null
+++ b/intern/cycles/render/mesh_volume.cpp
@@ -0,0 +1,586 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "render/mesh.h"
+#include "render/attribute.h"
+#include "render/scene.h"
+
+#include "util/util_foreach.h"
+#include "util/util_logging.h"
+#include "util/util_progress.h"
+#include "util/util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+static size_t compute_voxel_index(const int3 &resolution, size_t x, size_t y, size_t z)
+{
+ if(x == -1 || x >= resolution.x) {
+ return -1;
+ }
+
+ if(y == -1 || y >= resolution.y) {
+ return -1;
+ }
+
+ if(z == -1 || z >= resolution.z) {
+ return -1;
+ }
+
+ return x + y*resolution.x + z*resolution.x*resolution.y;
+}
+
+struct QuadData {
+ int v0, v1, v2, v3;
+
+ float3 normal;
+};
+
+enum {
+ QUAD_X_MIN = 0,
+ QUAD_X_MAX = 1,
+ QUAD_Y_MIN = 2,
+ QUAD_Y_MAX = 3,
+ QUAD_Z_MIN = 4,
+ QUAD_Z_MAX = 5,
+};
+
+const int quads_indices[6][4] = {
+ /* QUAD_X_MIN */
+ { 4, 0, 3, 7 },
+ /* QUAD_X_MAX */
+ { 1, 5, 6, 2 },
+ /* QUAD_Y_MIN */
+ { 4, 5, 1, 0 },
+ /* QUAD_Y_MAX */
+ { 3, 2, 6, 7 },
+ /* QUAD_Z_MIN */
+ { 0, 1, 2, 3 },
+ /* QUAD_Z_MAX */
+ { 5, 4, 7, 6 },
+};
+
+const float3 quads_normals[6] = {
+ /* QUAD_X_MIN */
+ make_float3(-1.0f, 0.0f, 0.0f),
+ /* QUAD_X_MAX */
+ make_float3(1.0f, 0.0f, 0.0f),
+ /* QUAD_Y_MIN */
+ make_float3(0.0f, -1.0f, 0.0f),
+ /* QUAD_Y_MAX */
+ make_float3(0.0f, 1.0f, 0.0f),
+ /* QUAD_Z_MIN */
+ make_float3(0.0f, 0.0f, -1.0f),
+ /* QUAD_Z_MAX */
+ make_float3(0.0f, 0.0f, 1.0f),
+};
+
+static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData> &quads, int face_index)
+{
+ size_t vertex_offset = vertices.size();
+
+ QuadData quad;
+ quad.v0 = vertex_offset + 0;
+ quad.v1 = vertex_offset + 1;
+ quad.v2 = vertex_offset + 2;
+ quad.v3 = vertex_offset + 3;
+ quad.normal = quads_normals[face_index];
+
+ quads.push_back(quad);
+
+ vertices.push_back(corners[quads_indices[face_index][0]]);
+ vertices.push_back(corners[quads_indices[face_index][1]]);
+ vertices.push_back(corners[quads_indices[face_index][2]]);
+ vertices.push_back(corners[quads_indices[face_index][3]]);
+}
+
+struct VolumeParams {
+ int3 resolution;
+ float3 cell_size;
+ float3 start_point;
+ int pad_size;
+};
+
+static const int CUBE_SIZE = 8;
+
+/* Create a mesh from a volume.
+ *
+ * The way the algorithm works is as follows:
+ *
+ * - the coordinates of active voxels from a dense volume (or 3d image) are
+ * gathered inside an auxialliary volume.
+ * - each set of coordinates of an CUBE_SIZE cube are mapped to the same
+ * coordinate of the auxilliary volume.
+ * - quads are created between active and non-active voxels in the auxialliary
+ * volume to generate a tight mesh around the volume.
+ */
+class VolumeMeshBuilder {
+ /* Auxilliary volume that is used to check if a node already added. */
+ vector<char> grid;
+
+ /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE
+ * of the original volume on each axis. */
+ int3 res;
+
+ size_t number_of_nodes;
+
+ /* Offset due to padding in the original grid. Padding will transform the
+ * coordinates of the original grid from 0...res to -padding...res+padding,
+ * so some coordinates are negative, and we need to properly account for
+ * them. */
+ int3 pad_offset;
+
+ VolumeParams *params;
+
+public:
+ VolumeMeshBuilder(VolumeParams *volume_params);
+
+ void add_node(int x, int y, int z);
+
+ void add_node_with_padding(int x, int y, int z);
+
+ void create_mesh(vector<float3> &vertices,
+ vector<int> &indices,
+ vector<float3> &face_normals);
+
+private:
+ void generate_vertices_and_quads(vector<int3> &vertices_is,
+ vector<QuadData> &quads);
+
+ void deduplicate_vertices(vector<int3> &vertices,
+ vector<QuadData> &quads);
+
+ void convert_object_space(const vector<int3> &vertices,
+ vector<float3> &out_vertices);
+
+ void convert_quads_to_tris(const vector<QuadData> &quads,
+ vector<int> &tris,
+ vector<float3> &face_normals);
+};
+
+VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
+{
+ params = volume_params;
+ number_of_nodes = 0;
+
+ const size_t x = divide_up(params->resolution.x, CUBE_SIZE);
+ const size_t y = divide_up(params->resolution.y, CUBE_SIZE);
+ const size_t z = divide_up(params->resolution.z, CUBE_SIZE);
+
+ /* Adding 2*pad_size since we pad in both positive and negative directions
+ * along the axis. */
+ const size_t px = divide_up(params->resolution.x + 2*params->pad_size, CUBE_SIZE);
+ const size_t py = divide_up(params->resolution.y + 2*params->pad_size, CUBE_SIZE);
+ const size_t pz = divide_up(params->resolution.z + 2*params->pad_size, CUBE_SIZE);
+
+ res = make_int3(px, py, pz);
+ pad_offset = make_int3(px - x, py - y, pz - z);
+
+ grid.resize(px*py*pz, 0);
+}
+
+void VolumeMeshBuilder::add_node(int x, int y, int z)
+{
+ /* Map coordinates to index space. */
+ const int index_x = (x/CUBE_SIZE) + pad_offset.x;
+ const int index_y = (y/CUBE_SIZE) + pad_offset.y;
+ const int index_z = (z/CUBE_SIZE) + pad_offset.z;
+
+ assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0));
+
+ const size_t index = compute_voxel_index(res, index_x, index_y, index_z);
+
+ /* We already have a node here. */
+ if(grid[index] == 1) {
+ return;
+ }
+
+ ++number_of_nodes;
+
+ grid[index] = 1;
+}
+
+void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z)
+{
+ for(int px = x - params->pad_size; px < x + params->pad_size; ++px) {
+ for(int py = y - params->pad_size; py < y + params->pad_size; ++py) {
+ for(int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) {
+ add_node(px, py, pz);
+ }
+ }
+ }
+}
+
+void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
+ vector<int> &indices,
+ vector<float3> &face_normals)
+{
+ /* We create vertices in index space (is), and only convert them to object
+ * space when done. */
+ vector<int3> vertices_is;
+ vector<QuadData> quads;
+
+ generate_vertices_and_quads(vertices_is, quads);
+
+ deduplicate_vertices(vertices_is, quads);
+
+ convert_object_space(vertices_is, vertices);
+
+ convert_quads_to_tris(quads, indices, face_normals);
+}
+
+void VolumeMeshBuilder::generate_vertices_and_quads(
+ vector<ccl::int3> &vertices_is,
+ vector<QuadData> &quads)
+{
+ /* Overallocation, we could count the number of quads and vertices to create
+ * in a pre-pass if memory becomes an issue. */
+ vertices_is.reserve(number_of_nodes*8);
+ quads.reserve(number_of_nodes*6);
+
+ for(int z = 0; z < res.z; ++z) {
+ for(int y = 0; y < res.y; ++y) {
+ for(int x = 0; x < res.x; ++x) {
+ size_t voxel_index = compute_voxel_index(res, x, y, z);
+ if(grid[voxel_index] == 0) {
+ continue;
+ }
+
+ /* Compute min and max coords of the node in index space. */
+ int3 min = make_int3((x - pad_offset.x)*CUBE_SIZE,
+ (y - pad_offset.y)*CUBE_SIZE,
+ (z - pad_offset.z)*CUBE_SIZE);
+
+ /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
+ int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
+
+ int3 corners[8] = {
+ make_int3(min[0], min[1], min[2]),
+ make_int3(max[0], min[1], min[2]),
+ make_int3(max[0], max[1], min[2]),
+ make_int3(min[0], max[1], min[2]),
+ make_int3(min[0], min[1], max[2]),
+ make_int3(max[0], min[1], max[2]),
+ make_int3(max[0], max[1], max[2]),
+ make_int3(min[0], max[1], max[2]),
+ };
+
+ /* Only create a quad if on the border between an active and
+ * an inactive node.
+ */
+
+ voxel_index = compute_voxel_index(res, x - 1, y, z);
+ if(voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, QUAD_X_MIN);
+ }
+
+ voxel_index = compute_voxel_index(res, x + 1, y, z);
+ if(voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, QUAD_X_MAX);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y - 1, z);
+ if(voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, QUAD_Y_MIN);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y + 1, z);
+ if(voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, QUAD_Y_MAX);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y, z - 1);
+ if(voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, QUAD_Z_MIN);
+ }
+
+ voxel_index = compute_voxel_index(res, x, y, z + 1);
+ if(voxel_index == -1 || grid[voxel_index] == 0) {
+ create_quad(corners, vertices_is, quads, QUAD_Z_MAX);
+ }
+ }
+ }
+ }
+}
+
+void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
+ vector<QuadData> &quads)
+{
+ vector<int3> sorted_vertices = vertices;
+ std::sort(sorted_vertices.begin(), sorted_vertices.end());
+ vector<int3>::iterator it = std::unique(sorted_vertices.begin(), sorted_vertices.end());
+ sorted_vertices.resize(std::distance(sorted_vertices.begin(), it));
+
+ vector<QuadData> new_quads = quads;
+
+ for(size_t i = 0; i < vertices.size(); ++i) {
+ for(size_t j = 0; j < sorted_vertices.size(); ++j) {
+ if(vertices[i] != sorted_vertices[j]) {
+ continue;
+ }
+
+ for(int k = 0; k < quads.size(); ++k) {
+ if(quads[k].v0 == i) {
+ new_quads[k].v0 = j;
+ }
+ else if(quads[k].v1 == i) {
+ new_quads[k].v1 = j;
+ }
+ else if(quads[k].v2 == i) {
+ new_quads[k].v2 = j;
+ }
+ else if(quads[k].v3 == i) {
+ new_quads[k].v3 = j;
+ }
+ }
+
+ break;
+ }
+ }
+
+ vertices = sorted_vertices;
+ quads = new_quads;
+}
+
+void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
+ vector<float3> &out_vertices)
+{
+ out_vertices.reserve(vertices.size());
+
+ for(size_t i = 0; i < vertices.size(); ++i) {
+ float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z);
+ vertex *= params->cell_size;
+ vertex += params->start_point;
+
+ out_vertices.push_back(vertex);
+ }
+}
+
+void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
+ vector<int> &tris,
+ vector<float3> &face_normals)
+{
+ int index_offset = 0;
+ tris.resize(quads.size()*6);
+ face_normals.reserve(quads.size()*2);
+
+ for(size_t i = 0; i < quads.size(); ++i) {
+ tris[index_offset++] = quads[i].v0;
+ tris[index_offset++] = quads[i].v2;
+ tris[index_offset++] = quads[i].v1;
+
+ face_normals.push_back(quads[i].normal);
+
+ tris[index_offset++] = quads[i].v0;
+ tris[index_offset++] = quads[i].v3;
+ tris[index_offset++] = quads[i].v2;
+
+ face_normals.push_back(quads[i].normal);
+ }
+}
+
+/* ************************************************************************** */
+
+struct VoxelAttributeGrid {
+ float *data;
+ int channels;
+};
+
+void MeshManager::create_volume_mesh(Scene *scene,
+ Mesh *mesh,
+ Progress& progress)
+{
+ string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
+ progress.set_status("Updating Mesh", msg);
+
+ vector<VoxelAttributeGrid> voxel_grids;
+
+ /* Compute volume parameters. */
+ VolumeParams volume_params;
+ volume_params.resolution = make_int3(0, 0, 0);
+
+ foreach(Attribute& attr, mesh->attributes.attributes) {
+ if(attr.element != ATTR_ELEMENT_VOXEL) {
+ continue;
+ }
+
+ VoxelAttribute *voxel = attr.data_voxel();
+ device_memory *image_memory = scene->image_manager->image_memory(voxel->slot);
+ int3 resolution = make_int3(image_memory->data_width,
+ image_memory->data_height,
+ image_memory->data_depth);
+
+ if(volume_params.resolution == make_int3(0, 0, 0)) {
+ volume_params.resolution = resolution;
+ }
+ else if(volume_params.resolution != resolution) {
+ VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n";
+ return;
+ }
+
+ VoxelAttributeGrid voxel_grid;
+ voxel_grid.data = static_cast<float*>(image_memory->host_pointer);
+ voxel_grid.channels = image_memory->data_elements;
+ voxel_grids.push_back(voxel_grid);
+ }
+
+ if(voxel_grids.empty()) {
+ return;
+ }
+
+ /* Compute padding. */
+ Shader *volume_shader = NULL;
+ int pad_size = 0;
+
+ foreach(Shader *shader, mesh->used_shaders) {
+ if(!shader->has_volume) {
+ continue;
+ }
+
+ volume_shader = shader;
+
+ if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) {
+ pad_size = max(1, pad_size);
+ }
+ else if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) {
+ pad_size = max(2, pad_size);
+ }
+
+ break;
+ }
+
+ if(!volume_shader) {
+ return;
+ }
+
+ /* Compute start point and cell size from transform. */
+ Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM);
+ const int3 resolution = volume_params.resolution;
+ float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
+ float3 cell_size = make_float3(1.0f/resolution.x,
+ 1.0f/resolution.y,
+ 1.0f/resolution.z);
+
+ if(attr) {
+ const Transform *tfm = attr->data_transform();
+ const Transform itfm = transform_inverse(*tfm);
+ start_point = transform_point(&itfm, start_point);
+ cell_size = transform_direction(&itfm, cell_size);
+ }
+
+ volume_params.start_point = start_point;
+ volume_params.cell_size = cell_size;
+ volume_params.pad_size = pad_size;
+
+ /* Build bounding mesh around non-empty volume cells. */
+ VolumeMeshBuilder builder(&volume_params);
+ const float isovalue = mesh->volume_isovalue;
+
+ for(int z = 0; z < resolution.z; ++z) {
+ for(int y = 0; y < resolution.y; ++y) {
+ for(int x = 0; x < resolution.x; ++x) {
+ size_t voxel_index = compute_voxel_index(resolution, x, y, z);
+
+ for(size_t i = 0; i < voxel_grids.size(); ++i) {
+ const VoxelAttributeGrid &voxel_grid = voxel_grids[i];
+
+ if(voxel_grid.channels == 1) {
+ if(voxel_grid.data[voxel_index] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ break;
+ }
+ }
+ else if(voxel_grid.channels == 3) {
+ voxel_index = compute_voxel_index(resolution, x*3, y, z);
+
+ if(voxel_grid.data[voxel_index] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ break;
+ }
+
+ if(voxel_grid.data[voxel_index + 1] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ break;
+ }
+
+ if(voxel_grid.data[voxel_index + 2] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ break;
+ }
+ }
+ else if(voxel_grid.channels == 4) {
+ voxel_index = compute_voxel_index(resolution, x*4, y, z);
+
+ /* check alpha first */
+ if(voxel_grid.data[voxel_index + 3] < isovalue) {
+ continue;
+ }
+
+ if(voxel_grid.data[voxel_index] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ continue;
+ }
+
+ if(voxel_grid.data[voxel_index + 1] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ continue;
+ }
+
+ if(voxel_grid.data[voxel_index + 2] >= isovalue) {
+ builder.add_node_with_padding(x, y, z);
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Create mesh. */
+ vector<float3> vertices;
+ vector<int> indices;
+ vector<float3> face_normals;
+ builder.create_mesh(vertices, indices, face_normals);
+
+ mesh->clear(true);
+ mesh->reserve_mesh(vertices.size(), indices.size()/3);
+ mesh->used_shaders.push_back(volume_shader);
+
+ for(size_t i = 0; i < vertices.size(); ++i) {
+ mesh->add_vertex(vertices[i]);
+ }
+
+ for(size_t i = 0; i < indices.size(); i += 3) {
+ mesh->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
+ }
+
+ Attribute *attr_fN = mesh->attributes.add(ATTR_STD_FACE_NORMAL);
+ float3 *fN = attr_fN->data_float3();
+
+ for(size_t i = 0; i < face_normals.size(); ++i) {
+ fN[i] = face_normals[i];
+ }
+
+ /* Print stats. */
+ VLOG(1) << "Memory usage volume mesh: "
+ << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
+ << "Mb.";
+
+ VLOG(1) << "Memory usage volume grid: "
+ << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
+ << "Mb.";
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 48613a9324c..d732189af66 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -117,8 +117,7 @@ Transform TextureMapping::compute_transform()
case NORMAL:
/* no translation for normals, and inverse transpose */
mat = rmat*smat;
- mat = transform_inverse(mat);
- mat = transform_transpose(mat);
+ mat = transform_transposed_inverse(mat);
break;
}
@@ -153,7 +152,6 @@ void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_ou
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
- compiler.add_node(tfm.w);
if(use_minmax) {
compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
@@ -193,9 +191,7 @@ void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in,
void TextureMapping::compile(OSLCompiler &compiler)
{
if(!skip()) {
- Transform tfm = transform_transpose(compute_transform());
-
- compiler.parameter("mapping", tfm);
+ compiler.parameter("mapping", compute_transform());
compiler.parameter("use_mapping", 1);
}
}
@@ -208,7 +204,7 @@ NODE_DEFINE(ImageTextureNode)
TEXTURE_MAPPING_DEFINE(ImageTextureNode);
- SOCKET_STRING(filename, "Filename", ustring(""));
+ SOCKET_STRING(filename, "Filename", ustring());
static NodeEnum color_space_enum;
color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
@@ -302,17 +298,17 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
- bool is_float_bool;
+ ImageMetaData metadata;
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
- is_float_bool,
- is_linear,
interpolation,
extension,
- use_alpha);
- is_float = (int)is_float_bool;
+ use_alpha,
+ metadata);
+ is_float = metadata.is_float;
+ is_linear = metadata.is_linear;
}
if(slot != -1) {
@@ -363,26 +359,22 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
+ ImageMetaData metadata;
if(builtin_data == NULL) {
- ImageDataType type;
- bool builtin_free_cache;
- type = image_manager->get_image_metadata(filename.string(), NULL, is_linear, builtin_free_cache);
- if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4)
- is_float = 1;
+ image_manager->get_image_metadata(filename.string(), NULL, metadata);
}
else {
- bool is_float_bool;
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
- is_float_bool,
- is_linear,
interpolation,
extension,
- use_alpha);
- is_float = (int)is_float_bool;
+ use_alpha,
+ metadata);
}
+ is_float = metadata.is_float;
+ is_linear = metadata.is_linear;
}
if(slot == -1) {
@@ -419,7 +411,7 @@ NODE_DEFINE(EnvironmentTextureNode)
TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
- SOCKET_STRING(filename, "Filename", ustring(""));
+ SOCKET_STRING(filename, "Filename", ustring());
static NodeEnum color_space_enum;
color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
@@ -501,17 +493,17 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(slot == -1) {
- bool is_float_bool;
+ ImageMetaData metadata;
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
- is_float_bool,
- is_linear,
interpolation,
EXTENSION_REPEAT,
- use_alpha);
- is_float = (int)is_float_bool;
+ use_alpha,
+ metadata);
+ is_float = metadata.is_float;
+ is_linear = metadata.is_linear;
}
if(slot != -1) {
@@ -553,26 +545,22 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
*/
image_manager = compiler.image_manager;
if(is_float == -1) {
+ ImageMetaData metadata;
if(builtin_data == NULL) {
- ImageDataType type;
- bool builtin_free_cache;
- type = image_manager->get_image_metadata(filename.string(), NULL, is_linear, builtin_free_cache);
- if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4)
- is_float = 1;
+ image_manager->get_image_metadata(filename.string(), NULL, metadata);
}
else {
- bool is_float_bool;
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
- is_float_bool,
- is_linear,
interpolation,
EXTENSION_REPEAT,
- use_alpha);
- is_float = (int)is_float_bool;
+ use_alpha,
+ metadata);
}
+ is_float = metadata.is_float;
+ is_linear = metadata.is_linear;
}
if(slot == -1) {
@@ -1348,7 +1336,7 @@ NODE_DEFINE(PointDensityTextureNode)
{
NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER);
- SOCKET_STRING(filename, "Filename", ustring(""));
+ SOCKET_STRING(filename, "Filename", ustring());
static NodeEnum space_enum;
space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
@@ -1421,13 +1409,13 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
if(use_density || use_color) {
if(slot == -1) {
- bool is_float, is_linear;
+ ImageMetaData metadata;
slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
- is_float, is_linear,
interpolation,
EXTENSION_CLIP,
- true);
+ true,
+ metadata);
}
if(slot != -1) {
@@ -1442,7 +1430,6 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
- compiler.add_node(tfm.w);
}
}
else {
@@ -1473,20 +1460,20 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
if(use_density || use_color) {
if(slot == -1) {
- bool is_float, is_linear;
+ ImageMetaData metadata;
slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
- is_float, is_linear,
interpolation,
EXTENSION_CLIP,
- true);
+ true,
+ metadata);
}
if(slot != -1) {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
- compiler.parameter("mapping", transform_transpose(tfm));
+ compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
}
compiler.parameter(this, "interpolation");
@@ -1566,8 +1553,7 @@ void MappingNode::compile(SVMCompiler& compiler)
void MappingNode::compile(OSLCompiler& compiler)
{
- Transform tfm = transform_transpose(tex_mapping.compute_transform());
- compiler.parameter("Matrix", tfm);
+ compiler.parameter("Matrix", tex_mapping.compute_transform());
compiler.parameter_point("mapping_min", tex_mapping.min);
compiler.parameter_point("mapping_max", tex_mapping.max);
compiler.parameter("use_minmax", tex_mapping.use_minmax);
@@ -1872,7 +1858,7 @@ NODE_DEFINE(AnisotropicBsdfNode)
SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
@@ -1932,7 +1918,7 @@ NODE_DEFINE(GlossyBsdfNode)
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
- SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
@@ -2844,6 +2830,120 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_scatter_volume");
}
+/* Principled Volume Closure */
+
+NODE_DEFINE(PrincipledVolumeNode)
+{
+ NodeType* type = NodeType::add("principled_volume", create, NodeType::SHADER);
+
+ SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring());
+ SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring());
+ SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring());
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f));
+ SOCKET_IN_FLOAT(density, "Density", 1.0f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
+ SOCKET_IN_COLOR(absorption_color, "Absorption Color", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
+ SOCKET_IN_COLOR(emission_color, "Emission Color", make_float3(1.0f, 1.0f, 1.0f));
+ SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f);
+ SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", make_float3(1.0f, 1.0f, 1.0f));
+ SOCKET_IN_FLOAT(temperature, "Temperature", 1500.0f);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
+PrincipledVolumeNode::PrincipledVolumeNode()
+: VolumeNode(node_type)
+{
+ closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+}
+
+void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if(shader->has_volume) {
+ ShaderInput *density_in = input("Density");
+ ShaderInput *blackbody_in = input("Blackbody Intensity");
+
+ if(density_in->link || density > 0.0f) {
+ attributes->add_standard(density_attribute);
+ attributes->add_standard(color_attribute);
+ }
+
+ if(blackbody_in->link || blackbody_intensity > 0.0f) {
+ attributes->add_standard(temperature_attribute);
+ }
+
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void PrincipledVolumeNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *density_in = input("Density");
+ ShaderInput *anisotropy_in = input("Anisotropy");
+ ShaderInput *absorption_color_in = input("Absorption Color");
+ ShaderInput *emission_in = input("Emission Strength");
+ ShaderInput *emission_color_in = input("Emission Color");
+ ShaderInput *blackbody_in = input("Blackbody Intensity");
+ ShaderInput *blackbody_tint_in = input("Blackbody Tint");
+ ShaderInput *temperature_in = input("Temperature");
+
+ if(color_in->link)
+ compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
+ else
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
+
+ compiler.add_node(NODE_PRINCIPLED_VOLUME,
+ compiler.encode_uchar4(
+ compiler.stack_assign_if_linked(density_in),
+ compiler.stack_assign_if_linked(anisotropy_in),
+ compiler.stack_assign(absorption_color_in),
+ compiler.closure_mix_weight_offset()),
+ compiler.encode_uchar4(
+ compiler.stack_assign_if_linked(emission_in),
+ compiler.stack_assign(emission_color_in),
+ compiler.stack_assign_if_linked(blackbody_in),
+ compiler.stack_assign(temperature_in)),
+ compiler.stack_assign(blackbody_tint_in));
+
+ int attr_density = compiler.attribute_standard(density_attribute);
+ int attr_color = compiler.attribute_standard(color_attribute);
+ int attr_temperature = compiler.attribute_standard(temperature_attribute);
+
+ compiler.add_node(
+ __float_as_int(density),
+ __float_as_int(anisotropy),
+ __float_as_int(emission_strength),
+ __float_as_int(blackbody_intensity));
+
+ compiler.add_node(
+ attr_density,
+ attr_color,
+ attr_temperature);
+}
+
+void PrincipledVolumeNode::compile(OSLCompiler& compiler)
+{
+ if(Attribute::name_standard(density_attribute.c_str())) {
+ density_attribute = ustring("geom:" + density_attribute.string());
+ }
+ if(Attribute::name_standard(color_attribute.c_str())) {
+ color_attribute = ustring("geom:" + color_attribute.string());
+ }
+ if(Attribute::name_standard(temperature_attribute.c_str())) {
+ temperature_attribute = ustring("geom:" + temperature_attribute.string());
+ }
+
+ compiler.add(this, "node_principled_volume");
+}
+
/* Hair BSDF Closure */
NODE_DEFINE(HairBsdfNode)
@@ -3114,7 +3214,6 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
compiler.add_node(ob_itfm.x);
compiler.add_node(ob_itfm.y);
compiler.add_node(ob_itfm.z);
- compiler.add_node(ob_itfm.w);
}
}
@@ -3153,7 +3252,7 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.parameter("is_volume", true);
compiler.parameter(this, "use_transform");
- Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
+ Transform ob_itfm = transform_transposed_inverse(ob_tfm);
compiler.parameter("object_itfm", ob_itfm);
compiler.parameter(this, "from_dupli");
@@ -3167,7 +3266,7 @@ NODE_DEFINE(UVMapNode)
{
NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER);
- SOCKET_IN_STRING(attribute, "attribute", ustring(""));
+ SOCKET_STRING(attribute, "attribute", ustring());
SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
SOCKET_OUT_POINT(UV, "UV");
@@ -3463,7 +3562,7 @@ NODE_DEFINE(ParticleInfoNode)
{
NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER);
- SOCKET_OUT_FLOAT(random, "Index");
+ SOCKET_OUT_FLOAT(index, "Index");
SOCKET_OUT_FLOAT(random, "Random");
SOCKET_OUT_FLOAT(age, "Age");
SOCKET_OUT_FLOAT(lifetime, "Lifetime");
@@ -3576,7 +3675,7 @@ NODE_DEFINE(HairInfoNode)
SOCKET_OUT_FLOAT(is_strand, "Is Strand");
SOCKET_OUT_FLOAT(intercept, "Intercept");
SOCKET_OUT_FLOAT(thickness, "Thickness");
- SOCKET_OUT_NORMAL(tangent Normal, "Tangent Normal");
+ SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
#if 0 /*output for minimum hair width transparency - deactivated */
SOCKET_OUT_FLOAT(fade, "Fade");
#endif
@@ -4465,7 +4564,7 @@ NODE_DEFINE(AttributeNode)
{
NodeType* type = NodeType::add("attribute", create, NodeType::SHADER);
- SOCKET_STRING(attribute, "Attribute", ustring(""));
+ SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_VECTOR(vector, "Vector");
@@ -4486,16 +4585,12 @@ void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
ShaderOutput *fac_out = output("Fac");
if(!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) {
- AttributeStandard std = Attribute::name_standard(attribute.c_str());
-
- if(std != ATTR_STD_NONE)
- attributes->add(std);
- else
- attributes->add(attribute);
+ attributes->add_standard(attribute);
}
- if(shader->has_volume)
+ if(shader->has_volume) {
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
ShaderNode::attributes(shader, attributes);
}
@@ -4506,13 +4601,7 @@ void AttributeNode::compile(SVMCompiler& compiler)
ShaderOutput *vector_out = output("Vector");
ShaderOutput *fac_out = output("Fac");
ShaderNodeType attr_node = NODE_ATTR;
- AttributeStandard std = Attribute::name_standard(attribute.c_str());
- int attr;
-
- if(std != ATTR_STD_NONE)
- attr = compiler.attribute(std);
- else
- attr = compiler.attribute(attribute);
+ int attr = compiler.attribute_standard(attribute);;
if(bump == SHADER_BUMP_DX)
attr_node = NODE_ATTR_BUMP_DX;
@@ -5470,7 +5559,7 @@ NODE_DEFINE(NormalMapNode)
space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL);
- SOCKET_STRING(attribute, "Attribute", ustring(""));
+ SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
@@ -5489,7 +5578,7 @@ NormalMapNode::NormalMapNode()
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
- if(attribute == ustring("")) {
+ if(attribute.empty()) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
}
@@ -5512,7 +5601,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
int attr = 0, attr_sign = 0;
if(space == NODE_NORMAL_MAP_TANGENT) {
- if(attribute == ustring("")) {
+ if(attribute.empty()) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
}
@@ -5534,7 +5623,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
void NormalMapNode::compile(OSLCompiler& compiler)
{
if(space == NODE_NORMAL_MAP_TANGENT) {
- if(attribute == ustring("")) {
+ if(attribute.empty()) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
}
@@ -5565,7 +5654,7 @@ NODE_DEFINE(TangentNode)
axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
- SOCKET_STRING(attribute, "Attribute", ustring(""));
+ SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_OUT_NORMAL(tangent, "Tangent");
@@ -5582,7 +5671,7 @@ void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
if(direction_type == NODE_TANGENT_UVMAP) {
- if(attribute == ustring(""))
+ if(attribute.empty())
attributes->add(ATTR_STD_UV_TANGENT);
else
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
@@ -5600,7 +5689,7 @@ void TangentNode::compile(SVMCompiler& compiler)
int attr;
if(direction_type == NODE_TANGENT_UVMAP) {
- if(attribute == ustring(""))
+ if(attribute.empty())
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
else
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
@@ -5618,7 +5707,7 @@ void TangentNode::compile(SVMCompiler& compiler)
void TangentNode::compile(OSLCompiler& compiler)
{
if(direction_type == NODE_TANGENT_UVMAP) {
- if(attribute == ustring(""))
+ if(attribute.empty())
compiler.parameter("attr_name", ustring("geom:tangent"));
else
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
@@ -5696,6 +5785,15 @@ DisplacementNode::DisplacementNode()
{
}
+void DisplacementNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ if((height - midlevel == 0.0f) || (scale == 0.0f)) {
+ folder.make_zero();
+ }
+ }
+}
+
void DisplacementNode::compile(SVMCompiler& compiler)
{
ShaderInput *height_in = input("Height");
@@ -5731,7 +5829,7 @@ NODE_DEFINE(VectorDisplacementNode)
space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
- SOCKET_STRING(attribute, "Attribute", ustring(""));
+ SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f);
@@ -5747,10 +5845,20 @@ VectorDisplacementNode::VectorDisplacementNode()
{
}
+void VectorDisplacementNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ if((vector == make_float3(0.0f, 0.0f, 0.0f) && midlevel == 0.0f) ||
+ (scale == 0.0f)) {
+ folder.make_zero();
+ }
+ }
+}
+
void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
- if(attribute == ustring("")) {
+ if(attribute.empty()) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
}
@@ -5774,7 +5882,7 @@ void VectorDisplacementNode::compile(SVMCompiler& compiler)
int attr = 0, attr_sign = 0;
if(space == NODE_NORMAL_MAP_TANGENT) {
- if(attribute == ustring("")) {
+ if(attribute.empty()) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
}
@@ -5797,7 +5905,7 @@ void VectorDisplacementNode::compile(SVMCompiler& compiler)
void VectorDisplacementNode::compile(OSLCompiler& compiler)
{
if(space == NODE_NORMAL_MAP_TANGENT) {
- if(attribute == ustring("")) {
+ if(attribute.empty()) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
}
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index f664ebf545d..58c3d472cd3 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -82,6 +82,7 @@ public:
~ImageTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
ImageManager *image_manager;
int is_float;
@@ -112,6 +113,7 @@ public:
~EnvironmentTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
ImageManager *image_manager;
@@ -257,6 +259,7 @@ public:
~PointDensityTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return true; }
@@ -361,6 +364,7 @@ public:
ClosureType get_closure_type() { return distribution; }
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
};
class DiffuseBsdfNode : public BsdfNode {
@@ -394,6 +398,7 @@ public:
bool has_integrator_dependency();
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
};
class TranslucentBsdfNode : public BsdfNode {
@@ -556,6 +561,25 @@ public:
float anisotropy;
};
+class PrincipledVolumeNode : public VolumeNode {
+public:
+ SHADER_NODE_CLASS(PrincipledVolumeNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
+
+ ustring density_attribute;
+ ustring color_attribute;
+ ustring temperature_attribute;
+
+ float anisotropy;
+ float3 absorption_color;
+ float emission_strength;
+ float3 emission_color;
+ float blackbody_intensity;
+ float3 blackbody_tint;
+ float temperature;
+};
+
class HairBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(HairBsdfNode)
@@ -572,6 +596,7 @@ class GeometryNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GeometryNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
float3 normal_osl;
@@ -581,6 +606,7 @@ class TextureCoordinateNode : public ShaderNode {
public:
SHADER_NODE_CLASS(TextureCoordinateNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return use_transform; }
@@ -594,6 +620,7 @@ class UVMapNode : public ShaderNode {
public:
SHADER_NODE_CLASS(UVMapNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
@@ -627,6 +654,7 @@ class ParticleInfoNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ParticleInfoNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
@@ -635,6 +663,7 @@ public:
SHADER_NODE_CLASS(HairInfoNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
virtual int get_feature() {
@@ -796,6 +825,7 @@ class AttributeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(AttributeNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
ustring attribute;
@@ -993,6 +1023,7 @@ class NormalMapNode : public ShaderNode {
public:
SHADER_NODE_CLASS(NormalMapNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
@@ -1007,6 +1038,7 @@ class TangentNode : public ShaderNode {
public:
SHADER_NODE_CLASS(TangentNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
@@ -1031,6 +1063,7 @@ public:
class DisplacementNode : public ShaderNode {
public:
SHADER_NODE_CLASS(DisplacementNode)
+ void constant_fold(const ConstantFolder& folder);
virtual int get_feature() {
return NODE_FEATURE_BUMP;
}
@@ -1046,6 +1079,8 @@ class VectorDisplacementNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorDisplacementNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency() { return true; }
+ void constant_fold(const ConstantFolder& folder);
virtual int get_feature() {
return NODE_FEATURE_BUMP;
}
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index e03160954bc..138de250c5f 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -33,6 +33,52 @@
CCL_NAMESPACE_BEGIN
+/* Global state of object transform update. */
+
+struct UpdateObjectTransformState {
+ /* Global state used by device_update_object_transform().
+ * Common for both threaded and non-threaded update.
+ */
+
+ /* Type of the motion required by the scene settings. */
+ Scene::MotionType need_motion;
+
+ /* Mapping from particle system to a index in packed particle array.
+ * Only used for read.
+ */
+ map<ParticleSystem*, int> particle_offset;
+
+ /* Mesh area.
+ * Used to avoid calculation of mesh area multiple times. Used for both
+ * read and write. Acquire surface_area_lock to keep it all thread safe.
+ */
+ map<Mesh*, float> surface_area_map;
+
+ /* Motion offsets for each object. */
+ array<uint> motion_offset;
+
+ /* Packed object arrays. Those will be filled in. */
+ uint *object_flag;
+ KernelObject *objects;
+ Transform *object_motion_pass;
+ DecomposedTransform *object_motion;
+
+ /* Flags which will be synchronized to Integrator. */
+ bool have_motion;
+ bool have_curves;
+
+ /* ** Scheduling queue. ** */
+
+ Scene *scene;
+
+ /* Some locks to keep everything thread-safe. */
+ thread_spin_lock queue_lock;
+ thread_spin_lock surface_area_lock;
+
+ /* First unused object index in the queue. */
+ int queue_start_object;
+};
+
/* Object */
NODE_DEFINE(Object)
@@ -48,6 +94,7 @@ NODE_DEFINE(Object)
SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
+ SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
@@ -60,45 +107,54 @@ Object::Object()
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
- motion.pre = transform_empty();
- motion.mid = transform_empty();
- motion.post = transform_empty();
- use_motion = false;
}
Object::~Object()
{
}
-void Object::compute_bounds(bool motion_blur)
+void Object::update_motion()
{
- BoundBox mbounds = mesh->bounds;
+ if(!use_motion()) {
+ return;
+ }
- if(motion_blur && use_motion) {
- MotionTransform mtfm = motion;
+ bool have_motion = false;
- if(hide_on_missing_motion) {
- /* Hide objects that have no valid previous or next transform, for
- * example particle that stop existing. TODO: add support for this
- * case in the kernel so we don't get render artifacts. */
- if(mtfm.pre == transform_empty() ||
- mtfm.post == transform_empty()) {
- bounds = BoundBox::empty;
+ for(size_t i = 0; i < motion.size(); i++) {
+ if(motion[i] == transform_empty()) {
+ if(hide_on_missing_motion) {
+ /* Hide objects that have no valid previous or next
+ * transform, for example particle that stop existing. It
+ * would be better to handle this in the kernel and make
+ * objects invisible outside certain motion steps. */
+ tfm = transform_empty();
+ motion.clear();
return;
}
+ else {
+ /* Otherwise just copy center motion. */
+ motion[i] = tfm;
+ }
}
- /* In case of missing motion information for previous/next frame,
- * assume there is no motion. */
- if(mtfm.pre == transform_empty()) {
- mtfm.pre = tfm;
- }
- if(mtfm.post == transform_empty()) {
- mtfm.post = tfm;
- }
+ /* Test if any of the transforms are actually different. */
+ have_motion = have_motion || motion[i] != tfm;
+ }
+
+ /* Clear motion array if there is no actual motion. */
+ if(!have_motion) {
+ motion.clear();
+ }
+}
+
+void Object::compute_bounds(bool motion_blur)
+{
+ BoundBox mbounds = mesh->bounds;
- MotionTransform decomp;
- transform_motion_decompose(&decomp, &mtfm, &tfm);
+ if(motion_blur && use_motion()) {
+ array<DecomposedTransform> decomp(motion.size());
+ transform_motion_decompose(decomp.data(), motion.data(), motion.size());
bounds = BoundBox::empty;
@@ -108,11 +164,12 @@ void Object::compute_bounds(bool motion_blur)
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
Transform ttfm;
- transform_motion_interpolate(&ttfm, &decomp, t);
+ transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
bounds.grow(mbounds.transformed(&ttfm));
}
}
else {
+ /* No motion blur case. */
if(mesh->transform_applied) {
bounds = mbounds;
}
@@ -132,7 +189,7 @@ void Object::apply_transform(bool apply_to_motion)
/* store matrix to transform later. when accessing these as attributes we
* do not want the transform to be applied for consistency between static
* and dynamic BVH, so we do it on packing. */
- mesh->transform_normal = transform_transpose(transform_inverse(tfm));
+ mesh->transform_normal = transform_transposed_inverse(tfm);
/* apply to mesh vertices */
for(size_t i = 0; i < mesh->verts.size(); i++)
@@ -232,27 +289,30 @@ void Object::tag_update(Scene *scene)
scene->object_manager->need_update = true;
}
-vector<float> Object::motion_times()
+bool Object::use_motion() const
{
- /* compute times at which we sample motion for this object */
- vector<float> times;
-
- if(!mesh || mesh->motion_steps == 1)
- return times;
+ return (motion.size() > 1);
+}
- int motion_steps = mesh->motion_steps;
+float Object::motion_time(int step) const
+{
+ return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
- for(int step = 0; step < motion_steps; step++) {
- if(step != motion_steps / 2) {
- float time = 2.0f * step / (motion_steps - 1) - 1.0f;
- times.push_back(time);
+int Object::motion_step(float time) const
+{
+ if(use_motion()) {
+ for(size_t step = 0; step < motion.size(); step++) {
+ if(time == motion_time(step)) {
+ return step;
+ }
}
}
- return times;
+ return -1;
}
-bool Object::is_traceable()
+bool Object::is_traceable() const
{
/* Mesh itself can be empty,can skip all such objects. */
if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
@@ -289,8 +349,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
Object *ob,
int object_index)
{
- float4 *objects = state->objects;
- float4 *objects_vector = state->objects_vector;
+ KernelObject& kobject = state->objects[object_index];
+ Transform *object_motion_pass = state->object_motion_pass;
Mesh *mesh = ob->mesh;
uint flag = 0;
@@ -357,15 +417,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
}
- /* Pack in texture. */
- int offset = object_index*OBJECT_SIZE;
-
- /* OBJECT_TRANSFORM */
- memcpy(&objects[offset], &tfm, sizeof(float4)*3);
- /* OBJECT_INVERSE_TRANSFORM */
- memcpy(&objects[offset+4], &itfm, sizeof(float4)*3);
- /* OBJECT_PROPERTIES */
- objects[offset+12] = make_float4(surface_area, pass_id, random_number, __int_as_float(particle_index));
+ kobject.tfm = tfm;
+ kobject.itfm = itfm;
+ kobject.surface_area = surface_area;
+ kobject.pass_id = pass_id;
+ kobject.random_number = random_number;
+ kobject.particle_index = particle_index;
+ kobject.motion_offset = 0;
if(mesh->use_motion_blur) {
state->have_motion = true;
@@ -375,50 +433,56 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
if(state->need_motion == Scene::MOTION_PASS) {
- /* Motion transformations, is world/object space depending if mesh
- * comes with deformed position in object space, or if we transform
- * the shading point in world space.
- */
- MotionTransform mtfm = ob->motion;
+ /* Clear motion array if there is no actual motion. */
+ ob->update_motion();
- /* In case of missing motion information for previous/next frame,
- * assume there is no motion. */
- if(!ob->use_motion || mtfm.pre == transform_empty()) {
- mtfm.pre = ob->tfm;
+ /* Compute motion transforms. */
+ Transform tfm_pre, tfm_post;
+ if(ob->use_motion()) {
+ tfm_pre = ob->motion[0];
+ tfm_post = ob->motion[ob->motion.size() - 1];
}
- if(!ob->use_motion || mtfm.post == transform_empty()) {
- mtfm.post = ob->tfm;
+ else {
+ tfm_pre = tfm;
+ tfm_post = tfm;
}
+ /* Motion transformations, is world/object space depending if mesh
+ * comes with deformed position in object space, or if we transform
+ * the shading point in world space. */
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
- mtfm.pre = mtfm.pre * itfm;
- mtfm.post = mtfm.post * itfm;
+ tfm_pre = tfm_pre * itfm;
+ tfm_post = tfm_post * itfm;
}
- memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3);
- memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3);
+ int motion_pass_offset = object_index*OBJECT_MOTION_PASS_SIZE;
+ object_motion_pass[motion_pass_offset + 0] = tfm_pre;
+ object_motion_pass[motion_pass_offset + 1] = tfm_post;
}
else if(state->need_motion == Scene::MOTION_BLUR) {
- if(ob->use_motion) {
- /* decompose transformations for interpolation. */
- MotionTransform decomp;
+ if(ob->use_motion()) {
+ kobject.motion_offset = state->motion_offset[object_index];
- transform_motion_decompose(&decomp, &ob->motion, &ob->tfm);
- memcpy(&objects[offset], &decomp, sizeof(float4)*12);
+ /* Decompose transforms for interpolation. */
+ DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
+ transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
flag |= SD_OBJECT_MOTION;
state->have_motion = true;
}
}
/* Dupli object coords and motion info. */
+ kobject.dupli_generated[0] = ob->dupli_generated[0];
+ kobject.dupli_generated[1] = ob->dupli_generated[1];
+ kobject.dupli_generated[2] = ob->dupli_generated[2];
+ kobject.numkeys = mesh->curve_keys.size();
+ kobject.dupli_uv[0] = ob->dupli_uv[0];
+ kobject.dupli_uv[1] = ob->dupli_uv[1];
int totalsteps = mesh->motion_steps;
- int numsteps = (totalsteps - 1)/2;
- int numverts = mesh->verts.size();
- int numkeys = mesh->curve_keys.size();
-
- objects[offset+13] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], __int_as_float(numkeys));
- objects[offset+14] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], __int_as_float(numsteps), __int_as_float(numverts));
- objects[offset+15] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ kobject.numsteps = (totalsteps - 1)/2;
+ kobject.numverts = mesh->verts.size();;
+ kobject.patch_map_offset = 0;
+ kobject.attribute_map_offset = 0;
/* Object flag. */
if(ob->use_holdout) {
@@ -475,7 +539,6 @@ void ObjectManager::device_update_object_transform_task(
void ObjectManager::device_update_transforms(DeviceScene *dscene,
Scene *scene,
- uint *object_flag,
Progress& progress)
{
UpdateObjectTransformState state;
@@ -485,13 +548,29 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
state.scene = scene;
state.queue_start_object = 0;
- state.object_flag = object_flag;
- state.objects = dscene->objects.alloc(OBJECT_SIZE*scene->objects.size());
+ state.objects = dscene->objects.alloc(scene->objects.size());
+ state.object_flag = dscene->object_flag.alloc(scene->objects.size());
+ state.object_motion = NULL;
+ state.object_motion_pass = NULL;
+
if(state.need_motion == Scene::MOTION_PASS) {
- state.objects_vector = dscene->objects_vector.alloc(OBJECT_VECTOR_SIZE*scene->objects.size());
+ state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size());
}
- else {
- state.objects_vector = NULL;
+ else if(state.need_motion == Scene::MOTION_BLUR) {
+ /* Set object offsets into global object motion array. */
+ uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
+ uint motion_offset = 0;
+
+ foreach(Object *ob, scene->objects) {
+ *motion_offsets = motion_offset;
+ motion_offsets++;
+
+ /* Clear motion array if there is no actual motion. */
+ ob->update_motion();
+ motion_offset += ob->motion.size();
+ }
+
+ state.object_motion = dscene->object_motion.alloc(motion_offset);
}
/* Particle system device offsets
@@ -534,7 +613,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
dscene->objects.copy_to_device();
if(state.need_motion == Scene::MOTION_PASS) {
- dscene->objects_vector.copy_to_device();
+ dscene->object_motion_pass.copy_to_device();
+ }
+ else if(state.need_motion == Scene::MOTION_BLUR) {
+ dscene->object_motion.copy_to_device();
}
dscene->data.bvh.have_motion = state.have_motion;
@@ -554,12 +636,9 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
if(scene->objects.size() == 0)
return;
- /* object info flag */
- uint *object_flag = dscene->object_flag.alloc(scene->objects.size());
-
/* set object transform matrices, before applying static transforms */
progress.set_status("Updating Objects", "Copying Transformations to device");
- device_update_transforms(dscene, scene, object_flag, progress);
+ device_update_transforms(dscene, scene, progress);
if(progress.get_cancel()) return;
@@ -567,7 +646,7 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
/* todo: do before to support getting object level coords? */
if(scene->params.bvh_type == SceneParams::BVH_STATIC) {
progress.set_status("Updating Objects", "Applying Static Transformations");
- apply_static_transforms(dscene, scene, object_flag, progress);
+ apply_static_transforms(dscene, scene, progress);
}
}
@@ -586,9 +665,10 @@ void ObjectManager::device_update_flags(Device *,
if(scene->objects.size() == 0)
return;
- /* object info flag */
+ /* Object info flag. */
uint *object_flag = dscene->object_flag.data();
+ /* Object volume intersection. */
vector<Object *> volume_objects;
bool has_volume_objects = false;
foreach(Object *object, scene->objects) {
@@ -604,9 +684,16 @@ void ObjectManager::device_update_flags(Device *,
foreach(Object *object, scene->objects) {
if(object->mesh->has_volume) {
object_flag[object_index] |= SD_OBJECT_HAS_VOLUME;
+ object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
+
+ foreach(Attribute& attr, object->mesh->attributes.attributes) {
+ if(attr.element == ATTR_ELEMENT_VOXEL) {
+ object_flag[object_index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
+ }
+ }
}
else {
- object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME;
+ object_flag[object_index] &= ~(SD_OBJECT_HAS_VOLUME|SD_OBJECT_HAS_VOLUME_ATTRIBUTES);
}
if(object->is_shadow_catcher) {
object_flag[object_index] |= SD_OBJECT_SHADOW_CATCHER;
@@ -635,7 +722,7 @@ void ObjectManager::device_update_flags(Device *,
++object_index;
}
- /* allocate object flag */
+ /* Copy object flag. */
dscene->object_flag.copy_to_device();
}
@@ -645,27 +732,26 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
return;
}
- uint4* objects = (uint4*)dscene->objects.data();
+ KernelObject *kobjects = dscene->objects.data();
bool update = false;
int object_index = 0;
foreach(Object *object, scene->objects) {
Mesh* mesh = object->mesh;
- int offset = object_index*OBJECT_SIZE + 15;
if(mesh->patch_table) {
uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
- if(objects[offset].x != patch_map_offset) {
- objects[offset].x = patch_map_offset;
+ if(kobjects[object_index].patch_map_offset != patch_map_offset) {
+ kobjects[object_index].patch_map_offset = patch_map_offset;
update = true;
}
}
- if(objects[offset].y != mesh->attr_map_offset) {
- objects[offset].y = mesh->attr_map_offset;
+ if(kobjects[object_index].attribute_map_offset != mesh->attr_map_offset) {
+ kobjects[object_index].attribute_map_offset = mesh->attr_map_offset;
update = true;
}
@@ -680,11 +766,12 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
void ObjectManager::device_free(Device *, DeviceScene *dscene)
{
dscene->objects.free();
- dscene->objects_vector.free();
+ dscene->object_motion_pass.free();
+ dscene->object_motion.free();
dscene->object_flag.free();
}
-void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress)
+void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress)
{
/* todo: normals and displacement should be done before applying transform! */
/* todo: create objects/meshes in right order! */
@@ -708,6 +795,8 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
if(progress.get_cancel()) return;
+ uint *object_flag = dscene->object_flag.data();
+
/* apply transforms for objects with single user meshes */
foreach(Object *object, scene->objects) {
/* Annoying feedback loop here: we can't use is_instanced() because
@@ -718,7 +807,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
!object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
{
- if(!(motion_blur && object->use_motion)) {
+ if(!(motion_blur && object->use_motion())) {
if(!object->mesh->transform_applied) {
object->apply_transform(apply_to_motion);
object->mesh->transform_applied = true;
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index acdb1b64123..c7212ae25f9 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -35,6 +35,7 @@ class ParticleSystem;
class Progress;
class Scene;
struct Transform;
+struct UpdateObjectTransformState;
/* Object */
@@ -49,8 +50,7 @@ public:
int pass_id;
vector<ParamValue> attributes;
uint visibility;
- MotionTransform motion;
- bool use_motion;
+ array<Transform> motion;
bool hide_on_missing_motion;
bool use_holdout;
bool is_shadow_catcher;
@@ -69,12 +69,17 @@ public:
void compute_bounds(bool motion_blur);
void apply_transform(bool apply_to_motion);
- vector<float> motion_times();
+ /* Convert between normalized -1..1 motion time and index
+ * in the motion array. */
+ bool use_motion() const;
+ float motion_time(int step) const;
+ int motion_step(float time) const;
+ void update_motion();
/* Check whether object is traceable and it worth adding it to
* kernel scene.
*/
- bool is_traceable();
+ bool is_traceable() const;
/* Combine object's visibility with all possible internal run-time
* determined flags which denotes trace-time visibility.
@@ -95,7 +100,6 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_transforms(DeviceScene *dscene,
Scene *scene,
- uint *object_flag,
Progress& progress);
void device_update_flags(Device *device,
@@ -109,49 +113,9 @@ public:
void tag_update(Scene *scene);
- void apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
+ void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress);
protected:
- /* Global state of object transform update. */
- struct UpdateObjectTransformState {
- /* Global state used by device_update_object_transform().
- * Common for both threaded and non-threaded update.
- */
-
- /* Type of the motion required by the scene settings. */
- Scene::MotionType need_motion;
-
- /* Mapping from particle system to a index in packed particle array.
- * Only used for read.
- */
- map<ParticleSystem*, int> particle_offset;
-
- /* Mesh area.
- * Used to avoid calculation of mesh area multiple times. Used for both
- * read and write. Acquire surface_area_lock to keep it all thread safe.
- */
- map<Mesh*, float> surface_area_map;
-
- /* Packed object arrays. Those will be filled in. */
- uint *object_flag;
- float4 *objects;
- float4 *objects_vector;
-
- /* Flags which will be synchronized to Integrator. */
- bool have_motion;
- bool have_curves;
-
- /* ** Scheduling queue. ** */
-
- Scene *scene;
-
- /* Some locks to keep everything thread-safe. */
- thread_spin_lock queue_lock;
- thread_spin_lock surface_area_lock;
-
- /* First unused object index in the queue. */
- int queue_start_object;
- };
void device_update_object_transform(UpdateObjectTransformState *state,
Object *ob,
const int object_index);
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 5c5ac6e2be9..f1a22350060 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -34,6 +34,7 @@
#include "util/util_md5.h"
#include "util/util_path.h"
#include "util/util_progress.h"
+#include "util/util_projection.h"
#endif
@@ -233,18 +234,25 @@ void OSLShaderManager::shading_system_init()
"glossy", /* PATH_RAY_GLOSSY */
"singular", /* PATH_RAY_SINGULAR */
"transparent", /* PATH_RAY_TRANSPARENT */
+
"shadow", /* PATH_RAY_SHADOW_OPAQUE_NON_CATCHER */
"shadow", /* PATH_RAY_SHADOW_OPAQUE_CATCHER */
"shadow", /* PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER */
"shadow", /* PATH_RAY_SHADOW_TRANSPARENT_CATCHER */
"__unused__",
+ "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
+ "__unused__",
+
"__unused__",
"diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
"__unused__",
"__unused__",
- "__unused__", /* PATH_RAY_SINGLE_PASS_DONE */
- "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
};
const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]);
@@ -737,6 +745,10 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
current_shader->has_object_dependency = true;
}
+ if(node->has_attribute_dependency()) {
+ current_shader->has_attribute_dependency = true;
+ }
+
if(node->has_integrator_dependency()) {
current_shader->has_integrator_dependency = true;
}
@@ -821,7 +833,9 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
case SocketType::TRANSFORM:
{
Transform value = node->get_transform(socket);
- ss->Parameter(uname, TypeDesc::TypeMatrix, &value);
+ ProjectionTransform projection(value);
+ projection = projection_transpose(projection);
+ ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
break;
}
case SocketType::BOOLEAN_ARRAY:
@@ -889,7 +903,11 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
case SocketType::TRANSFORM_ARRAY:
{
const array<Transform>& value = node->get_transform_array(socket);
- ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data());
+ array<ProjectionTransform> fvalue(value.size());
+ for(size_t i = 0; i < value.size(); i++) {
+ fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
+ }
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
break;
}
case SocketType::CLOSURE:
@@ -956,7 +974,9 @@ void OSLCompiler::parameter(const char *name, ustring s)
void OSLCompiler::parameter(const char *name, const Transform& tfm)
{
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&tfm);
+ ProjectionTransform projection(tfm);
+ projection = projection_transpose(projection);
+ ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&projection);
}
void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
@@ -984,6 +1004,14 @@ void OSLCompiler::parameter_color_array(const char *name, const array<float3>& f
ss->Parameter(name, type, table.data());
}
+void OSLCompiler::parameter_attribute(const char *name, ustring s)
+{
+ if(Attribute::name_standard(s.c_str()))
+ parameter(name, (string("geom:") + s.c_str()).c_str());
+ else
+ parameter(name, s.c_str());
+}
+
void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
{
ShaderNode *node = (input->link)? input->link->parent: NULL;
@@ -1117,6 +1145,7 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
shader->has_surface_spatial_varying = false;
shader->has_volume_spatial_varying = false;
shader->has_object_dependency = false;
+ shader->has_attribute_dependency = false;
shader->has_integrator_dependency = false;
/* generate surface shader */
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 2be1126fdd3..95e35dd857b 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -140,6 +140,8 @@ public:
void parameter_array(const char *name, const float f[], int arraylen);
void parameter_color_array(const char *name, const array<float3>& f);
+ void parameter_attribute(const char *name, ustring s);
+
ShaderType output_type() { return current_type; }
bool background;
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index 3ee620c9d01..e4be3306d7e 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -62,14 +62,10 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
for(size_t j = 0; j < scene->particle_systems.size(); j++)
num_particles += scene->particle_systems[j]->particles.size();
- float4 *particles = dscene->particles.alloc(PARTICLE_SIZE*num_particles);
+ KernelParticle *kparticles = dscene->particles.alloc(num_particles);
/* dummy particle */
- particles[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- particles[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- particles[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- particles[3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ memset(kparticles, 0, sizeof(KernelParticle));
int i = 1;
for(size_t j = 0; j < scene->particle_systems.size(); j++) {
@@ -78,13 +74,15 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
for(size_t k = 0; k < psys->particles.size(); k++) {
/* pack in texture */
Particle& pa = psys->particles[k];
- int offset = i*PARTICLE_SIZE;
- particles[offset] = make_float4(__uint_as_float(pa.index), pa.age, pa.lifetime, pa.size);
- particles[offset+1] = pa.rotation;
- particles[offset+2] = make_float4(pa.location.x, pa.location.y, pa.location.z, pa.velocity.x);
- particles[offset+3] = make_float4(pa.velocity.y, pa.velocity.z, pa.angular_velocity.x, pa.angular_velocity.y);
- particles[offset+4] = make_float4(pa.angular_velocity.z, 0.0f, 0.0f, 0.0f);
+ kparticles[i].index = pa.index;
+ kparticles[i].age = pa.age;
+ kparticles[i].lifetime = pa.lifetime;
+ kparticles[i].size = pa.size;
+ kparticles[i].rotation = pa.rotation;
+ kparticles[i].location = float3_to_float4(pa.location);
+ kparticles[i].velocity = float3_to_float4(pa.velocity);
+ kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity);
i++;
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index e34601a36a9..ba47e3ab6f8 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -60,19 +60,21 @@ DeviceScene::DeviceScene(Device *device)
curve_keys(device, "__curve_keys", MEM_TEXTURE),
patches(device, "__patches", MEM_TEXTURE),
objects(device, "__objects", MEM_TEXTURE),
- objects_vector(device, "__objects_vector", MEM_TEXTURE),
+ object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE),
+ object_motion(device, "__object_motion", MEM_TEXTURE),
+ object_flag(device, "__object_flag", MEM_TEXTURE),
+ camera_motion(device, "__camera_motion", MEM_TEXTURE),
attributes_map(device, "__attributes_map", MEM_TEXTURE),
attributes_float(device, "__attributes_float", MEM_TEXTURE),
attributes_float3(device, "__attributes_float3", MEM_TEXTURE),
attributes_uchar4(device, "__attributes_uchar4", MEM_TEXTURE),
light_distribution(device, "__light_distribution", MEM_TEXTURE),
- light_data(device, "__light_data", MEM_TEXTURE),
+ lights(device, "__lights", MEM_TEXTURE),
light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_TEXTURE),
light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_TEXTURE),
particles(device, "__particles", MEM_TEXTURE),
svm_nodes(device, "__svm_nodes", MEM_TEXTURE),
- shader_flag(device, "__shader_flag", MEM_TEXTURE),
- object_flag(device, "__object_flag", MEM_TEXTURE),
+ shaders(device, "__shaders", MEM_TEXTURE),
lookup_table(device, "__lookup_table", MEM_TEXTURE),
sobol_directions(device, "__sobol_directions", MEM_TEXTURE)
{
@@ -204,8 +206,7 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Meshes Flags");
- mesh_manager->device_update_flags(device, &dscene, this, progress);
+ mesh_manager->device_update_preprocess(device, this, progress);
if(progress.get_cancel() || device->have_error()) return;
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index ea9485ff230..04bd4735a86 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -86,8 +86,13 @@ public:
device_vector<uint> patches;
/* objects */
- device_vector<float4> objects;
- device_vector<float4> objects_vector;
+ device_vector<KernelObject> objects;
+ device_vector<Transform> object_motion_pass;
+ device_vector<DecomposedTransform> object_motion;
+ device_vector<uint> object_flag;
+
+ /* cameras */
+ device_vector<DecomposedTransform> camera_motion;
/* attributes */
device_vector<uint4> attributes_map;
@@ -96,18 +101,17 @@ public:
device_vector<uchar4> attributes_uchar4;
/* lights */
- device_vector<float4> light_distribution;
- device_vector<float4> light_data;
+ device_vector<KernelLightDistribution> light_distribution;
+ device_vector<KernelLight> lights;
device_vector<float2> light_background_marginal_cdf;
device_vector<float2> light_background_conditional_cdf;
/* particles */
- device_vector<float4> particles;
+ device_vector<KernelParticle> particles;
/* shaders */
device_vector<int4> svm_nodes;
- device_vector<uint> shader_flag;
- device_vector<uint> object_flag;
+ device_vector<KernelShader> shaders;
/* lookup tables */
device_vector<float> lookup_table;
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index e8d9558c38d..bb636dd962a 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -55,7 +55,7 @@ Session::Session(const SessionParams& params_)
device = Device::create(params.device, stats, params.background);
- if(params.background && params.output_path.empty()) {
+ if(params.background && !params.write_render_cb) {
buffers = NULL;
display = NULL;
}
@@ -101,7 +101,7 @@ Session::~Session()
wait();
}
- if(!params.output_path.empty()) {
+ if(params.write_render_cb) {
/* tonemap and write out image if requested */
delete display;
@@ -109,8 +109,10 @@ Session::~Session()
display->reset(buffers->params);
tonemap(params.samples);
- progress.set_status("Writing Image", params.output_path);
- display->write(params.output_path);
+ int w = display->draw_width;
+ int h = display->draw_height;
+ uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h);
+ params.write_render_cb((uchar*)pixels, w, h, 4);
}
/* clean up */
@@ -656,13 +658,13 @@ DeviceRequestedFeatures Session::get_requested_device_features()
*/
requested_features.use_hair = false;
requested_features.use_object_motion = false;
- requested_features.use_camera_motion = scene->camera->use_motion;
+ requested_features.use_camera_motion = scene->camera->use_motion();
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
if(mesh->num_curves()) {
requested_features.use_hair = true;
}
- requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
+ requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur;
requested_features.use_camera_motion |= mesh->use_motion_blur;
#ifdef WITH_OPENSUBDIV
if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 8495d95666b..e63cad0d977 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -45,7 +45,6 @@ public:
DeviceInfo device;
bool background;
bool progressive_refine;
- string output_path;
bool progressive;
bool experimental;
@@ -71,11 +70,15 @@ public:
ShadingSystem shadingsystem;
+ function<bool(const uchar *pixels,
+ int width,
+ int height,
+ int channels)> write_render_cb;
+
SessionParams()
{
background = false;
progressive_refine = false;
- output_path = "";
progressive = false;
experimental = false;
@@ -106,7 +109,6 @@ public:
{ return !(device == params.device
&& background == params.background
&& progressive_refine == params.progressive_refine
- && output_path == params.output_path
/* && samples == params.samples */
&& progressive == params.progressive
&& experimental == params.experimental
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index a1ebb26eba3..ec52c51e337 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -191,6 +191,7 @@ Shader::Shader()
has_surface_spatial_varying = false;
has_volume_spatial_varying = false;
has_object_dependency = false;
+ has_attribute_dependency = false;
has_integrator_dependency = false;
has_volume_connected = false;
@@ -431,14 +432,12 @@ void ShaderManager::device_update_common(Device *device,
Scene *scene,
Progress& /*progress*/)
{
- dscene->shader_flag.free();
+ dscene->shaders.free();
if(scene->shaders.size() == 0)
return;
- uint shader_flag_size = scene->shaders.size()*SHADER_SIZE;
- uint *shader_flag = dscene->shader_flag.alloc(shader_flag_size);
- uint i = 0;
+ KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
bool has_volumes = false;
bool has_transparent_shadow = false;
@@ -463,6 +462,8 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_HAS_ONLY_VOLUME;
if(shader->heterogeneous_volume && shader->has_volume_spatial_varying)
flag |= SD_HETEROGENEOUS_VOLUME;
+ if(shader->has_attribute_dependency)
+ flag |= SD_NEED_ATTRIBUTES;
if(shader->has_bssrdf_bump)
flag |= SD_HAS_BSSRDF_BUMP;
if(device->info.has_volume_decoupled) {
@@ -484,16 +485,17 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_HAS_CONSTANT_EMISSION;
/* regular shader */
- shader_flag[i++] = flag;
- shader_flag[i++] = shader->pass_id;
- shader_flag[i++] = __float_as_int(constant_emission.x);
- shader_flag[i++] = __float_as_int(constant_emission.y);
- shader_flag[i++] = __float_as_int(constant_emission.z);
+ kshader->flags = flag;
+ kshader->pass_id = shader->pass_id;
+ kshader->constant_emission[0] = constant_emission.x;
+ kshader->constant_emission[1] = constant_emission.y;
+ kshader->constant_emission[2] = constant_emission.z;
+ kshader++;
has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}
- dscene->shader_flag.copy_to_device();
+ dscene->shaders.copy_to_device();
/* lookup tables */
KernelTables *ktables = &dscene->data.tables;
@@ -522,7 +524,7 @@ void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *sce
{
scene->lookup_tables->remove_table(&beckmann_table_offset);
- dscene->shader_flag.free();
+ dscene->shaders.free();
}
void ShaderManager::add_default(Scene *scene)
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index 4a48c1347da..abd483caabc 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -121,6 +121,7 @@ public:
bool has_surface_spatial_varying;
bool has_volume_spatial_varying;
bool has_object_dependency;
+ bool has_attribute_dependency;
bool has_integrator_dependency;
/* displacement */
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index b678277433b..c5b4060d5c3 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -399,6 +399,12 @@ uint SVMCompiler::attribute(AttributeStandard std)
return shader_manager->get_attribute_id(std);
}
+uint SVMCompiler::attribute_standard(ustring name)
+{
+ AttributeStandard std = Attribute::name_standard(name.c_str());
+ return (std)? attribute(std): attribute(name);
+}
+
bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
{
/* nasty exception .. */
@@ -447,6 +453,10 @@ void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done)
current_shader->has_object_dependency = true;
}
+ if(node->has_attribute_dependency()) {
+ current_shader->has_attribute_dependency = true;
+ }
+
if(node->has_integrator_dependency()) {
current_shader->has_integrator_dependency = true;
}
@@ -830,6 +840,7 @@ void SVMCompiler::compile(Scene *scene,
shader->has_surface_spatial_varying = false;
shader->has_volume_spatial_varying = false;
shader->has_object_dependency = false;
+ shader->has_attribute_dependency = false;
shader->has_integrator_dependency = false;
/* generate bump shader */
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index 0e9905957c7..18be0fa9a22 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -117,6 +117,7 @@ public:
void add_node(const float4& f);
uint attribute(ustring name);
uint attribute(AttributeStandard std);
+ uint attribute_standard(ustring name);
uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
uint closure_mix_weight_offset() { return mix_weight_offset; }
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 66c4f22a7e2..24043e2231b 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -67,6 +67,7 @@ set(SRC_HEADERS
util_param.h
util_path.h
util_progress.h
+ util_projection.h
util_queue.h
util_rect.h
util_set.h
diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h
index e0a89b539b0..a0a62ae95df 100644
--- a/intern/cycles/util/util_math_float3.h
+++ b/intern/cycles/util/util_math_float3.h
@@ -57,6 +57,7 @@ ccl_device_inline float3 clamp(const float3& a, const float3& mn, const float3&
ccl_device_inline float3 fabs(const float3& a);
ccl_device_inline float3 mix(const float3& a, const float3& b, float t);
ccl_device_inline float3 rcp(const float3& a);
+ccl_device_inline float3 sqrt(const float3& a);
#endif /* !__KERNEL_OPENCL__ */
ccl_device_inline float min3(float3 a);
@@ -270,6 +271,15 @@ ccl_device_inline float3 fabs(const float3& a)
#endif
}
+ccl_device_inline float3 sqrt(const float3& a)
+{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_sqrt_ps(a));
+#else
+ return make_float3(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z));
+#endif
+}
+
ccl_device_inline float3 mix(const float3& a, const float3& b, float t)
{
return a + t*(b - a);
diff --git a/intern/cycles/util/util_math_int3.h b/intern/cycles/util/util_math_int3.h
index fa7a02636de..6eef8517665 100644
--- a/intern/cycles/util/util_math_int3.h
+++ b/intern/cycles/util/util_math_int3.h
@@ -76,6 +76,21 @@ ccl_device_inline int3 clamp(const int3& a, int3& mn, int mx)
clamp(a.z, mn.z, mx));
#endif
}
+
+ccl_device_inline bool operator==(const int3 &a, const int3 &b)
+{
+ return a.x == b.x && a.y == b.y && a.z == b.z;
+}
+
+ccl_device_inline bool operator!=(const int3 &a, const int3 &b)
+{
+ return !(a == b);
+}
+
+ccl_device_inline bool operator<(const int3 &a, const int3 &b)
+{
+ return a.x < b.x && a.y < b.y && a.z < b.z;
+}
#endif /* !__KERNEL_OPENCL__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_projection.h b/intern/cycles/util/util_projection.h
new file mode 100644
index 00000000000..dbcb9877a48
--- /dev/null
+++ b/intern/cycles/util/util_projection.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PROJECTION_H__
+#define __UTIL_PROJECTION_H__
+
+#include "util/util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* 4x4 projection matrix, perspective or orthographic. */
+
+typedef struct ProjectionTransform {
+ float4 x, y, z, w; /* rows */
+
+#ifndef __KERNEL_GPU__
+ ProjectionTransform()
+ {
+ }
+
+ explicit ProjectionTransform(const Transform& tfm)
+ : x(tfm.x),
+ y(tfm.y),
+ z(tfm.z),
+ w(make_float4(0.0f, 0.0f, 0.0f, 1.0f))
+ {
+ }
+#endif
+} ProjectionTransform;
+
+typedef struct PerspectiveMotionTransform {
+ ProjectionTransform pre;
+ ProjectionTransform post;
+} PerspectiveMotionTransform;
+
+/* Functions */
+
+ccl_device_inline float3 transform_perspective(const ProjectionTransform *t, const float3 a)
+{
+ float4 b = make_float4(a.x, a.y, a.z, 1.0f);
+ float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
+ float w = dot(t->w, b);
+
+ return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device_inline float3 transform_perspective_direction(const ProjectionTransform *t, const float3 a)
+{
+ float3 c = make_float3(
+ a.x*t->x.x + a.y*t->x.y + a.z*t->x.z,
+ a.x*t->y.x + a.y*t->y.y + a.z*t->y.z,
+ a.x*t->z.x + a.y*t->z.y + a.z*t->z.z);
+
+ return c;
+}
+
+#ifndef __KERNEL_GPU__
+
+ccl_device_inline Transform projection_to_transform(const ProjectionTransform& a)
+{
+ Transform tfm = {a.x, a.y, a.z};
+ return tfm;
+}
+
+ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform& a)
+{
+ ProjectionTransform t;
+
+ t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
+ t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
+ t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
+ t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
+
+ return t;
+}
+
+ProjectionTransform projection_inverse(const ProjectionTransform& a);
+
+ccl_device_inline ProjectionTransform make_projection(
+ float a, float b, float c, float d,
+ float e, float f, float g, float h,
+ float i, float j, float k, float l,
+ float m, float n, float o, float p)
+{
+ ProjectionTransform t;
+
+ t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
+ t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
+ t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
+ t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
+
+ return t;
+}
+ccl_device_inline ProjectionTransform projection_identity()
+{
+ return make_projection(
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const ProjectionTransform& b)
+{
+ ProjectionTransform c = projection_transpose(b);
+ ProjectionTransform t;
+
+ t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
+ t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
+ t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
+ t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+
+ return t;
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const Transform& b)
+{
+ return a * ProjectionTransform(b);
+}
+
+ccl_device_inline ProjectionTransform operator*(const Transform& a, const ProjectionTransform& b)
+{
+ return ProjectionTransform(a) * b;
+}
+
+ccl_device_inline void print_projection(const char *label, const ProjectionTransform& t)
+{
+ print_float4(label, t.x);
+ print_float4(label, t.y);
+ print_float4(label, t.z);
+ print_float4(label, t.w);
+ printf("\n");
+}
+
+ccl_device_inline ProjectionTransform projection_perspective(float fov, float n, float f)
+{
+ ProjectionTransform persp = make_projection(
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, f / (f - n), -f*n / (f - n),
+ 0, 0, 1, 0);
+
+ float inv_angle = 1.0f/tanf(0.5f*fov);
+
+ Transform scale = transform_scale(inv_angle, inv_angle, 1);
+
+ return scale * persp;
+}
+
+ccl_device_inline ProjectionTransform projection_orthographic(float znear, float zfar)
+{
+ Transform t =
+ transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
+ transform_translate(0.0f, 0.0f, -znear);
+
+ return ProjectionTransform(t);
+}
+
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_PROJECTION_H__ */
+
diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp
index c1270545339..206c3da23eb 100644
--- a/intern/cycles/util/util_transform.cpp
+++ b/intern/cycles/util/util_transform.cpp
@@ -46,6 +46,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "util/util_projection.h"
#include "util/util_transform.h"
#include "util/util_boundbox.h"
@@ -129,9 +130,9 @@ static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
return true;
}
-Transform transform_inverse(const Transform& tfm)
+ProjectionTransform projection_inverse(const ProjectionTransform& tfm)
{
- Transform tfmR = transform_identity();
+ ProjectionTransform tfmR = projection_identity();
float M[4][4], R[4][4];
memcpy(R, &tfmR, sizeof(R));
@@ -145,7 +146,7 @@ Transform transform_inverse(const Transform& tfm)
M[2][2] += 1e-8f;
if(UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
- return transform_identity();
+ return projection_identity();
}
}
@@ -154,6 +155,19 @@ Transform transform_inverse(const Transform& tfm)
return tfmR;
}
+Transform transform_inverse(const Transform& tfm)
+{
+ ProjectionTransform projection(tfm);
+ return projection_to_transform(projection_inverse(projection));
+}
+
+Transform transform_transposed_inverse(const Transform& tfm)
+{
+ ProjectionTransform projection(tfm);
+ ProjectionTransform iprojection = projection_inverse(projection);
+ return projection_to_transform(projection_transpose(iprojection));
+}
+
/* Motion Transform */
float4 transform_to_quat(const Transform& tfm)
@@ -202,14 +216,14 @@ float4 transform_to_quat(const Transform& tfm)
return qt;
}
-static void transform_decompose(Transform *decomp, const Transform *tfm)
+static void transform_decompose(DecomposedTransform *decomp, const Transform *tfm)
{
/* extract translation */
decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f);
/* extract rotation */
Transform M = *tfm;
- M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f; M.w.w = 1.0f;
+ M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f;
Transform R = M;
float norm;
@@ -217,9 +231,9 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
do {
Transform Rnext;
- Transform Rit = transform_inverse(transform_transpose(R));
+ Transform Rit = transform_transposed_inverse(R);
- for(int i = 0; i < 4; i++)
+ for(int i = 0; i < 3; i++)
for(int j = 0; j < 4; j++)
Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
@@ -247,18 +261,18 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z);
}
-void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid)
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
{
- transform_decompose(&decomp->pre, &motion->pre);
- transform_decompose(&decomp->mid, mid);
- transform_decompose(&decomp->post, &motion->post);
-
- /* ensure rotation around shortest angle, negated quaternions are the same
- * but this means we don't have to do the check in quat_interpolate */
- if(dot(decomp->pre.x, decomp->mid.x) < 0.0f)
- decomp->pre.x = -decomp->pre.x;
- if(dot(decomp->mid.x, decomp->post.x) < 0.0f)
- decomp->mid.x = -decomp->mid.x;
+ for(size_t i = 0; i < size; i++) {
+ transform_decompose(decomp + i, motion + i);
+
+ if(i > 0) {
+ /* Ensure rotation around shortest angle, negated quaternions are the same
+ * but this means we don't have to do the check in quat_interpolate */
+ if(dot(decomp[i-1].x, decomp[i].x) < 0.0f)
+ decomp[i-1].x = -decomp[i-1].x;
+ }
+ }
}
Transform transform_from_viewplane(BoundBox2D& viewplane)
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index ac0804a7227..987f4dac777 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -26,10 +26,10 @@
CCL_NAMESPACE_BEGIN
-/* Data Types */
+/* Affine transformation, stored as 4x3 matrix. */
typedef struct Transform {
- float4 x, y, z, w; /* rows */
+ float4 x, y, z;
#ifndef __KERNEL_GPU__
float4 operator[](int i) const { return *(&x + i); }
@@ -37,32 +37,16 @@ typedef struct Transform {
#endif
} Transform;
-/* transform decomposed in rotation/translation/scale. we use the same data
+/* Transform decomposed in rotation/translation/scale. we use the same data
* structure as Transform, and tightly pack decomposition into it. first the
* rotation (4), then translation (3), then 3x3 scale matrix (9). */
-typedef struct ccl_may_alias MotionTransform {
- Transform pre;
- Transform mid;
- Transform post;
-} MotionTransform;
-
-typedef struct PerspectiveMotionTransform {
- Transform pre;
- Transform post;
-} PerspectiveMotionTransform;
+typedef struct DecomposedTransform {
+ float4 x, y, z, w;
+} DecomposedTransform;
/* Functions */
-ccl_device_inline float3 transform_perspective(const Transform *t, const float3 a)
-{
- float4 b = make_float4(a.x, a.y, a.z, 1.0f);
- float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
- float w = dot(t->w, b);
-
- return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
-}
-
ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
{
/* TODO(sergey): Disabled for now, causes crashes in certain cases. */
@@ -73,7 +57,7 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
x = _mm_loadu_ps(&t->x.x);
y = _mm_loadu_ps(&t->y.x);
z = _mm_loadu_ps(&t->z.x);
- w = _mm_loadu_ps(&t->w.x);
+ w = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
_MM_TRANSPOSE4_PS(x, y, z, w);
@@ -129,29 +113,15 @@ ccl_device_inline float3 transform_direction_transposed(const Transform *t, cons
return make_float3(dot(x, a), dot(y, a), dot(z, a));
}
-ccl_device_inline Transform transform_transpose(const Transform a)
-{
- Transform t;
-
- t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
- t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
- t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
- t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
-
- return t;
-}
-
ccl_device_inline Transform make_transform(float a, float b, float c, float d,
float e, float f, float g, float h,
- float i, float j, float k, float l,
- float m, float n, float o, float p)
+ float i, float j, float k, float l)
{
Transform t;
t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
- t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
return t;
}
@@ -165,21 +135,22 @@ ccl_device_inline Transform make_transform_frame(float3 N)
const float3 dy = normalize(cross(N, dx));
return make_transform(dx.x, dx.y, dx.z, 0.0f,
dy.x, dy.y, dy.z, 0.0f,
- N.x , N.y, N.z, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f);
+ N.x , N.y, N.z, 0.0f);
}
#ifndef __KERNEL_GPU__
ccl_device_inline Transform operator*(const Transform a, const Transform b)
{
- Transform c = transform_transpose(b);
- Transform t;
+ float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
+ float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
+ float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
+ float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
- t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
- t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
- t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
- t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+ Transform t;
+ t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
+ t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
+ t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
return t;
}
@@ -189,7 +160,6 @@ ccl_device_inline void print_transform(const char *label, const Transform& t)
print_float4(label, t.x);
print_float4(label, t.y);
print_float4(label, t.z);
- print_float4(label, t.w);
printf("\n");
}
@@ -198,8 +168,7 @@ ccl_device_inline Transform transform_translate(float3 t)
return make_transform(
1, 0, 0, t.x,
0, 1, 0, t.y,
- 0, 0, 1, t.z,
- 0, 0, 0, 1);
+ 0, 0, 1, t.z);
}
ccl_device_inline Transform transform_translate(float x, float y, float z)
@@ -212,8 +181,7 @@ ccl_device_inline Transform transform_scale(float3 s)
return make_transform(
s.x, 0, 0, 0,
0, s.y, 0, 0,
- 0, 0, s.z, 0,
- 0, 0, 0, 1);
+ 0, 0, s.z, 0);
}
ccl_device_inline Transform transform_scale(float x, float y, float z)
@@ -221,21 +189,6 @@ ccl_device_inline Transform transform_scale(float x, float y, float z)
return transform_scale(make_float3(x, y, z));
}
-ccl_device_inline Transform transform_perspective(float fov, float n, float f)
-{
- Transform persp = make_transform(
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, f / (f - n), -f*n / (f - n),
- 0, 0, 1, 0);
-
- float inv_angle = 1.0f/tanf(0.5f*fov);
-
- Transform scale = transform_scale(inv_angle, inv_angle, 1);
-
- return scale * persp;
-}
-
ccl_device_inline Transform transform_rotate(float angle, float3 axis)
{
float s = sinf(angle);
@@ -258,9 +211,7 @@ ccl_device_inline Transform transform_rotate(float angle, float3 axis)
axis.z*axis.x*t - s*axis.y,
axis.z*axis.y*t + s*axis.x,
axis.z*axis.z*t + c,
- 0.0f,
-
- 0.0f, 0.0f, 0.0f, 1.0f);
+ 0.0f);
}
/* Euler is assumed to be in XYZ order. */
@@ -272,12 +223,6 @@ ccl_device_inline Transform transform_euler(float3 euler)
transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
}
-ccl_device_inline Transform transform_orthographic(float znear, float zfar)
-{
- return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
- transform_translate(0.0f, 0.0f, -znear);
-}
-
ccl_device_inline Transform transform_identity()
{
return transform_scale(1.0f, 1.0f, 1.0f);
@@ -306,20 +251,20 @@ ccl_device_inline void transform_set_column(Transform *t, int column, float3 val
}
Transform transform_inverse(const Transform& a);
+Transform transform_transposed_inverse(const Transform& a);
ccl_device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
{
/* the epsilon here is quite arbitrary, but this function is only used for
- * surface area and bump, where we except it to not be so sensitive */
- Transform ttfm = transform_transpose(tfm);
+ * surface area and bump, where we expect it to not be so sensitive */
float eps = 1e-6f;
float sx = len_squared(float4_to_float3(tfm.x));
float sy = len_squared(float4_to_float3(tfm.y));
float sz = len_squared(float4_to_float3(tfm.z));
- float stx = len_squared(float4_to_float3(ttfm.x));
- float sty = len_squared(float4_to_float3(ttfm.y));
- float stz = len_squared(float4_to_float3(ttfm.z));
+ float stx = len_squared(transform_get_column(&tfm, 0));
+ float sty = len_squared(transform_get_column(&tfm, 1));
+ float stz = len_squared(transform_get_column(&tfm, 2));
if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
@@ -357,7 +302,6 @@ ccl_device_inline Transform transform_empty()
return make_transform(
0, 0, 0, 0,
0, 0, 0, 0,
- 0, 0, 0, 0,
0, 0, 0, 0);
}
@@ -414,12 +358,11 @@ ccl_device_inline Transform transform_quick_inverse(Transform M)
R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T));
R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T));
R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T));
- R.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return R;
}
-ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp)
+ccl_device_inline void transform_compose(Transform *tfm, const DecomposedTransform *decomp)
{
/* rotation */
float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
@@ -452,60 +395,30 @@ ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp
tfm->x = make_float4(dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
tfm->y = make_float4(dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
tfm->z = make_float4(dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
- tfm->w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
}
-/* Disabled for now, need arc-length parametrization for constant speed motion.
- * #define CURVED_MOTION_INTERPOLATE */
-
-ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t)
+/* Interpolate from array of decomposed transforms. */
+ccl_device void transform_motion_array_interpolate(Transform *tfm,
+ const ccl_global DecomposedTransform *motion,
+ uint numsteps,
+ float time)
{
- /* possible optimization: is it worth it adding a check to skip scaling?
- * it's probably quite uncommon to have scaling objects. or can we skip
- * just shearing perhaps? */
- Transform decomp;
-
-#ifdef CURVED_MOTION_INTERPOLATE
- /* 3 point bezier curve interpolation for position */
- float3 Ppre = float4_to_float3(motion->pre.y);
- float3 Pmid = float4_to_float3(motion->mid.y);
- float3 Ppost = float4_to_float3(motion->post.y);
-
- float3 Pcontrol = 2.0f*Pmid - 0.5f*(Ppre + Ppost);
- float3 P = Ppre*t*t + Pcontrol*2.0f*t*(1.0f - t) + Ppost*(1.0f - t)*(1.0f - t);
-
- decomp.y.x = P.x;
- decomp.y.y = P.y;
- decomp.y.z = P.z;
-#endif
-
- /* linear interpolation for rotation and scale */
- if(t < 0.5f) {
- t *= 2.0f;
-
- decomp.x = quat_interpolate(motion->pre.x, motion->mid.x, t);
-#ifdef CURVED_MOTION_INTERPOLATE
- decomp.y.w = (1.0f - t)*motion->pre.y.w + t*motion->mid.y.w;
-#else
- decomp.y = (1.0f - t)*motion->pre.y + t*motion->mid.y;
-#endif
- decomp.z = (1.0f - t)*motion->pre.z + t*motion->mid.z;
- decomp.w = (1.0f - t)*motion->pre.w + t*motion->mid.w;
- }
- else {
- t = (t - 0.5f)*2.0f;
-
- decomp.x = quat_interpolate(motion->mid.x, motion->post.x, t);
-#ifdef CURVED_MOTION_INTERPOLATE
- decomp.y.w = (1.0f - t)*motion->mid.y.w + t*motion->post.y.w;
-#else
- decomp.y = (1.0f - t)*motion->mid.y + t*motion->post.y;
-#endif
- decomp.z = (1.0f - t)*motion->mid.z + t*motion->post.z;
- decomp.w = (1.0f - t)*motion->mid.w + t*motion->post.w;
- }
-
- /* compose rotation, translation, scale into matrix */
+ /* Figure out which steps we need to interpolate. */
+ int maxstep = numsteps-1;
+ int step = min((int)(time*maxstep), maxstep-1);
+ float t = time*maxstep - step;
+
+ const ccl_global DecomposedTransform *a = motion + step;
+ const ccl_global DecomposedTransform *b = motion + step + 1;
+
+ /* Interpolate rotation, translation and scale. */
+ DecomposedTransform decomp;
+ decomp.x = quat_interpolate(a->x, b->x, t);
+ decomp.y = (1.0f - t)*a->y + t*b->y;
+ decomp.z = (1.0f - t)*a->z + t*b->z;
+ decomp.w = (1.0f - t)*a->w + t*b->w;
+
+ /* Compose rotation, translation, scale into matrix. */
transform_compose(tfm, &decomp);
}
@@ -513,13 +426,13 @@ ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransfo
class BoundBox2D;
-ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransform& B)
+ccl_device_inline bool operator==(const DecomposedTransform& A, const DecomposedTransform& B)
{
- return (A.pre == B.pre && A.post == B.post);
+ return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
}
float4 transform_to_quat(const Transform& tfm);
-void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid);
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
Transform transform_from_viewplane(BoundBox2D& viewplane);
#endif
diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h
index 625c19c7c46..e98e4e34181 100644
--- a/intern/cycles/util/util_vector.h
+++ b/intern/cycles/util/util_vector.h
@@ -215,6 +215,18 @@ public:
return data_;
}
+ T* resize(size_t newsize, const T& value)
+ {
+ size_t oldsize = size();
+ resize(newsize);
+
+ for(size_t i = oldsize; i < size(); i++) {
+ data_[i] = value;
+ }
+
+ return data_;
+ }
+
void clear()
{
if(data_ != NULL) {
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index 9c06c8a6d67..1eb6c3ba2dc 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -48,6 +48,16 @@
#include <libswscale/swscale.h>
+/* Stupid way to distinguish FFmpeg from Libav:
+ * - FFmpeg's MICRO version starts from 100 and goes up, while
+ * - Libav's micro is always below 100.
+ */
+#if LIBAVCODEC_VERSION_MICRO >= 100
+# define AV_USING_FFMPEG
+#else
+# define AV_USING_LIBAV
+#endif
+
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
# define FFMPEG_HAVE_AVIO 1
#endif
@@ -428,8 +438,45 @@ void av_frame_free(AVFrame **frame)
#endif
FFMPEG_INLINE
-AVRational av_get_r_frame_rate_compat(const AVStream *stream)
+const char* av_get_metadata_key_value(AVDictionary *metadata, const char *key)
{
+ if (metadata == NULL) {
+ return NULL;
+ }
+ AVDictionaryEntry *tag = NULL;
+ while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+ if (!strcmp(tag->key, key)) {
+ return tag->value;
+ }
+ }
+ return NULL;
+}
+
+FFMPEG_INLINE
+bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
+{
+ const char* encoder = av_get_metadata_key_value(ctx->metadata, "ENCODER");
+ if (encoder != NULL && !strncmp(encoder, "Lavf", 4)) {
+ return true;
+ }
+ return false;
+}
+
+FFMPEG_INLINE
+AVRational av_get_r_frame_rate_compat(AVFormatContext *ctx,
+ const AVStream *stream)
+{
+ /* If the video is encoded with FFmpeg and we are decoding with FFmpeg
+ * as well it seems to be more reliable to use r_frame_rate (tbr).
+ *
+ * For other cases we fall back to avg_frame_rate (fps) when possible.
+ */
+#ifdef AV_USING_FFMPEG
+ if (av_check_encoded_with_ffmpeg(ctx)) {
+ return stream->r_frame_rate;
+ }
+#endif
+
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
/* For until r_frame_rate was deprecated use it. */
return stream->r_frame_rate;
diff --git a/intern/gawain/CMakeLists.txt b/intern/gawain/CMakeLists.txt
index 9924daa8cd1..177c76327aa 100644
--- a/intern/gawain/CMakeLists.txt
+++ b/intern/gawain/CMakeLists.txt
@@ -16,12 +16,14 @@ set(SRC
src/gwn_imm_util.c
src/gwn_primitive.c
src/gwn_shader_interface.c
+ src/gwn_vertex_array_id.cpp
src/gwn_vertex_buffer.c
src/gwn_vertex_format.c
gawain/gwn_attr_binding.h
gawain/gwn_attr_binding_private.h
gawain/gwn_batch.h
+ gawain/gwn_batch_private.h
gawain/gwn_buffer_id.h
gawain/gwn_common.h
gawain/gwn_element.h
@@ -30,6 +32,7 @@ set(SRC
gawain/gwn_primitive.h
gawain/gwn_primitive_private.h
gawain/gwn_shader_interface.h
+ gawain/gwn_vertex_array_id.h
gawain/gwn_vertex_buffer.h
gawain/gwn_vertex_format.h
gawain/gwn_vertex_format_private.h
diff --git a/intern/gawain/gawain/gwn_batch.h b/intern/gawain/gawain/gwn_batch.h
index 94cd893f09e..3e90ef091f1 100644
--- a/intern/gawain/gawain/gwn_batch.h
+++ b/intern/gawain/gawain/gwn_batch.h
@@ -23,34 +23,61 @@ typedef enum {
} Gwn_BatchPhase;
#define GWN_BATCH_VBO_MAX_LEN 3
+#define GWN_BATCH_VAO_STATIC_LEN 3
+#define GWN_BATCH_VAO_DYN_ALLOC_COUNT 16
typedef struct Gwn_Batch {
// geometry
Gwn_VertBuf* verts[GWN_BATCH_VBO_MAX_LEN]; // verts[0] is required, others can be NULL
+ Gwn_VertBuf* inst; // instance attribs
Gwn_IndexBuf* elem; // NULL if element list not needed
- Gwn_PrimType prim_type;
GLenum gl_prim_type;
+ // cached values (avoid dereferencing later)
+ GLuint vao_id;
+ GLuint program;
+ const struct Gwn_ShaderInterface* interface;
+
// book-keeping
- GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer)
+ unsigned owns_flag;
+ struct Gwn_Context *context; // used to free all vaos. this implies all vaos were created under the same context.
Gwn_BatchPhase phase;
- bool program_dirty;
bool program_in_use;
- unsigned owns_flag;
- // state
- GLuint program;
- const Gwn_ShaderInterface* interface;
+ // Vao management: remembers all geometry state (vertex attrib bindings & element buffer)
+ // for each shader interface. Start with a static number of vaos and fallback to dynamic count
+ // if necessary. Once a batch goes dynamic it does not go back.
+ bool is_dynamic_vao_count;
+ union {
+ // Static handle count
+ struct {
+ const struct Gwn_ShaderInterface* interfaces[GWN_BATCH_VAO_STATIC_LEN];
+ GLuint vao_ids[GWN_BATCH_VAO_STATIC_LEN];
+ } static_vaos;
+ // Dynamic handle count
+ struct {
+ unsigned count;
+ const struct Gwn_ShaderInterface** interfaces;
+ GLuint* vao_ids;
+ } dynamic_vaos;
+ };
+
+ // XXX This is the only solution if we want to have some data structure using
+ // batches as key to identify nodes. We must destroy these nodes with this callback.
+ void (*free_callback)(struct Gwn_Batch*, void*);
+ void* callback_data;
} Gwn_Batch;
enum {
GWN_BATCH_OWNS_VBO = (1 << 0),
/* each vbo index gets bit-shifted */
+ GWN_BATCH_OWNS_INSTANCES = (1 << 30),
GWN_BATCH_OWNS_INDEX = (1 << 31),
};
Gwn_Batch* GWN_batch_create_ex(Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, unsigned owns_flag);
void GWN_batch_init_ex(Gwn_Batch*, Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, unsigned owns_flag);
+Gwn_Batch* GWN_batch_duplicate(Gwn_Batch* batch_src);
#define GWN_batch_create(prim, verts, elem) \
GWN_batch_create_ex(prim, verts, elem, 0)
@@ -59,19 +86,24 @@ void GWN_batch_init_ex(Gwn_Batch*, Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, un
void GWN_batch_discard(Gwn_Batch*); // verts & elem are not discarded
+void GWN_batch_callback_free_set(Gwn_Batch*, void (*callback)(Gwn_Batch*, void*), void*);
+
+void GWN_batch_instbuf_set(Gwn_Batch*, Gwn_VertBuf*, bool own_vbo); // Instancing
+
int GWN_batch_vertbuf_add_ex(Gwn_Batch*, Gwn_VertBuf*, bool own_vbo);
#define GWN_batch_vertbuf_add(batch, verts) \
GWN_batch_vertbuf_add_ex(batch, verts, false)
+void GWN_batch_program_set_no_use(Gwn_Batch*, GLuint program, const Gwn_ShaderInterface*);
void GWN_batch_program_set(Gwn_Batch*, GLuint program, const Gwn_ShaderInterface*);
-void GWN_batch_program_unset(Gwn_Batch*);
// Entire batch draws with one shader program, but can be redrawn later with another program.
// Vertex shader's inputs must be compatible with the batch's vertex format.
void GWN_batch_program_use_begin(Gwn_Batch*); // call before Batch_Uniform (temp hack?)
void GWN_batch_program_use_end(Gwn_Batch*);
+void GWN_batch_uniform_1ui(Gwn_Batch*, const char* name, int value);
void GWN_batch_uniform_1i(Gwn_Batch*, const char* name, int value);
void GWN_batch_uniform_1b(Gwn_Batch*, const char* name, bool value);
void GWN_batch_uniform_1f(Gwn_Batch*, const char* name, float value);
@@ -84,11 +116,11 @@ void GWN_batch_uniform_4fv(Gwn_Batch*, const char* name, const float data[4]);
void GWN_batch_draw(Gwn_Batch*);
+// This does not bind/unbind shader and does not call gpuBindMatrices()
+void GWN_batch_draw_range_ex(Gwn_Batch*, int v_first, int v_count, bool force_instance);
-void GWN_batch_draw_stupid(Gwn_Batch*, int v_first, int v_count);
-void GWN_batch_draw_stupid_instanced(Gwn_Batch*, Gwn_Batch*, int instance_first, int instance_count);
-void GWN_batch_draw_procedural(Gwn_Batch*, Gwn_PrimType, int v_count);
-
+// Does not even need batch
+void GWN_draw_primitive(Gwn_PrimType, int v_count);
#if 0 // future plans
diff --git a/intern/gawain/gawain/gwn_batch_private.h b/intern/gawain/gawain/gwn_batch_private.h
new file mode 100644
index 00000000000..6503429c237
--- /dev/null
+++ b/intern/gawain/gawain/gwn_batch_private.h
@@ -0,0 +1,30 @@
+
+// Gawain context
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2018 Mike Erwin, Clément Foucault
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gwn_batch.h"
+#include "gwn_context.h"
+#include "gwn_shader_interface.h"
+
+void gwn_batch_remove_interface_ref(Gwn_Batch*, const Gwn_ShaderInterface*);
+void gwn_batch_vao_cache_clear(Gwn_Batch*);
+
+void gwn_context_add_batch(Gwn_Context*, Gwn_Batch*);
+void gwn_context_remove_batch(Gwn_Context*, Gwn_Batch*);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/gawain/gawain/gwn_buffer_id.h b/intern/gawain/gawain/gwn_buffer_id.h
index db5df99f526..6f51ca6905d 100644
--- a/intern/gawain/gawain/gwn_buffer_id.h
+++ b/intern/gawain/gawain/gwn_buffer_id.h
@@ -25,10 +25,6 @@ extern "C" {
GLuint GWN_buf_id_alloc(void);
void GWN_buf_id_free(GLuint buffer_id);
-GLuint GWN_vao_alloc(void);
-void GWN_vao_free(GLuint vao_id);
-
-
#ifdef __cplusplus
}
#endif
diff --git a/intern/gawain/gawain/gwn_context.h b/intern/gawain/gawain/gwn_context.h
new file mode 100644
index 00000000000..3addce762b3
--- /dev/null
+++ b/intern/gawain/gawain/gwn_context.h
@@ -0,0 +1,34 @@
+
+// Gawain context
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2018 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+// This interface allow Gawain to manage VAOs for mutiple context and threads.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gwn_common.h"
+#include "gwn_batch.h"
+#include "gwn_shader_interface.h"
+
+typedef struct Gwn_Context Gwn_Context;
+
+Gwn_Context* GWN_context_create(void);
+void GWN_context_discard(Gwn_Context*);
+
+void GWN_context_active_set(Gwn_Context*);
+Gwn_Context* GWN_context_active_get(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/gawain/gawain/gwn_element.h b/intern/gawain/gawain/gwn_element.h
index 3081305769f..7a28ab183f8 100644
--- a/intern/gawain/gawain/gwn_element.h
+++ b/intern/gawain/gawain/gwn_element.h
@@ -15,6 +15,8 @@
#define GWN_TRACK_INDEX_RANGE 1
+#define GWN_PRIM_RESTART 0xFFFFFFFF
+
typedef enum {
GWN_INDEX_U8, // GL has this, Vulkan does not
GWN_INDEX_U16,
@@ -30,8 +32,8 @@ typedef struct Gwn_IndexBuf {
unsigned max_index;
unsigned base_index;
#endif
- void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated
GLuint vbo_id; // 0 indicates not yet sent to VRAM
+ bool use_prim_restart;
} Gwn_IndexBuf;
void GWN_indexbuf_use(Gwn_IndexBuf*);
@@ -43,17 +45,18 @@ typedef struct Gwn_IndexBufBuilder {
unsigned index_ct;
Gwn_PrimType prim_type;
unsigned* data;
+ bool use_prim_restart;
} Gwn_IndexBufBuilder;
-// supported primitives:
-// GWN_PRIM_POINTS
-// GWN_PRIM_LINES
-// GWN_PRIM_TRIS
+// supports all primitive types.
+void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct, bool use_prim_restart);
+
+// supports only GWN_PRIM_POINTS, GWN_PRIM_LINES and GWN_PRIM_TRIS.
void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned prim_ct, unsigned vertex_ct);
-//void GWN_indexbuf_init_custom(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct);
void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, unsigned v);
+void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder*);
void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, unsigned v);
void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2);
diff --git a/intern/gawain/gawain/gwn_shader_interface.h b/intern/gawain/gawain/gwn_shader_interface.h
index 345ad8d389b..3be2831e539 100644
--- a/intern/gawain/gawain/gwn_shader_interface.h
+++ b/intern/gawain/gawain/gwn_shader_interface.h
@@ -33,7 +33,6 @@ typedef enum {
GWN_UNIFORM_WORLDNORMAL, // mat3 WorldNormalMatrix
GWN_UNIFORM_CAMERATEXCO, // vec4 CameraTexCoFactors
GWN_UNIFORM_ORCO, // vec3 OrcoTexCoFactors[]
- GWN_UNIFORM_CLIPPLANES, // vec4 ClipPlanes[]
GWN_UNIFORM_COLOR, // vec4 color
GWN_UNIFORM_EYE, // vec3 eye
@@ -54,6 +53,7 @@ typedef struct Gwn_ShaderInput {
} Gwn_ShaderInput;
#define GWN_NUM_SHADERINTERFACE_BUCKETS 257
+#define GWN_SHADERINTERFACE_REF_ALLOC_COUNT 16
typedef struct Gwn_ShaderInterface {
GLint program;
@@ -63,6 +63,8 @@ typedef struct Gwn_ShaderInterface {
Gwn_ShaderInput* ubo_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS];
Gwn_ShaderInput* builtin_uniforms[GWN_NUM_UNIFORMS];
char* name_buffer;
+ struct Gwn_Batch** batches; // references to batches using this interface
+ unsigned batches_ct;
} Gwn_ShaderInterface;
Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program_id);
@@ -72,3 +74,7 @@ const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface*, c
const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface*, Gwn_UniformBuiltin);
const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface*, const char* name);
const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface*, const char* name);
+
+// keep track of batches using this interface
+void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface*, struct Gwn_Batch*);
+void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface*, struct Gwn_Batch*);
diff --git a/intern/gawain/gawain/gwn_vertex_array_id.h b/intern/gawain/gawain/gwn_vertex_array_id.h
new file mode 100644
index 00000000000..1c093d428ce
--- /dev/null
+++ b/intern/gawain/gawain/gwn_vertex_array_id.h
@@ -0,0 +1,34 @@
+
+// Gawain buffer IDs
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2018 Mike Erwin, Clément Foucault
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+// Manage GL vertex array IDs in a thread-safe way
+// Use these instead of glGenBuffers & its friends
+// - alloc must be called from a thread that is bound
+// to the context that will be used for drawing with
+// this vao.
+// - free can be called from any thread
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gwn_common.h"
+#include "gwn_context.h"
+
+GLuint GWN_vao_default(void);
+GLuint GWN_vao_alloc(void);
+void GWN_vao_free(GLuint vao_id, Gwn_Context*);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/gawain/gawain/gwn_vertex_buffer.h b/intern/gawain/gawain/gwn_vertex_buffer.h
index 34f12754f40..ddb77368a02 100644
--- a/intern/gawain/gawain/gwn_vertex_buffer.h
+++ b/intern/gawain/gawain/gwn_vertex_buffer.h
@@ -22,29 +22,35 @@
// Is Gwn_VertBuf always used as part of a Gwn_Batch?
+typedef enum {
+ // can be extended to support more types
+ GWN_USAGE_STREAM,
+ GWN_USAGE_STATIC, // do not keep data in memory
+ GWN_USAGE_DYNAMIC
+} Gwn_UsageType;
+
typedef struct Gwn_VertBuf {
Gwn_VertFormat format;
unsigned vertex_ct;
- unsigned alloc_ct; // size in vertex of alloced data
-#if VRAM_USAGE
- unsigned vram_size; // size in byte of data present in the VRAM
-#endif
- unsigned data_dirty : 1; // does the data has been touched since last transfert
- unsigned data_dynamic : 1; // do we keep the RAM allocation for further updates?
- unsigned data_resized : 1; // does the data has been resized since last transfert
- GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated
- GLuint vbo_id; // 0 indicates not yet sent to VRAM
+ bool dirty;
+ GLubyte* data; // NULL indicates data in VRAM (unmapped)
+ GLuint vbo_id; // 0 indicates not yet allocated
+ Gwn_UsageType usage; // usage hint for GL optimisation
} Gwn_VertBuf;
-Gwn_VertBuf* GWN_vertbuf_create(void);
-Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat*);
-Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat*);
+Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType);
+Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat*, Gwn_UsageType);
+
+#define GWN_vertbuf_create_with_format(format) \
+ GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_STATIC)
-void GWN_vertbuf_clear(Gwn_VertBuf*);
void GWN_vertbuf_discard(Gwn_VertBuf*);
-void GWN_vertbuf_init(Gwn_VertBuf*);
-void GWN_vertbuf_init_with_format(Gwn_VertBuf*, const Gwn_VertFormat*);
+void GWN_vertbuf_init(Gwn_VertBuf*, Gwn_UsageType);
+void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf*, const Gwn_VertFormat*, Gwn_UsageType);
+
+#define GWN_vertbuf_init_with_format(verts, format) \
+ GWN_vertbuf_init_with_format_ex(verts, format, GWN_USAGE_STATIC)
unsigned GWN_vertbuf_size_get(const Gwn_VertBuf*);
void GWN_vertbuf_data_alloc(Gwn_VertBuf*, unsigned v_ct);
diff --git a/intern/gawain/gawain/gwn_vertex_format.h b/intern/gawain/gawain/gwn_vertex_format.h
index 911c0605ecc..503c2d03c42 100644
--- a/intern/gawain/gawain/gwn_vertex_format.h
+++ b/intern/gawain/gawain/gwn_vertex_format.h
@@ -14,7 +14,7 @@
#include "gwn_common.h"
#define GWN_VERT_ATTR_MAX_LEN 16
-#define MAX_ATTRIB_NAMES 3
+#define GWN_VERT_ATTR_MAX_NAMES 3
#define GWN_VERT_ATTR_NAME_AVERAGE_LEN 11
#define GWN_VERT_ATTR_NAMES_BUF_LEN ((GWN_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GWN_VERT_ATTR_MAX_LEN)
@@ -39,24 +39,24 @@ typedef enum {
} Gwn_VertFetchMode;
typedef struct Gwn_VertAttr {
+ Gwn_VertFetchMode fetch_mode;
Gwn_VertCompType comp_type;
unsigned gl_comp_type;
unsigned comp_ct; // 1 to 4 or 8 or 12 or 16
unsigned sz; // size in bytes, 1 to 64
unsigned offset; // from beginning of vertex, in bytes
- Gwn_VertFetchMode fetch_mode;
- const char* name[MAX_ATTRIB_NAMES];
- unsigned name_ct;
+ unsigned name_ct; // up to GWN_VERT_ATTR_MAX_NAMES
+ const char* name[GWN_VERT_ATTR_MAX_NAMES];
} Gwn_VertAttr;
typedef struct Gwn_VertFormat {
unsigned attrib_ct; // 0 to 16 (GWN_VERT_ATTR_MAX_LEN)
unsigned name_ct; // total count of active vertex attrib
unsigned stride; // stride in bytes, 1 to 256
+ unsigned name_offset;
bool packed;
- Gwn_VertAttr attribs[GWN_VERT_ATTR_MAX_LEN]; // TODO: variable-size attribs array
char names[GWN_VERT_ATTR_NAMES_BUF_LEN];
- unsigned name_offset;
+ Gwn_VertAttr attribs[GWN_VERT_ATTR_MAX_LEN]; // TODO: variable-size attribs array
} Gwn_VertFormat;
void GWN_vertformat_clear(Gwn_VertFormat*);
diff --git a/intern/gawain/src/gwn_batch.c b/intern/gawain/src/gwn_batch.c
index ec3f98e348c..c720ba967b5 100644
--- a/intern/gawain/src/gwn_batch.c
+++ b/intern/gawain/src/gwn_batch.c
@@ -10,13 +10,56 @@
// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
#include "gwn_batch.h"
+#include "gwn_batch_private.h"
#include "gwn_buffer_id.h"
+#include "gwn_vertex_array_id.h"
#include "gwn_primitive_private.h"
#include <stdlib.h>
+#include <string.h>
// necessary functions from matrix API
extern void gpuBindMatrices(const Gwn_ShaderInterface* shaderface);
-extern bool gpuMatricesDirty(void); // how best to use this here?
+
+static void batch_update_program_bindings(Gwn_Batch* batch, unsigned int v_first);
+
+void gwn_batch_vao_cache_clear(Gwn_Batch* batch)
+ {
+ if (batch->context == NULL)
+ return;
+
+ if (batch->is_dynamic_vao_count)
+ {
+ for (int i = 0; i < batch->dynamic_vaos.count; ++i)
+ {
+ if (batch->dynamic_vaos.vao_ids[i])
+ GWN_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
+ if (batch->dynamic_vaos.interfaces[i])
+ GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface *)batch->dynamic_vaos.interfaces[i], batch);
+ }
+ free(batch->dynamic_vaos.interfaces);
+ free(batch->dynamic_vaos.vao_ids);
+ }
+ else
+ {
+ for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i)
+ {
+ if (batch->static_vaos.vao_ids[i])
+ GWN_vao_free(batch->static_vaos.vao_ids[i], batch->context);
+ if (batch->static_vaos.interfaces[i])
+ GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface *)batch->static_vaos.interfaces[i], batch);
+ }
+ }
+
+ batch->is_dynamic_vao_count = false;
+ for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i)
+ {
+ batch->static_vaos.vao_ids[i] = 0;
+ batch->static_vaos.interfaces[i] = NULL;
+ }
+
+ gwn_context_remove_batch(batch->context, batch);
+ batch->context = NULL;
+ }
Gwn_Batch* GWN_batch_create_ex(
Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem,
@@ -40,11 +83,25 @@ void GWN_batch_init_ex(
batch->verts[0] = verts;
for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v)
batch->verts[v] = NULL;
+ batch->inst = NULL;
batch->elem = elem;
- batch->prim_type = prim_type;
batch->gl_prim_type = convert_prim_type_to_gl(prim_type);
batch->phase = GWN_BATCH_READY_TO_DRAW;
+ batch->is_dynamic_vao_count = false;
batch->owns_flag = owns_flag;
+ batch->free_callback = NULL;
+ }
+
+// This will share the VBOs with the new batch
+Gwn_Batch* GWN_batch_duplicate(Gwn_Batch* batch_src)
+ {
+ Gwn_Batch* batch = GWN_batch_create_ex(GWN_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0);
+
+ batch->gl_prim_type = batch_src->gl_prim_type;
+ for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v)
+ batch->verts[v] = batch_src->verts[v];
+
+ return batch;
}
void GWN_batch_discard(Gwn_Batch* batch)
@@ -52,6 +109,9 @@ void GWN_batch_discard(Gwn_Batch* batch)
if (batch->owns_flag & GWN_BATCH_OWNS_INDEX)
GWN_indexbuf_discard(batch->elem);
+ if (batch->owns_flag & GWN_BATCH_OWNS_INSTANCES)
+ GWN_vertbuf_discard(batch->inst);
+
if ((batch->owns_flag & ~GWN_BATCH_OWNS_INDEX) != 0)
{
for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
@@ -63,16 +123,46 @@ void GWN_batch_discard(Gwn_Batch* batch)
}
}
- if (batch->vao_id)
- GWN_vao_free(batch->vao_id);
+ gwn_batch_vao_cache_clear(batch);
+
+ if (batch->free_callback)
+ batch->free_callback(batch, batch->callback_data);
free(batch);
}
+void GWN_batch_callback_free_set(Gwn_Batch* batch, void (*callback)(Gwn_Batch*, void*), void* user_data)
+ {
+ batch->free_callback = callback;
+ batch->callback_data = user_data;
+ }
+
+void GWN_batch_instbuf_set(Gwn_Batch* batch, Gwn_VertBuf* inst, bool own_vbo)
+ {
+#if TRUST_NO_ONE
+ assert(inst != NULL);
+#endif
+ // redo the bindings
+ gwn_batch_vao_cache_clear(batch);
+
+ if (batch->inst != NULL && (batch->owns_flag & GWN_BATCH_OWNS_INSTANCES))
+ GWN_vertbuf_discard(batch->inst);
+
+ batch->inst = inst;
+
+ if (own_vbo)
+ batch->owns_flag |= GWN_BATCH_OWNS_INSTANCES;
+ else
+ batch->owns_flag &= ~GWN_BATCH_OWNS_INSTANCES;
+ }
+
int GWN_batch_vertbuf_add_ex(
Gwn_Batch* batch, Gwn_VertBuf* verts,
bool own_vbo)
{
+ // redo the bindings
+ gwn_batch_vao_cache_clear(batch);
+
for (unsigned v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
{
if (batch->verts[v] == NULL)
@@ -97,115 +187,218 @@ int GWN_batch_vertbuf_add_ex(
return -1;
}
-void GWN_batch_program_set(Gwn_Batch* batch, GLuint program, const Gwn_ShaderInterface* shaderface)
+static GLuint batch_vao_get(Gwn_Batch *batch)
+ {
+ // Search through cache
+ if (batch->is_dynamic_vao_count)
+ {
+ for (int i = 0; i < batch->dynamic_vaos.count; ++i)
+ if (batch->dynamic_vaos.interfaces[i] == batch->interface)
+ return batch->dynamic_vaos.vao_ids[i];
+ }
+ else
+ {
+ for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i)
+ if (batch->static_vaos.interfaces[i] == batch->interface)
+ return batch->static_vaos.vao_ids[i];
+ }
+
+ // Set context of this batch.
+ // It will be bound to it until gwn_batch_vao_cache_clear is called.
+ // Until then it can only be drawn with this context.
+ if (batch->context == NULL)
+ {
+ batch->context = GWN_context_active_get();
+ gwn_context_add_batch(batch->context, batch);
+ }
+#if TRUST_NO_ONE
+ else // Make sure you are not trying to draw this batch in another context.
+ assert(batch->context == GWN_context_active_get());
+#endif
+
+ // Cache miss, time to add a new entry!
+ GLuint new_vao = 0;
+ if (!batch->is_dynamic_vao_count)
+ {
+ int i; // find first unused slot
+ for (i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i)
+ if (batch->static_vaos.vao_ids[i] == 0)
+ break;
+
+ if (i < GWN_BATCH_VAO_STATIC_LEN)
+ {
+ batch->static_vaos.interfaces[i] = batch->interface;
+ batch->static_vaos.vao_ids[i] = new_vao = GWN_vao_alloc();
+ }
+ else
+ {
+ // Not enough place switch to dynamic.
+ batch->is_dynamic_vao_count = true;
+ // Erase previous entries, they will be added back if drawn again.
+ for (int j = 0; j < GWN_BATCH_VAO_STATIC_LEN; ++j)
+ {
+ GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface*)batch->static_vaos.interfaces[j], batch);
+ GWN_vao_free(batch->static_vaos.vao_ids[j], batch->context);
+ }
+ // Init dynamic arrays and let the branch below set the values.
+ batch->dynamic_vaos.count = GWN_BATCH_VAO_DYN_ALLOC_COUNT;
+ batch->dynamic_vaos.interfaces = calloc(batch->dynamic_vaos.count, sizeof(Gwn_ShaderInterface*));
+ batch->dynamic_vaos.vao_ids = calloc(batch->dynamic_vaos.count, sizeof(GLuint));
+ }
+ }
+
+ if (batch->is_dynamic_vao_count)
+ {
+ int i; // find first unused slot
+ for (i = 0; i < batch->dynamic_vaos.count; ++i)
+ if (batch->dynamic_vaos.vao_ids[i] == 0)
+ break;
+
+ if (i == batch->dynamic_vaos.count)
+ {
+ // Not enough place, realloc the array.
+ i = batch->dynamic_vaos.count;
+ batch->dynamic_vaos.count += GWN_BATCH_VAO_DYN_ALLOC_COUNT;
+ batch->dynamic_vaos.interfaces = realloc(batch->dynamic_vaos.interfaces, sizeof(Gwn_ShaderInterface*) * batch->dynamic_vaos.count);
+ batch->dynamic_vaos.vao_ids = realloc(batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count);
+ memset(batch->dynamic_vaos.interfaces + i, 0, sizeof(Gwn_ShaderInterface*) * GWN_BATCH_VAO_DYN_ALLOC_COUNT);
+ memset(batch->dynamic_vaos.vao_ids + i, 0, sizeof(GLuint) * GWN_BATCH_VAO_DYN_ALLOC_COUNT);
+ }
+
+ batch->dynamic_vaos.interfaces[i] = batch->interface;
+ batch->dynamic_vaos.vao_ids[i] = new_vao = GWN_vao_alloc();
+ }
+
+ GWN_shaderinterface_add_batch_ref((Gwn_ShaderInterface*)batch->interface, batch);
+
+#if TRUST_NO_ONE
+ assert(new_vao != 0);
+#endif
+
+ // We just got a fresh VAO we need to initialize it.
+ glBindVertexArray(new_vao);
+ batch_update_program_bindings(batch, 0);
+ glBindVertexArray(0);
+
+ return new_vao;
+ }
+
+void GWN_batch_program_set_no_use(Gwn_Batch* batch, GLuint program, const Gwn_ShaderInterface* shaderface)
{
#if TRUST_NO_ONE
- assert(glIsProgram(program));
+ assert(glIsProgram(shaderface->program));
+ assert(batch->program_in_use == 0);
#endif
- batch->program = program;
batch->interface = shaderface;
- batch->program_dirty = true;
+ batch->program = program;
+ batch->vao_id = batch_vao_get(batch);
+ }
+void GWN_batch_program_set(Gwn_Batch* batch, GLuint program, const Gwn_ShaderInterface* shaderface)
+ {
+ GWN_batch_program_set_no_use(batch, program, shaderface);
GWN_batch_program_use_begin(batch); // hack! to make Batch_Uniform* simpler
}
-// fclem : hack !
-// we need this because we don't want to unbind the shader between drawcalls
-// but we still want the correct shader to be bound outside the draw manager
-void GWN_batch_program_unset(Gwn_Batch* batch)
+void gwn_batch_remove_interface_ref(Gwn_Batch* batch, const Gwn_ShaderInterface* interface)
{
- batch->program_in_use = false;
+ if (batch->is_dynamic_vao_count)
+ {
+ for (int i = 0; i < batch->dynamic_vaos.count; ++i)
+ {
+ if (batch->dynamic_vaos.interfaces[i] == interface)
+ {
+ GWN_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
+ batch->dynamic_vaos.vao_ids[i] = 0;
+ batch->dynamic_vaos.interfaces[i] = NULL;
+ break; // cannot have duplicates
+ }
+ }
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i)
+ {
+ if (batch->static_vaos.interfaces[i] == interface)
+ {
+ GWN_vao_free(batch->static_vaos.vao_ids[i], batch->context);
+ batch->static_vaos.vao_ids[i] = 0;
+ batch->static_vaos.interfaces[i] = NULL;
+ break; // cannot have duplicates
+ }
+ }
+ }
}
-static void create_bindings(Gwn_Batch* batch, const Gwn_ShaderInterface* interface, unsigned int v_first, const bool use_instancing)
+static void create_bindings(Gwn_VertBuf* verts, const Gwn_ShaderInterface* interface, unsigned int v_first, const bool use_instancing)
{
- for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
- {
- Gwn_VertBuf* verts = batch->verts[v];
- if (verts == NULL)
- break;
+ const Gwn_VertFormat* format = &verts->format;
+
+ const unsigned attrib_ct = format->attrib_ct;
+ const unsigned stride = format->stride;
- const Gwn_VertFormat* format = &verts->format;
+ GWN_vertbuf_use(verts);
- const unsigned attrib_ct = format->attrib_ct;
- const unsigned stride = format->stride;
+ for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx)
+ {
+ const Gwn_VertAttr* a = format->attribs + a_idx;
- GWN_vertbuf_use(verts);
+ const GLvoid* pointer = (const GLubyte*)0 + a->offset + v_first * stride;
- for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx)
+ for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx)
{
- const Gwn_VertAttr* a = format->attribs + a_idx;
+ const Gwn_ShaderInput* input = GWN_shaderinterface_attr(interface, a->name[n_idx]);
- const GLvoid* pointer = (const GLubyte*)0 + a->offset + v_first * stride;
+ if (input == NULL) continue;
- for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx)
+ if (a->comp_ct == 16 || a->comp_ct == 12 || a->comp_ct == 8)
{
- const Gwn_ShaderInput* input = GWN_shaderinterface_attr(interface, a->name[n_idx]);
-
- if (input == NULL) continue;
-
- if (a->comp_ct == 16 || a->comp_ct == 12 || a->comp_ct == 8)
- {
#if TRUST_NO_ONE
- assert(a->fetch_mode == GWN_FETCH_FLOAT);
- assert(a->gl_comp_type == GL_FLOAT);
+ assert(a->fetch_mode == GWN_FETCH_FLOAT);
+ assert(a->gl_comp_type == GL_FLOAT);
#endif
- for (int i = 0; i < a->comp_ct / 4; ++i)
- {
- glEnableVertexAttribArray(input->location + i);
- glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0);
- glVertexAttribPointer(input->location + i, 4, a->gl_comp_type, GL_FALSE, stride,
- (const GLubyte*)pointer + i * 16);
- }
+ for (int i = 0; i < a->comp_ct / 4; ++i)
+ {
+ glEnableVertexAttribArray(input->location + i);
+ glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0);
+ glVertexAttribPointer(input->location + i, 4, a->gl_comp_type, GL_FALSE, stride,
+ (const GLubyte*)pointer + i * 16);
}
- else
+ }
+ else
+ {
+ glEnableVertexAttribArray(input->location);
+ glVertexAttribDivisor(input->location, (use_instancing) ? 1 : 0);
+
+ switch (a->fetch_mode)
{
- glEnableVertexAttribArray(input->location);
- glVertexAttribDivisor(input->location, (use_instancing) ? 1 : 0);
-
- switch (a->fetch_mode)
- {
- case GWN_FETCH_FLOAT:
- case GWN_FETCH_INT_TO_FLOAT:
- glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer);
- break;
- case GWN_FETCH_INT_TO_FLOAT_UNIT:
- glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer);
- break;
- case GWN_FETCH_INT:
- glVertexAttribIPointer(input->location, a->comp_ct, a->gl_comp_type, stride, pointer);
- }
+ case GWN_FETCH_FLOAT:
+ case GWN_FETCH_INT_TO_FLOAT:
+ glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer);
+ break;
+ case GWN_FETCH_INT_TO_FLOAT_UNIT:
+ glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer);
+ break;
+ case GWN_FETCH_INT:
+ glVertexAttribIPointer(input->location, a->comp_ct, a->gl_comp_type, stride, pointer);
}
}
}
}
}
-static void Batch_update_program_bindings(Gwn_Batch* batch, unsigned int v_first)
+static void batch_update_program_bindings(Gwn_Batch* batch, unsigned int v_first)
{
- // disable all as a precaution
- // why are we not using prev_attrib_enabled_bits?? see immediate.c
- for (unsigned a_idx = 0; a_idx < GWN_VERT_ATTR_MAX_LEN; ++a_idx)
- glDisableVertexAttribArray(a_idx);
-
- create_bindings(batch, batch->interface, v_first, false);
+ for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v)
+ create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
- batch->program_dirty = false;
- }
-
-static void Batch_update_program_bindings_instancing(Gwn_Batch* batch, Gwn_Batch* batch_instancing, unsigned int instance_first)
- {
- // disable all as a precaution
- // why are we not using prev_attrib_enabled_bits?? see immediate.c
- for (unsigned a_idx = 0; a_idx < GWN_VERT_ATTR_MAX_LEN; ++a_idx)
- glDisableVertexAttribArray(a_idx);
+ if (batch->inst)
+ create_bindings(batch->inst, batch->interface, v_first, true);
- create_bindings(batch, batch->interface, 0, false);
- if (batch_instancing)
- create_bindings(batch_instancing, batch->interface, instance_first, true);
-
- batch->program_dirty = false;
+ if (batch->elem)
+ GWN_indexbuf_use(batch->elem);
}
void GWN_batch_program_use_begin(Gwn_Batch* batch)
@@ -236,6 +429,12 @@ void GWN_batch_program_use_end(Gwn_Batch* batch)
#define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name);
#endif
+void GWN_batch_uniform_1ui(Gwn_Batch* batch, const char* name, int value)
+ {
+ GET_UNIFORM
+ glUniform1ui(uniform->location, value);
+ }
+
void GWN_batch_uniform_1i(Gwn_Batch* batch, const char* name, int value)
{
GET_UNIFORM
@@ -290,145 +489,124 @@ void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[
glUniform4fv(uniform->location, 1, data);
}
-static void Batch_prime(Gwn_Batch* batch)
- {
- batch->vao_id = GWN_vao_alloc();
- glBindVertexArray(batch->vao_id);
+static void primitive_restart_enable(const Gwn_IndexBuf *el)
+{
+ // TODO(fclem) Replace by GL_PRIMITIVE_RESTART_FIXED_INDEX when we have ogl 4.3
+ glEnable(GL_PRIMITIVE_RESTART);
+ GLuint restart_index = (GLuint)0xFFFFFFFF;
- for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v)
- {
- if (batch->verts[v] == NULL)
- break;
- GWN_vertbuf_use(batch->verts[v]);
- }
+#if GWN_TRACK_INDEX_RANGE
+ if (el->index_type == GWN_INDEX_U8)
+ restart_index = (GLuint)0xFF;
+ else if (el->index_type == GWN_INDEX_U16)
+ restart_index = (GLuint)0xFFFF;
+#endif
- if (batch->elem)
- GWN_indexbuf_use(batch->elem);
+ glPrimitiveRestartIndex(restart_index);
+}
- // vertex attribs and element list remain bound to this VAO
- }
+static void primitive_restart_disable(void)
+{
+ glDisable(GL_PRIMITIVE_RESTART);
+}
void GWN_batch_draw(Gwn_Batch* batch)
{
#if TRUST_NO_ONE
assert(batch->phase == GWN_BATCH_READY_TO_DRAW);
- assert(glIsProgram(batch->program));
+ assert(batch->verts[0]->vbo_id != 0);
#endif
-
- if (batch->vao_id)
- glBindVertexArray(batch->vao_id);
- else
- Batch_prime(batch);
-
- if (batch->program_dirty)
- Batch_update_program_bindings(batch, 0);
-
GWN_batch_program_use_begin(batch);
+ gpuBindMatrices(batch->interface); // external call.
- gpuBindMatrices(batch->interface);
-
- if (batch->elem)
- {
- const Gwn_IndexBuf* el = batch->elem;
-
-#if GWN_TRACK_INDEX_RANGE
- if (el->base_index)
- glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0, el->base_index);
- else
- glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0);
-#else
- glDrawElements(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0);
-#endif
- }
- else
- glDrawArrays(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct);
+ GWN_batch_draw_range_ex(batch, 0, 0, false);
GWN_batch_program_use_end(batch);
- glBindVertexArray(0);
}
-void GWN_batch_draw_stupid(Gwn_Batch* batch, int v_first, int v_count)
+void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool force_instance)
{
- if (batch->vao_id)
- glBindVertexArray(batch->vao_id);
- else
- Batch_prime(batch);
-
- if (batch->program_dirty)
- Batch_update_program_bindings(batch, v_first);
+#if TRUST_NO_ONE
+ assert(!(force_instance && (batch->inst == NULL)) || v_count > 0); // we cannot infer length if force_instance
+#endif
+ const bool do_instance = (force_instance || batch->inst);
- // GWN_batch_program_use_begin(batch);
+ // If using offset drawing, use the default VAO and redo bindings.
+ if (v_first != 0 && (do_instance || batch->elem))
+ {
+ glBindVertexArray(GWN_vao_default());
+ batch_update_program_bindings(batch, v_first);
+ }
+ else
+ glBindVertexArray(batch->vao_id);
- //gpuBindMatrices(batch->program);
+ if (do_instance)
+ {
+ // Infer length if vertex count is not given
+ if (v_count == 0)
+ v_count = batch->inst->vertex_ct;
- // Infer lenght if vertex count is not given
- if (v_count == 0)
- v_count = (batch->elem) ? batch->elem->index_ct : batch->verts[0]->vertex_ct;
+ if (batch->elem)
+ {
+ const Gwn_IndexBuf* el = batch->elem;
- if (batch->elem)
- {
- const Gwn_IndexBuf* el = batch->elem;
+ if (el->use_prim_restart)
+ primitive_restart_enable(el);
#if GWN_TRACK_INDEX_RANGE
- if (el->base_index)
- glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0, el->base_index);
- else
- glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0);
+ glDrawElementsInstancedBaseVertex(batch->gl_prim_type, el->index_ct, el->gl_index_type, 0, v_count, el->base_index);
#else
- glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, 0);
+ glDrawElementsInstanced(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, v_count);
#endif
+ if (el->use_prim_restart)
+ primitive_restart_disable();
+ }
+ else
+ glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct, v_count);
}
else
- glDrawArrays(batch->gl_prim_type, 0, v_count);
-
- // GWN_batch_program_use_end(batch);
- glBindVertexArray(0);
- }
-
-void GWN_batch_draw_stupid_instanced(Gwn_Batch* batch_instanced, Gwn_Batch* batch_instancing, int instance_first, int instance_count)
- {
-#if TRUST_NO_ONE
- // batch_instancing can be null if the number of instances is specified.
- assert(batch_instancing != NULL || instance_count != 0);
-#endif
- if (batch_instanced->vao_id)
- glBindVertexArray(batch_instanced->vao_id);
- else
- Batch_prime(batch_instanced);
-
- if (batch_instanced->program_dirty)
- Batch_update_program_bindings_instancing(batch_instanced, batch_instancing, instance_first);
+ {
+ // Infer length if vertex count is not given
+ if (v_count == 0)
+ v_count = (batch->elem) ? batch->elem->index_ct : batch->verts[0]->vertex_ct;
- if (instance_count == 0)
- instance_count = batch_instancing->verts[0]->vertex_ct;
+ if (batch->elem)
+ {
+ const Gwn_IndexBuf* el = batch->elem;
- if (batch_instanced->elem)
- {
- const Gwn_IndexBuf* el = batch_instanced->elem;
+ if (el->use_prim_restart)
+ primitive_restart_enable(el);
#if GWN_TRACK_INDEX_RANGE
- glDrawElementsInstancedBaseVertex(batch_instanced->gl_prim_type, el->index_ct, el->gl_index_type, 0, instance_count, el->base_index);
+ if (el->base_index)
+ glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0, el->base_index);
+ else
+ glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0);
#else
- glDrawElementsInstanced(batch_instanced->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, instance_count);
+ glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, 0);
#endif
+ if (el->use_prim_restart)
+ primitive_restart_disable();
+ }
+ else
+ glDrawArrays(batch->gl_prim_type, v_first, v_count);
}
- else
- glDrawArraysInstanced(batch_instanced->gl_prim_type, 0, batch_instanced->verts[0]->vertex_ct, instance_count);
- glBindVertexArray(0);
+ // Performance hog if you are drawing with the same vao multiple time.
+ // Only activate for debugging.
+ // glBindVertexArray(0);
}
// just draw some vertices and let shader place them where we want.
-void GWN_batch_draw_procedural(Gwn_Batch* batch, Gwn_PrimType prim_type, int v_count)
+void GWN_draw_primitive(Gwn_PrimType prim_type, int v_count)
{
// we cannot draw without vao ... annoying ...
- if (batch->vao_id)
- glBindVertexArray(batch->vao_id);
- else
- Batch_prime(batch);
+ glBindVertexArray(GWN_vao_default());
GLenum type = convert_prim_type_to_gl(prim_type);
glDrawArrays(type, 0, v_count);
- glBindVertexArray(0);
+ // Performance hog if you are drawing with the same vao multiple time.
+ // Only activate for debugging.
+ // glBindVertexArray(0);
}
diff --git a/intern/gawain/src/gwn_buffer_id.cpp b/intern/gawain/src/gwn_buffer_id.cpp
index a93c3950d29..64bad855ca7 100644
--- a/intern/gawain/src/gwn_buffer_id.cpp
+++ b/intern/gawain/src/gwn_buffer_id.cpp
@@ -20,7 +20,6 @@
#endif
static std::vector<GLuint> orphaned_buffer_ids;
-static std::vector<GLuint> orphaned_vao_ids;
static std::mutex orphan_mutex;
@@ -36,10 +35,6 @@ static bool thread_is_main()
GLuint GWN_buf_id_alloc()
{
-#if TRUST_NO_ONE
- assert(thread_is_main());
-#endif
-
// delete orphaned IDs
orphan_mutex.lock();
if (!orphaned_buffer_ids.empty())
@@ -73,43 +68,3 @@ void GWN_buf_id_free(GLuint buffer_id)
orphan_mutex.unlock();
}
}
-
-GLuint GWN_vao_alloc()
- {
-#if TRUST_NO_ONE
- assert(thread_is_main());
-#endif
-
- // delete orphaned IDs
- orphan_mutex.lock();
- if (!orphaned_vao_ids.empty())
- {
- const auto orphaned_vao_ct = (unsigned)orphaned_vao_ids.size();
-#if ORPHAN_DEBUG
- printf("deleting %u orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s");
-#endif
- glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids.data());
- orphaned_vao_ids.clear();
- }
- orphan_mutex.unlock();
-
- GLuint new_vao_id = 0;
- glGenVertexArrays(1, &new_vao_id);
- return new_vao_id;
- }
-
-void GWN_vao_free(GLuint vao_id)
- {
- if (thread_is_main())
- glDeleteVertexArrays(1, &vao_id);
- else
- {
- // add this ID to the orphaned list
- orphan_mutex.lock();
-#if ORPHAN_DEBUG
- printf("orphaning VAO %u\n", vao_id);
-#endif
- orphaned_vao_ids.emplace_back(vao_id);
- orphan_mutex.unlock();
- }
- }
diff --git a/intern/gawain/src/gwn_element.c b/intern/gawain/src/gwn_element.c
index f31b64fa232..0b7dc675f87 100644
--- a/intern/gawain/src/gwn_element.c
+++ b/intern/gawain/src/gwn_element.c
@@ -39,26 +39,14 @@ unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf* elem)
#endif
}
-static void ElementList_prime(Gwn_IndexBuf* elem)
+void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned index_ct, unsigned vertex_ct, bool use_prim_restart)
{
- elem->vbo_id = GWN_buf_id_alloc();
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
- // fill with delicious data & send to GPU the first time only
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
-
-#if KEEP_SINGLE_COPY
- // now that GL has a copy, discard original
- free(elem->data);
- elem->data = NULL;
-#endif
- }
-
-void GWN_indexbuf_use(Gwn_IndexBuf* elem)
- {
- if (elem->vbo_id)
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
- else
- ElementList_prime(elem);
+ builder->use_prim_restart = use_prim_restart;
+ builder->max_allowed_index = vertex_ct - 1;
+ builder->max_index_ct = index_ct;
+ builder->index_ct = 0; // start empty
+ builder->prim_type = prim_type;
+ builder->data = calloc(builder->max_index_ct, sizeof(unsigned));
}
void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned prim_ct, unsigned vertex_ct)
@@ -82,11 +70,7 @@ void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, uns
return;
}
- builder->max_allowed_index = vertex_ct - 1;
- builder->max_index_ct = prim_ct * verts_per_prim;
- builder->index_ct = 0; // start empty
- builder->prim_type = prim_type;
- builder->data = calloc(builder->max_index_ct, sizeof(unsigned));
+ GWN_indexbuf_init_ex(builder, prim_type, prim_ct * verts_per_prim, vertex_ct, false);
}
void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v)
@@ -100,6 +84,17 @@ void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v)
builder->data[builder->index_ct++] = v;
}
+void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder* builder)
+ {
+#if TRUST_NO_ONE
+ assert(builder->data != NULL);
+ assert(builder->index_ct < builder->max_index_ct);
+ assert(builder->use_prim_restart);
+#endif
+
+ builder->data[builder->index_ct++] = GWN_PRIM_RESTART;
+ }
+
void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, unsigned v)
{
#if TRUST_NO_ONE
@@ -149,7 +144,9 @@ static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned
for (unsigned i = 1; i < value_ct; ++i)
{
const unsigned value = values[i];
- if (value < min_value)
+ if (value == GWN_PRIM_RESTART)
+ continue;
+ else if (value < min_value)
min_value = value;
else if (value > max_value)
max_value = value;
@@ -159,10 +156,14 @@ static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned
return max_value - min_value;
}
-static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
+static void squeeze_indices_byte(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem)
{
+ const unsigned *values = builder->data;
const unsigned index_ct = elem->index_ct;
- GLubyte* data = malloc(index_ct * sizeof(GLubyte));
+
+ // data will never be *larger* than builder->data...
+ // converting in place to avoid extra allocation
+ GLubyte *data = (GLubyte *)builder->data;
if (elem->max_index > 0xFF)
{
@@ -173,7 +174,7 @@ static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
elem->max_index -= base;
for (unsigned i = 0; i < index_ct; ++i)
- data[i] = (GLubyte)(values[i] - base);
+ data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base);
}
else
{
@@ -182,14 +183,16 @@ static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
for (unsigned i = 0; i < index_ct; ++i)
data[i] = (GLubyte)(values[i]);
}
-
- elem->data = data;
}
-static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
+static void squeeze_indices_short(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem)
{
+ const unsigned *values = builder->data;
const unsigned index_ct = elem->index_ct;
- GLushort* data = malloc(index_ct * sizeof(GLushort));
+
+ // data will never be *larger* than builder->data...
+ // converting in place to avoid extra allocation
+ GLushort *data = (GLushort *)builder->data;
if (elem->max_index > 0xFFFF)
{
@@ -200,7 +203,7 @@ static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
elem->max_index -= base;
for (unsigned i = 0; i < index_ct; ++i)
- data[i] = (GLushort)(values[i] - base);
+ data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base);
}
else
{
@@ -209,8 +212,6 @@ static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
for (unsigned i = 0; i < index_ct; ++i)
data[i] = (GLushort)(values[i]);
}
-
- elem->data = data;
}
#endif // GWN_TRACK_INDEX_RANGE
@@ -229,67 +230,56 @@ void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* ele
#endif
elem->index_ct = builder->index_ct;
+ elem->use_prim_restart = builder->use_prim_restart;
#if GWN_TRACK_INDEX_RANGE
- const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index);
+ unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index);
+
+ // count the primitive restart index.
+ if (elem->use_prim_restart)
+ range += 1;
if (range <= 0xFF)
{
elem->index_type = GWN_INDEX_U8;
- squeeze_indices_byte(builder->data, elem);
+ squeeze_indices_byte(builder, elem);
}
else if (range <= 0xFFFF)
{
elem->index_type = GWN_INDEX_U16;
- squeeze_indices_short(builder->data, elem);
+ squeeze_indices_short(builder, elem);
}
else
{
elem->index_type = GWN_INDEX_U32;
elem->base_index = 0;
-
- if (builder->index_ct < builder->max_index_ct)
- {
- builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned));
- // TODO: realloc only if index_ct is much smaller than max_index_ct
- }
-
- elem->data = builder->data;
}
elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
-#else
- if (builder->index_ct < builder->max_index_ct)
- {
- builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned));
- // TODO: realloc only if index_ct is much smaller than max_index_ct
- }
-
- elem->data = builder->data;
#endif
- // elem->data will never be *larger* than builder->data... how about converting
- // in place to avoid extra allocation?
+ if (elem->vbo_id == 0)
+ elem->vbo_id = GWN_buf_id_alloc();
- elem->vbo_id = 0;
- // TODO: create GL buffer object directly, based on an input flag
+ // send data to GPU
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW);
// discard builder (one-time use)
- if (builder->data != elem->data)
- free(builder->data);
+ free(builder->data);
builder->data = NULL;
// other fields are safe to leave
}
+void GWN_indexbuf_use(Gwn_IndexBuf* elem)
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+ }
+
void GWN_indexbuf_discard(Gwn_IndexBuf* elem)
{
if (elem->vbo_id)
GWN_buf_id_free(elem->vbo_id);
-#if KEEP_SINGLE_COPY
- else
-#endif
- if (elem->data)
- free(elem->data);
free(elem);
}
diff --git a/intern/gawain/src/gwn_immediate.c b/intern/gawain/src/gwn_immediate.c
index 1c0776d1bbf..c6df3ada018 100644
--- a/intern/gawain/src/gwn_immediate.c
+++ b/intern/gawain/src/gwn_immediate.c
@@ -14,6 +14,7 @@
#include "gwn_attr_binding.h"
#include "gwn_attr_binding_private.h"
#include "gwn_vertex_format_private.h"
+#include "gwn_vertex_array_id.h"
#include "gwn_primitive_private.h"
#include <string.h>
@@ -27,6 +28,7 @@ typedef struct {
#if IMM_BATCH_COMBO
Gwn_Batch* batch;
#endif
+ Gwn_Context* context;
// current draw call
GLubyte* buffer_data;
@@ -86,8 +88,8 @@ void immActivate(void)
assert(imm.prim_type == GWN_PRIM_NONE); // make sure we're not between a Begin/End pair
assert(imm.vao_id == 0);
#endif
-
imm.vao_id = GWN_vao_alloc();
+ imm.context = GWN_context_active_get();
}
void immDeactivate(void)
@@ -97,8 +99,7 @@ void immDeactivate(void)
assert(imm.prim_type == GWN_PRIM_NONE); // make sure we're not between a Begin/End pair
assert(imm.vao_id != 0);
#endif
-
- GWN_vao_free(imm.vao_id);
+ GWN_vao_free(imm.vao_id, imm.context);
imm.vao_id = 0;
imm.prev_enabled_attrib_bits = 0;
}
@@ -276,8 +277,6 @@ Gwn_Batch* immBeginBatch(Gwn_PrimType prim_type, unsigned vertex_ct)
imm.batch = GWN_batch_create(prim_type, verts, NULL);
imm.batch->phase = GWN_BATCH_BUILDING;
- GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
-
return imm.batch;
}
@@ -397,6 +396,7 @@ void immEnd(void)
// TODO: resize only if vertex count is much smaller
}
+ GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
imm.batch->phase = GWN_BATCH_READY_TO_DRAW;
imm.batch = NULL; // don't free, batch belongs to caller
}
diff --git a/intern/gawain/src/gwn_shader_interface.c b/intern/gawain/src/gwn_shader_interface.c
index 33821ae36e2..e92cabec12f 100644
--- a/intern/gawain/src/gwn_shader_interface.c
+++ b/intern/gawain/src/gwn_shader_interface.c
@@ -9,7 +9,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+#include "gwn_batch_private.h"
#include "gwn_shader_interface.h"
+#include "gwn_vertex_array_id.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
@@ -43,7 +45,6 @@ static const char* BuiltinUniform_name(Gwn_UniformBuiltin u)
[GWN_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix",
[GWN_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors",
[GWN_UNIFORM_ORCO] = "OrcoTexCoFactors",
- [GWN_UNIFORM_CLIPPLANES] = "ClipPlanes",
[GWN_UNIFORM_COLOR] = "color",
[GWN_UNIFORM_EYE] = "eye",
@@ -263,6 +264,18 @@ Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program)
#endif
}
+ // Builtin Uniforms
+ for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u)
+ {
+ const char* builtin_name = BuiltinUniform_name(u);
+ if (glGetUniformLocation(program, builtin_name) != -1)
+ add_uniform((Gwn_ShaderInterface*)shaderface, builtin_name);
+ }
+
+ // Batches ref buffer
+ shaderface->batches_ct = GWN_SHADERINTERFACE_REF_ALLOC_COUNT;
+ shaderface->batches = calloc(shaderface->batches_ct, sizeof(Gwn_Batch*));
+
return shaderface;
}
@@ -274,6 +287,12 @@ void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface)
buckets_free(shaderface->ubo_buckets);
// Free memory used by name_buffer.
free(shaderface->name_buffer);
+ // Remove this interface from all linked Batches vao cache.
+ for (int i = 0; i < shaderface->batches_ct; ++i)
+ if (shaderface->batches[i] != NULL)
+ gwn_batch_remove_interface_ref(shaderface->batches[i], shaderface);
+
+ free(shaderface->batches);
// Free memory used by shader interface by its self.
free(shaderface);
}
@@ -297,14 +316,7 @@ const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInter
assert(builtin != GWN_UNIFORM_CUSTOM);
assert(builtin != GWN_NUM_UNIFORMS);
#endif
-
- const Gwn_ShaderInput* input = shaderface->builtin_uniforms[builtin];
-
- // If input is not found add it so it's found next time.
- if (input == NULL)
- input = add_uniform((Gwn_ShaderInterface*)shaderface, BuiltinUniform_name(builtin));
-
- return (input->location != -1) ? input : NULL;
+ return shaderface->builtin_uniforms[builtin];
}
const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface* shaderface, const char* name)
@@ -316,3 +328,34 @@ const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shade
{
return buckets_lookup(shaderface->attrib_buckets, shaderface->name_buffer, name);
}
+
+void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch)
+ {
+ int i; // find first unused slot
+ for (i = 0; i < shaderface->batches_ct; ++i)
+ if (shaderface->batches[i] == NULL)
+ break;
+
+ if (i == shaderface->batches_ct)
+ {
+ // Not enough place, realloc the array.
+ i = shaderface->batches_ct;
+ shaderface->batches_ct += GWN_SHADERINTERFACE_REF_ALLOC_COUNT;
+ shaderface->batches = realloc(shaderface->batches, sizeof(Gwn_Batch*) * shaderface->batches_ct);
+ memset(shaderface->batches + i, 0, sizeof(Gwn_Batch*) * GWN_SHADERINTERFACE_REF_ALLOC_COUNT);
+ }
+
+ shaderface->batches[i] = batch;
+ }
+
+void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch)
+ {
+ for (int i = 0; i < shaderface->batches_ct; ++i)
+ {
+ if (shaderface->batches[i] == batch)
+ {
+ shaderface->batches[i] = NULL;
+ break; // cannot have duplicates
+ }
+ }
+ }
diff --git a/intern/gawain/src/gwn_vertex_array_id.cpp b/intern/gawain/src/gwn_vertex_array_id.cpp
new file mode 100644
index 00000000000..ed54562c434
--- /dev/null
+++ b/intern/gawain/src/gwn_vertex_array_id.cpp
@@ -0,0 +1,170 @@
+
+// Gawain vertex array IDs
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin, Clément Foucault
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.#include "buffer_id.h"
+
+#include "gwn_batch_private.h"
+#include "gwn_vertex_array_id.h"
+#include "gwn_context.h"
+#include <vector>
+#include <string.h>
+#include <pthread.h>
+#include <mutex>
+#include <unordered_set>
+
+#if TRUST_NO_ONE
+extern "C" {
+extern int BLI_thread_is_main(void); // Blender-specific function
+}
+
+static bool thread_is_main()
+ {
+ // "main" here means the GL context's thread
+ return BLI_thread_is_main();
+ }
+#endif
+
+struct Gwn_Context {
+ GLuint default_vao;
+ std::unordered_set<Gwn_Batch*> batches; // Batches that have VAOs from this context
+ std::vector<GLuint> orphaned_vertarray_ids;
+ std::mutex orphans_mutex; // todo: try spinlock instead
+#if TRUST_NO_ONE
+ pthread_t thread; // Thread on which this context is active.
+ bool thread_is_used;
+
+ Gwn_Context()
+ {
+ thread_is_used = false;
+ }
+#endif
+};
+
+#if defined(_MSC_VER) && (_MSC_VER == 1800)
+#define thread_local __declspec(thread)
+thread_local Gwn_Context* active_ctx = NULL;
+#else
+static thread_local Gwn_Context* active_ctx = NULL;
+#endif
+
+static void clear_orphans(Gwn_Context* ctx)
+ {
+ ctx->orphans_mutex.lock();
+ if (!ctx->orphaned_vertarray_ids.empty())
+ {
+ unsigned orphan_ct = (unsigned)ctx->orphaned_vertarray_ids.size();
+ glDeleteVertexArrays(orphan_ct, ctx->orphaned_vertarray_ids.data());
+ ctx->orphaned_vertarray_ids.clear();
+ }
+ ctx->orphans_mutex.unlock();
+ }
+
+Gwn_Context* GWN_context_create(void)
+ {
+#if TRUST_NO_ONE
+ assert(thread_is_main());
+#endif
+ Gwn_Context* ctx = new Gwn_Context;
+ glGenVertexArrays(1, &ctx->default_vao);
+ GWN_context_active_set(ctx);
+ return ctx;
+ }
+
+// to be called after GWN_context_active_set(ctx_to_destroy)
+void GWN_context_discard(Gwn_Context* ctx)
+ {
+#if TRUST_NO_ONE
+ // Make sure no other thread has locked it.
+ assert(ctx == active_ctx);
+ assert(pthread_equal(pthread_self(), ctx->thread));
+ assert(ctx->orphaned_vertarray_ids.empty());
+#endif
+ // delete remaining vaos
+ while (!ctx->batches.empty())
+ {
+ // this removes the array entry
+ gwn_batch_vao_cache_clear(*ctx->batches.begin());
+ }
+ glDeleteVertexArrays(1, &ctx->default_vao);
+ delete ctx;
+ active_ctx = NULL;
+ }
+
+// ctx can be NULL
+void GWN_context_active_set(Gwn_Context* ctx)
+ {
+#if TRUST_NO_ONE
+ if (active_ctx)
+ active_ctx->thread_is_used = false;
+ // Make sure no other context is already bound to this thread.
+ if (ctx)
+ {
+ // Make sure no other thread has locked it.
+ assert(ctx->thread_is_used == false);
+ ctx->thread = pthread_self();
+ ctx->thread_is_used = true;
+ }
+#endif
+ if (ctx)
+ clear_orphans(ctx);
+ active_ctx = ctx;
+ }
+
+Gwn_Context* GWN_context_active_get(void)
+ {
+ return active_ctx;
+ }
+
+GLuint GWN_vao_default(void)
+ {
+#if TRUST_NO_ONE
+ assert(active_ctx); // need at least an active context
+ assert(pthread_equal(pthread_self(), active_ctx->thread)); // context has been activated by another thread!
+#endif
+ return active_ctx->default_vao;
+ }
+
+GLuint GWN_vao_alloc(void)
+ {
+#if TRUST_NO_ONE
+ assert(active_ctx); // need at least an active context
+ assert(pthread_equal(pthread_self(), active_ctx->thread)); // context has been activated by another thread!
+#endif
+ clear_orphans(active_ctx);
+
+ GLuint new_vao_id = 0;
+ glGenVertexArrays(1, &new_vao_id);
+ return new_vao_id;
+ }
+
+// this can be called from multiple thread
+void GWN_vao_free(GLuint vao_id, Gwn_Context* ctx)
+ {
+#if TRUST_NO_ONE
+ assert(ctx);
+#endif
+ if (ctx == active_ctx)
+ glDeleteVertexArrays(1, &vao_id);
+ else
+ {
+ ctx->orphans_mutex.lock();
+ ctx->orphaned_vertarray_ids.emplace_back(vao_id);
+ ctx->orphans_mutex.unlock();
+ }
+ }
+
+void gwn_context_add_batch(Gwn_Context* ctx, Gwn_Batch* batch)
+ {
+ ctx->batches.emplace(batch);
+ }
+
+void gwn_context_remove_batch(Gwn_Context* ctx, Gwn_Batch* batch)
+ {
+ ctx->batches.erase(batch);
+ }
diff --git a/intern/gawain/src/gwn_vertex_buffer.c b/intern/gawain/src/gwn_vertex_buffer.c
index 32bef765390..39fc1885b92 100644
--- a/intern/gawain/src/gwn_vertex_buffer.c
+++ b/intern/gawain/src/gwn_vertex_buffer.c
@@ -19,16 +19,26 @@
static unsigned vbo_memory_usage;
-Gwn_VertBuf* GWN_vertbuf_create(void)
+static GLenum convert_usage_type_to_gl(Gwn_UsageType type)
+ {
+ static const GLenum table[] = {
+ [GWN_USAGE_STREAM] = GL_STREAM_DRAW,
+ [GWN_USAGE_STATIC] = GL_STATIC_DRAW,
+ [GWN_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW
+ };
+ return table[type];
+ }
+
+Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType usage)
{
Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf));
- GWN_vertbuf_init(verts);
+ GWN_vertbuf_init(verts, usage);
return verts;
}
-Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format)
+Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat* format, Gwn_UsageType usage)
{
- Gwn_VertBuf* verts = GWN_vertbuf_create();
+ Gwn_VertBuf* verts = GWN_vertbuf_create(usage);
GWN_vertformat_copy(&verts->format, format);
if (!format->packed)
VertexFormat_pack(&verts->format);
@@ -38,60 +48,33 @@ Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format)
// TODO: implement those memory savings
}
-Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat* format)
- {
- Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(format);
- verts->data_dynamic = true;
- return verts;
- }
-
-void GWN_vertbuf_init(Gwn_VertBuf* verts)
+void GWN_vertbuf_init(Gwn_VertBuf* verts, Gwn_UsageType usage)
{
memset(verts, 0, sizeof(Gwn_VertBuf));
+ verts->usage = usage;
+ verts->dirty = true;
}
-void GWN_vertbuf_init_with_format(Gwn_VertBuf* verts, const Gwn_VertFormat* format)
+void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf* verts, const Gwn_VertFormat* format, Gwn_UsageType usage)
{
- GWN_vertbuf_init(verts);
+ GWN_vertbuf_init(verts, usage);
GWN_vertformat_copy(&verts->format, format);
if (!format->packed)
VertexFormat_pack(&verts->format);
}
-/**
- * Like #GWN_vertbuf_discard but doesn't free.
- */
-void GWN_vertbuf_clear(Gwn_VertBuf* verts)
- {
- if (verts->vbo_id) {
- GWN_buf_id_free(verts->vbo_id);
-#if VRAM_USAGE
- vbo_memory_usage -= verts->vram_size;
-#endif
- }
-
- if (verts->data)
- {
- free(verts->data);
- verts->data = NULL;
- }
- }
-
void GWN_vertbuf_discard(Gwn_VertBuf* verts)
{
if (verts->vbo_id)
{
GWN_buf_id_free(verts->vbo_id);
#if VRAM_USAGE
- vbo_memory_usage -= verts->vram_size;
+ vbo_memory_usage -= GWN_vertbuf_size_get(verts);
#endif
}
if (verts->data)
- {
free(verts->data);
- }
-
free(verts);
}
@@ -101,33 +84,58 @@ unsigned GWN_vertbuf_size_get(const Gwn_VertBuf* verts)
return vertex_buffer_size(&verts->format, verts->vertex_ct);
}
+// create a new allocation, discarding any existing data
void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct)
{
Gwn_VertFormat* format = &verts->format;
if (!format->packed)
VertexFormat_pack(format);
+#if TRUST_NO_ONE
+ // catch any unnecessary use
+ assert(verts->vertex_ct != v_ct || verts->data == NULL);
+#endif
+
+ // only create the buffer the 1st time
+ if (verts->vbo_id == 0)
+ verts->vbo_id = GWN_buf_id_alloc();
+
+ // discard previous data if any
+ if (verts->data)
+ free(verts->data);
+
+#if VRAM_USAGE
+ vbo_memory_usage -= GWN_vertbuf_size_get(verts);
+#endif
+
+ verts->dirty = true;
verts->vertex_ct = v_ct;
+ verts->data = malloc(sizeof(GLubyte) * GWN_vertbuf_size_get(verts));
- // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it.
- verts->data = malloc(GWN_vertbuf_size_get(verts));
+#if VRAM_USAGE
+ vbo_memory_usage += GWN_vertbuf_size_get(verts);
+#endif
}
+// resize buffer keeping existing data
void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct)
{
#if TRUST_NO_ONE
- assert(verts->vertex_ct != v_ct); // allow this?
- assert(verts->data != NULL); // has already been allocated
- assert(verts->vbo_id == 0 || verts->data_dynamic); // has not been sent to VRAM
+ assert(verts->data != NULL);
+ assert(verts->vertex_ct != v_ct);
#endif
- // for dynamic buffers
- verts->data_resized = true;
+#if VRAM_USAGE
+ vbo_memory_usage -= GWN_vertbuf_size_get(verts);
+#endif
+ verts->dirty = true;
verts->vertex_ct = v_ct;
- verts->data = realloc(verts->data, GWN_vertbuf_size_get(verts));
- // TODO: skip realloc if v_ct < existing vertex count
- // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime)
+ verts->data = realloc(verts->data, sizeof(GLubyte) * GWN_vertbuf_size_get(verts));
+
+#if VRAM_USAGE
+ vbo_memory_usage += GWN_vertbuf_size_get(verts);
+#endif
}
void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, const void* data)
@@ -135,14 +143,13 @@ void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, co
const Gwn_VertFormat* format = &verts->format;
const Gwn_VertAttr* a = format->attribs + a_idx;
- verts->data_dirty = true;
-
#if TRUST_NO_ONE
assert(a_idx < format->attrib_ct);
assert(v_idx < verts->vertex_ct);
- assert(verts->data != NULL); // data must be in main mem
+ assert(verts->data != NULL);
#endif
+ verts->dirty = true;
memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz);
}
@@ -151,8 +158,6 @@ void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, unsigned a_idx, const void* data)
const Gwn_VertFormat* format = &verts->format;
const Gwn_VertAttr* a = format->attribs + a_idx;
- verts->data_dirty = true;
-
#if TRUST_NO_ONE
assert(a_idx < format->attrib_ct);
#endif
@@ -167,13 +172,12 @@ void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned s
const Gwn_VertFormat* format = &verts->format;
const Gwn_VertAttr* a = format->attribs + a_idx;
- verts->data_dirty = true;
-
#if TRUST_NO_ONE
assert(a_idx < format->attrib_ct);
- assert(verts->data != NULL); // data must be in main mem
+ assert(verts->data != NULL);
#endif
+ verts->dirty = true;
const unsigned vertex_ct = verts->vertex_ct;
if (format->attrib_ct == 1 && stride == format->stride)
@@ -196,9 +200,11 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB
#if TRUST_NO_ONE
assert(a_idx < format->attrib_ct);
- assert(verts->data != NULL); // data must be in main mem
+ assert(verts->data != NULL);
#endif
+ verts->dirty = true;
+
access->size = a->sz;
access->stride = format->stride;
access->data = (GLubyte*)verts->data + a->offset;
@@ -208,61 +214,30 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB
#endif
}
-
-static void VertexBuffer_prime(Gwn_VertBuf* verts)
+static void VertBuffer_upload_data(Gwn_VertBuf* verts)
{
unsigned buffer_sz = GWN_vertbuf_size_get(verts);
-#if VRAM_USAGE
- vbo_memory_usage += buffer_sz;
- verts->vram_size = buffer_sz;
-#endif
+ // orphan the vbo to avoid sync
+ glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage));
+ // upload data
+ glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data);
- verts->vbo_id = GWN_buf_id_alloc();
- glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
- // fill with delicious data & send to GPU the first time only
- glBufferData(GL_ARRAY_BUFFER, verts->vram_size, verts->data, (verts->data_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
-
- // now that GL has a copy, discard original
- if (!verts->data_dynamic)
+ if (verts->usage == GWN_USAGE_STATIC)
{
free(verts->data);
verts->data = NULL;
}
- verts->data_dirty = false;
+ verts->dirty = false;
}
-static void VertexBuffer_update(Gwn_VertBuf* verts)
+void GWN_vertbuf_use(Gwn_VertBuf* verts)
{
- unsigned buffer_sz = GWN_vertbuf_size_get(verts);
-
-#if VRAM_USAGE
- vbo_memory_usage -= verts->vram_size;
- vbo_memory_usage += buffer_sz;
- verts->vram_size = buffer_sz;
-#endif
-
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
- // fill with delicious data & send to GPU ... AGAIN
- if (verts->data_resized)
- glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_DYNAMIC_DRAW);
- else
- glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); // .. todo try glMapBuffer
-
- verts->data_dirty = false;
- verts->data_resized = false;
- }
-
-void GWN_vertbuf_use(Gwn_VertBuf* verts)
- {
- if (!verts->vbo_id)
- VertexBuffer_prime(verts);
- else if (verts->data_dirty)
- VertexBuffer_update(verts);
- else
- glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
+ if (verts->dirty)
+ VertBuffer_upload_data(verts);
}
unsigned GWN_vertbuf_get_memory_usage(void)
diff --git a/intern/gawain/src/gwn_vertex_format.c b/intern/gawain/src/gwn_vertex_format.c
index 4694bc22b2b..c180c304d28 100644
--- a/intern/gawain/src/gwn_vertex_format.c
+++ b/intern/gawain/src/gwn_vertex_format.c
@@ -177,7 +177,7 @@ void GWN_vertformat_alias_add(Gwn_VertFormat* format, const char* alias)
Gwn_VertAttr* attrib = format->attribs + (format->attrib_ct - 1);
#if TRUST_NO_ONE
assert(format->name_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more
- assert(attrib->name_ct < MAX_ATTRIB_NAMES);
+ assert(attrib->name_ct < GWN_VERT_ATTR_MAX_NAMES);
#endif
format->name_ct++; // multiname support
attrib->name[attrib->name_ct++] = copy_attrib_name(format, alias);
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 5a97da28d17..e4b74ae24af 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
intern/GHOST_WindowManager.cpp
GHOST_C-api.h
+ GHOST_IContext.h
GHOST_IEvent.h
GHOST_IEventConsumer.h
GHOST_ISystem.h
@@ -177,10 +178,12 @@ elseif(WITH_X11)
intern/GHOST_DisplayManagerX11.cpp
intern/GHOST_SystemX11.cpp
intern/GHOST_WindowX11.cpp
+ intern/GHOST_TaskbarX11.cpp
intern/GHOST_DisplayManagerX11.h
intern/GHOST_SystemX11.h
intern/GHOST_WindowX11.h
+ intern/GHOST_TaskbarX11.h
)
if(NOT WITH_GL_EGL)
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 967d3f58143..d5d8be7db8e 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -52,6 +52,7 @@ GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
+GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
/**
@@ -189,6 +190,23 @@ extern GHOST_WindowHandle GHOST_CreateWindow(
GHOST_GLSettings glSettings);
/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \param systemhandle The handle to the system
+ * \return A handle to the new context ( == NULL if creation failed).
+ */
+extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle);
+
+/**
+ * Dispose of a context.
+ * \param systemhandle The handle to the system
+ * \param contexthandle Handle to the context to be disposed.
+ * \return Indication of success.
+ */
+extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
+ GHOST_ContextHandle contexthandle);
+
+/**
* Returns the window user data.
* \param windowhandle The handle to the window
* \return The window user data.
@@ -711,6 +729,20 @@ extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle wind
extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle);
/**
+ * Activates the drawing context of this context.
+ * \param contexthandle The handle to the context
+ * \return A success indicator.
+ */
+extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle);
+
+/**
+ * Release the drawing context bound to this thread.
+ * \param contexthandle The handle to the context
+ * \return A success indicator.
+ */
+extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
+
+/**
* Returns the status of the tablet
* \param windowhandle The handle to the window
* \return Status of tablet
diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h
new file mode 100644
index 00000000000..5b027a614ab
--- /dev/null
+++ b/intern/ghost/GHOST_IContext.h
@@ -0,0 +1,78 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/GHOST_IContext.h
+ * \ingroup GHOST
+ * Declaration of GHOST_IContext interface class.
+ */
+
+#ifndef __GHOST_IContext_H__
+#define __GHOST_IContext_H__
+
+#include "STR_String.h"
+#include "GHOST_Types.h"
+
+
+/**
+ * Interface for GHOST context.
+ *
+ * You can create a offscreen context (windowless) with the system's
+ * GHOST_ISystem::createOffscreenContext method.
+ * \see GHOST_ISystem#createOffscreenContext
+ *
+ * \author Clément Foucault
+ * \date Feb 9, 2018
+ */
+class GHOST_IContext
+{
+public:
+ /**
+ * Destructor.
+ */
+ virtual ~GHOST_IContext()
+ {
+ }
+
+ /**
+ * Activates the drawing context.
+ * \return A boolean success indicator.
+ */
+ virtual GHOST_TSuccess activateDrawingContext() = 0;
+
+ /**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ virtual GHOST_TSuccess releaseDrawingContext() = 0;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IContext")
+#endif
+};
+
+#endif // __GHOST_IContext_H__
+
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 03193d6e1da..5c5590ef069 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -36,6 +36,7 @@
#define __GHOST_ISYSTEM_H__
#include "GHOST_Types.h"
+#include "GHOST_IContext.h"
#include "GHOST_ITimerTask.h"
#include "GHOST_IWindow.h"
@@ -262,6 +263,20 @@ public:
virtual GHOST_TSuccess disposeWindow(GHOST_IWindow *window) = 0;
/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ virtual GHOST_IContext *createOffscreenContext() = 0;
+
+ /**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+ virtual GHOST_TSuccess disposeContext(GHOST_IContext *context) = 0;
+
+ /**
* Returns whether a window is valid.
* \param window Pointer to the window to be checked.
* \return Indication of validity.
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index ce653188760..2fe94171cf8 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -132,6 +132,22 @@ void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
system->getAllDisplayDimensions(*width, *height);
}
+GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
+
+ return (GHOST_ContextHandle) system->createOffscreenContext();
+}
+
+GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
+ GHOST_ContextHandle contexthandle)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
+ GHOST_IContext *context = (GHOST_IContext *) contexthandle;
+
+ return system->disposeContext(context);
+}
+
GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
const char *title,
GHOST_TInt32 left,
@@ -713,7 +729,19 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl
return window->activateDrawingContext();
}
+GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
+{
+ GHOST_IContext *context = (GHOST_IContext *) contexthandle;
+
+ return context->activateDrawingContext();
+}
+
+GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
+{
+ GHOST_IContext *context = (GHOST_IContext *) contexthandle;
+ return context->releaseDrawingContext();
+}
GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle)
{
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index 8776fa4764f..670b86d456f 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -33,6 +33,7 @@
#ifndef __GHOST_CONTEXT_H__
#define __GHOST_CONTEXT_H__
+#include "GHOST_IContext.h"
#include "GHOST_Types.h"
#include "glew-mx.h"
@@ -40,7 +41,7 @@
#include <cstdlib> // for NULL
-class GHOST_Context
+class GHOST_Context : public GHOST_IContext
{
public:
/**
@@ -72,6 +73,12 @@ public:
virtual GHOST_TSuccess activateDrawingContext() = 0;
/**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ virtual GHOST_TSuccess releaseDrawingContext()= 0;
+
+ /**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index 6dcc4da0f0a..ea6eb485ce2 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -83,6 +83,12 @@ public:
GHOST_TSuccess activateDrawingContext();
/**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 03af3cc497e..46993a1cd1d 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -35,6 +35,8 @@
#include <Cocoa/Cocoa.h>
+//#define GHOST_MULTITHREADED_OPENGL
+
#ifdef GHOST_MULTITHREADED_OPENGL
#include <OpenGL/OpenGL.h>
#endif
@@ -62,8 +64,6 @@ GHOST_ContextCGL::GHOST_ContextCGL(
m_openGLContext(nil),
m_debug(contextFlags)
{
- assert(openGLView != nil);
-
// for now be very strict about OpenGL version requested
switch (contextMajorVersion) {
case 2:
@@ -73,7 +73,7 @@ GHOST_ContextCGL::GHOST_ContextCGL(
break;
case 3:
// Apple didn't implement 3.0 or 3.1
- assert(contextMinorVersion == 2);
+ assert(contextMinorVersion == 3);
assert(contextProfileMask == GL_CONTEXT_CORE_PROFILE_BIT);
m_coreProfile = true;
break;
@@ -88,7 +88,10 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
if (m_openGLContext != nil) {
if (m_openGLContext == [NSOpenGLContext currentContext]) {
[NSOpenGLContext clearCurrentContext];
- [m_openGLView clearGLContext];
+
+ if(m_openGLView) {
+ [m_openGLView clearGLContext];
+ }
}
if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
@@ -167,6 +170,18 @@ GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext()
}
}
+GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext()
+{
+ if (m_openGLContext != nil) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [NSOpenGLContext clearCurrentContext];
+ [pool drain];
+ return GHOST_kSuccess;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
{
@@ -258,7 +273,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
std::vector<NSOpenGLPixelFormatAttribute> attribs;
attribs.reserve(40);
- NSOpenGLContext *prev_openGLContext = [m_openGLView openGLContext];
+ NSOpenGLContext *prev_openGLContext = (m_openGLView) ? [m_openGLView openGLContext] : NULL;
#ifdef GHOST_OPENGL_ALPHA
static const bool needAlpha = true;
@@ -346,8 +361,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
#ifdef GHOST_MULTITHREADED_OPENGL
//Switch openGL to multhreaded mode
- CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
- if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
+ if (CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine) == kCGLNoError)
if (m_debug)
fprintf(stderr, "\nSwitched OpenGL to multithreaded mode\n");
#endif
@@ -362,8 +376,10 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
initContextGLEW();
- [m_openGLView setOpenGLContext:m_openGLContext];
- [m_openGLContext setView:m_openGLView];
+ if (m_openGLView) {
+ [m_openGLView setOpenGLContext:m_openGLContext];
+ [m_openGLContext setView:m_openGLView];
+ }
if (s_sharedCount == 0)
s_sharedOpenGLContext = m_openGLContext;
@@ -380,7 +396,10 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
error:
- [m_openGLView setOpenGLContext:prev_openGLContext];
+ if (m_openGLView) {
+ [m_openGLView setOpenGLContext:prev_openGLContext];
+ }
+
[pixelFormat release];
[pool drain];
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index a591d9b7583..56962d24939 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -312,6 +312,17 @@ GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
}
}
+GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
+{
+ if (m_display) {
+ bindAPI(m_api);
+
+ return EGL_CHK(::eglMakeCurrent(m_display, None, None, NULL)) ? GHOST_kSuccess : GHOST_kFailure;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
void GHOST_ContextEGL::initContextEGLEW()
{
diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h
index 6dfb177f26d..83415f6be54 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.h
+++ b/intern/ghost/intern/GHOST_ContextEGL.h
@@ -81,6 +81,12 @@ public:
GHOST_TSuccess activateDrawingContext();
/**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index 061ac29945b..fb7fa4ee762 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -74,7 +74,6 @@ GHOST_ContextGLX::GHOST_ContextGLX(
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_context(None)
{
- assert(m_window != 0);
assert(m_display != NULL);
}
@@ -119,6 +118,16 @@ GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext()
}
}
+GHOST_TSuccess GHOST_ContextGLX::releaseDrawingContext()
+{
+ if (m_display) {
+ return ::glXMakeCurrent(m_display, None, NULL) ? GHOST_kSuccess : GHOST_kFailure;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
+
void GHOST_ContextGLX::initContextGLXEW()
{
initContextGLEW();
@@ -246,9 +255,22 @@ const bool GLXEW_ARB_create_context_robustness =
}
attribs[i++] = 0;
+ /* Some drivers don't like having a true offscreen context.
+ * Create a pixel buffer instead of a window to render to.
+ * even if it will never be used for drawing. */
+ int pbuffer_attribs[] = {
+ GLX_PBUFFER_WIDTH, 1,
+ GLX_PBUFFER_HEIGHT, 1,
+ None
+ };
+
/* Create a GL 3.x context */
if (m_fbconfig) {
m_context = glXCreateContextAttribsARB(m_display, m_fbconfig, s_sharedContext, true, attribs);
+
+ if (!m_window) {
+ m_window = (Window)glXCreatePbuffer(m_display, m_fbconfig, pbuffer_attribs);
+ }
}
else {
GLXFBConfig *framebuffer_config = NULL;
@@ -263,6 +285,11 @@ const bool GLXEW_ARB_create_context_robustness =
if (framebuffer_config) {
m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs);
+
+ if (!m_window) {
+ m_window = (Window)glXCreatePbuffer(m_display, framebuffer_config[0], pbuffer_attribs);
+ }
+
XFree(framebuffer_config);
}
}
@@ -288,8 +315,10 @@ const bool GLXEW_ARB_create_context_robustness =
// which means we cannot use glX extensions until after we create a context
initContextGLXEW();
- initClearGL();
- ::glXSwapBuffers(m_display, m_window);
+ if (m_window) {
+ initClearGL();
+ ::glXSwapBuffers(m_display, m_window);
+ }
/* re initialize to get the extensions properly */
initContextGLXEW();
diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h
index 51fb1dd57dc..ded1b293659 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.h
+++ b/intern/ghost/intern/GHOST_ContextGLX.h
@@ -82,6 +82,12 @@ public:
GHOST_TSuccess activateDrawingContext();
/**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
diff --git a/intern/ghost/intern/GHOST_ContextNone.cpp b/intern/ghost/intern/GHOST_ContextNone.cpp
index 380ab532f7a..89bdf6b89fa 100644
--- a/intern/ghost/intern/GHOST_ContextNone.cpp
+++ b/intern/ghost/intern/GHOST_ContextNone.cpp
@@ -46,6 +46,12 @@ GHOST_TSuccess GHOST_ContextNone::activateDrawingContext()
}
+GHOST_TSuccess GHOST_ContextNone::releaseDrawingContext()
+{
+ return GHOST_kSuccess;
+}
+
+
GHOST_TSuccess GHOST_ContextNone::updateDrawingContext()
{
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_ContextNone.h b/intern/ghost/intern/GHOST_ContextNone.h
index 80cce76190d..9f2af4ae235 100644
--- a/intern/ghost/intern/GHOST_ContextNone.h
+++ b/intern/ghost/intern/GHOST_ContextNone.h
@@ -61,6 +61,12 @@ public:
/**
* Dummy function
+ * \return Always succeeds
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
+ * Dummy function
* \return Always succeeds
*/
GHOST_TSuccess updateDrawingContext();
diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp
index 7a02e9743c3..1ba591bd0b2 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.cpp
+++ b/intern/ghost/intern/GHOST_ContextSDL.cpp
@@ -105,6 +105,18 @@ GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext()
}
+GHOST_TSuccess GHOST_ContextSDL::releaseDrawingContext()
+{
+ if (m_context) {
+ /* Untested, may not work */
+ return SDL_GL_MakeCurrent(NULL, NULL) ? GHOST_kSuccess : GHOST_kFailure;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
+
+
GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
{
#ifdef GHOST_OPENGL_ALPHA
diff --git a/intern/ghost/intern/GHOST_ContextSDL.h b/intern/ghost/intern/GHOST_ContextSDL.h
index 61f339c1bc2..681d24bb7c6 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.h
+++ b/intern/ghost/intern/GHOST_ContextSDL.h
@@ -86,6 +86,12 @@ public:
GHOST_TSuccess activateDrawingContext();
/**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index 7b5e30247a8..58ade795e3f 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -43,14 +43,7 @@
HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
int GHOST_ContextWGL::s_sharedCount = 0;
-bool GHOST_ContextWGL::s_singleContextMode = false;
-
-
-/* Intel video-cards don't work fine with multiple contexts and
- * have to share the same context for all windows.
- * But if we just share context for all windows it could work incorrect
- * with multiple videocards configuration. Suppose, that Intel videocards
- * can't be in multiple-devices configuration. */
+/* Some third-generation Intel video-cards are constantly bring problems */
static bool is_crappy_intel_card()
{
return strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL;
@@ -69,6 +62,7 @@ GHOST_ContextWGL::GHOST_ContextWGL(
int contextFlags,
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual, numOfAASamples),
+ m_dummyPbuffer(NULL),
m_hWnd(hWnd),
m_hDC(hDC),
m_contextProfileMask(contextProfileMask),
@@ -85,8 +79,6 @@ GHOST_ContextWGL::GHOST_ContextWGL(
m_dummyVersion(NULL)
#endif
{
- assert(m_hWnd);
- assert(m_hDC);
}
@@ -106,12 +98,20 @@ GHOST_ContextWGL::~GHOST_ContextWGL()
WIN32_CHK(::wglDeleteContext(m_hGLRC));
}
+ if (m_dummyPbuffer) {
+ if (m_hDC != NULL)
+ WIN32_CHK(::wglReleasePbufferDCARB(m_dummyPbuffer, m_hDC));
+
+ WIN32_CHK(::wglDestroyPbufferARB(m_dummyPbuffer));
+ }
}
#ifndef NDEBUG
- free((void*)m_dummyRenderer);
- free((void*)m_dummyVendor);
- free((void*)m_dummyVersion);
+ if (m_dummyRenderer) {
+ free((void*)m_dummyRenderer);
+ free((void*)m_dummyVendor);
+ free((void*)m_dummyVersion);
+ }
#endif
}
@@ -154,6 +154,16 @@ GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
}
+GHOST_TSuccess GHOST_ContextWGL::releaseDrawingContext()
+{
+ if (WIN32_CHK(::wglMakeCurrent(NULL, NULL))) {
+ return GHOST_kSuccess;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
+
/* Ron Fosner's code for weighting pixel formats and forcing software.
* See http://www.opengl.org/resources/faq/technical/weight.cpp
*/
@@ -317,6 +327,8 @@ static HWND clone_window(HWND hWnd, LPVOID lpParam)
void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
{
HWND dummyHWND = NULL;
+ HPBUFFERARB dummyhBuffer = NULL;
+
HDC dummyHDC = NULL;
HGLRC dummyHGLRC = NULL;
@@ -333,23 +345,30 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
prevHGLRC = ::wglGetCurrentContext();
WIN32_CHK(GetLastError() == NO_ERROR);
- dummyHWND = clone_window(m_hWnd, NULL);
+ iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
- if (dummyHWND == NULL)
+ if (iPixelFormat == 0)
goto finalize;
- dummyHDC = GetDC(dummyHWND);
-
- if (!WIN32_CHK(dummyHDC != NULL))
+ PIXELFORMATDESCRIPTOR chosenPFD;
+ if (!WIN32_CHK(::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
goto finalize;
- iPixelFormat = choose_pixel_format_legacy(dummyHDC, preferredPFD);
+ if (m_hWnd) {
+ dummyHWND = clone_window(m_hWnd, NULL);
- if (iPixelFormat == 0)
- goto finalize;
+ if (dummyHWND == NULL)
+ goto finalize;
- PIXELFORMATDESCRIPTOR chosenPFD;
- if (!WIN32_CHK(::DescribePixelFormat(dummyHDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
+ dummyHDC = GetDC(dummyHWND);
+ }
+ else {
+ int iAttribList[] = {0};
+ dummyhBuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, iAttribList);
+ dummyHDC = wglGetPbufferDCARB(dummyhBuffer);
+ }
+
+ if (!WIN32_CHK(dummyHDC != NULL))
goto finalize;
if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD)))
@@ -378,8 +397,6 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
m_dummyVersion = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
#endif
- s_singleContextMode = is_crappy_intel_card();
-
finalize:
WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC));
@@ -392,6 +409,12 @@ finalize:
WIN32_CHK(::DestroyWindow(dummyHWND));
}
+ else if (dummyhBuffer != NULL) {
+ if (dummyHDC != NULL)
+ WIN32_CHK(::wglReleasePbufferDCARB(dummyhBuffer, dummyHDC));
+
+ WIN32_CHK(::wglDestroyPbufferARB(dummyhBuffer));
+ }
}
@@ -753,7 +776,9 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
HDC prevHDC = ::wglGetCurrentDC();
WIN32_CHK(GetLastError() == NO_ERROR);
- if (!WGLEW_ARB_create_context || ::GetPixelFormat(m_hDC) == 0) {
+ const bool create_hDC = m_hDC == NULL;
+
+ if (!WGLEW_ARB_create_context || create_hDC || ::GetPixelFormat(m_hDC) == 0) {
const bool needAlpha = m_alphaBackground;
#ifdef GHOST_OPENGL_STENCIL
@@ -770,20 +795,33 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
int iPixelFormat;
int lastPFD;
+ if (create_hDC) {
+ /* get a handle to a device context with graphics accelerator enabled */
+ m_hDC = wglGetCurrentDC();
+ if (m_hDC == NULL) {
+ m_hDC = GetDC(NULL);
+ }
+ }
+
PIXELFORMATDESCRIPTOR chosenPFD;
iPixelFormat = choose_pixel_format(m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, sRGB);
if (iPixelFormat == 0) {
- ::wglMakeCurrent(prevHDC, prevHGLRC);
- return GHOST_kFailure;
+ goto error;
+ }
+
+ if (create_hDC) {
+ /* create an off-screen pixel buffer (Pbuffer) */
+ int iAttribList[] = {0};
+ m_dummyPbuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, iAttribList);
+ m_hDC = wglGetPbufferDCARB(m_dummyPbuffer);
}
lastPFD = ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD);
if (!WIN32_CHK(lastPFD != 0)) {
- ::wglMakeCurrent(prevHDC, prevHGLRC);
- return GHOST_kFailure;
+ goto error;
}
if (needAlpha && chosenPFD.cAlphaBits == 0)
@@ -793,8 +831,7 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
fprintf(stderr, "Warning! Unable to find a pixel format with a stencil buffer.\n");
if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) {
- ::wglMakeCurrent(prevHDC, prevHGLRC);
- return GHOST_kFailure;
+ goto error;
}
}
@@ -870,30 +907,24 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
iAttributes.push_back(0);
- if (!s_singleContextMode || s_sharedHGLRC == NULL)
- m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
- else
- m_hGLRC = s_sharedHGLRC;
+ m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
}
if (!WIN32_CHK(m_hGLRC != NULL)) {
- ::wglMakeCurrent(prevHDC, prevHGLRC);
- return GHOST_kFailure;
+ goto error;
}
- if (s_sharedHGLRC == NULL)
- s_sharedHGLRC = m_hGLRC;
-
s_sharedCount++;
- if (!s_singleContextMode && s_sharedHGLRC != m_hGLRC && !WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
- ::wglMakeCurrent(prevHDC, prevHGLRC);
- return GHOST_kFailure;
+ if (s_sharedHGLRC == NULL) {
+ s_sharedHGLRC = m_hGLRC;
+ }
+ else if (!WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
+ goto error;
}
if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
- ::wglMakeCurrent(prevHDC, prevHGLRC);
- return GHOST_kFailure;
+ goto error;
}
initContextGLEW();
@@ -923,6 +954,16 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
#endif
return GHOST_kSuccess;
+error:
+ if (m_dummyPbuffer) {
+ if (m_hDC != NULL)
+ WIN32_CHK(::wglReleasePbufferDCARB(m_dummyPbuffer, m_hDC));
+
+ WIN32_CHK(::wglDestroyPbufferARB(m_dummyPbuffer));
+ }
+ ::wglMakeCurrent(prevHDC, prevHGLRC);
+ return GHOST_kFailure;
+
}
diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h
index a07cc1b6301..b3b66c5f6e2 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.h
+++ b/intern/ghost/intern/GHOST_ContextWGL.h
@@ -79,6 +79,12 @@ public:
GHOST_TSuccess activateDrawingContext();
/**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
@@ -137,6 +143,10 @@ private:
void initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD);
+ /* offscreen buffer with size of 1x1 pixel,
+ * kept here to release the device constext when closing the program. */
+ HPBUFFERARB m_dummyPbuffer;
+
HWND m_hWnd;
HDC m_hDC;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 6802ad42c7b..62d9774d81d 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -123,6 +123,25 @@ public:
const GHOST_TEmbedderWindowID parentWindow = 0
);
+ /**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ GHOST_IContext *
+ createOffscreenContext(
+ );
+
+ /**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+ GHOST_TSuccess
+ disposeContext(
+ GHOST_IContext *context
+ );
+
/***************************************************************************************
* Event management functionality
***************************************************************************************/
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index e9fffb6f60b..011719ea946 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -27,15 +27,6 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#import <Cocoa/Cocoa.h>
-
-/*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/
-#include <Carbon/Carbon.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
-
#include "GHOST_SystemCocoa.h"
#include "GHOST_DisplayManagerCocoa.h"
@@ -51,12 +42,26 @@
#include "GHOST_WindowManager.h"
#include "GHOST_WindowCocoa.h"
+#if defined(WITH_GL_EGL)
+# include "GHOST_ContextEGL.h"
+#else
+# include "GHOST_ContextCGL.h"
+#endif
+
#ifdef WITH_INPUT_NDOF
#include "GHOST_NDOFManagerCocoa.h"
#endif
#include "AssertMacros.h"
+#import <Cocoa/Cocoa.h>
+
+/* For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible) */
+#include <Carbon/Carbon.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
#pragma mark KeyMap, mouse converters
@@ -581,6 +586,53 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
}
/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+GHOST_IContext *
+GHOST_SystemCocoa::
+createOffscreenContext()
+{
+ GHOST_Context *context = new GHOST_ContextCGL(
+ false,
+ 0,
+ NULL,
+ NULL,
+
+#if defined(WITH_GL_PROFILE_CORE)
+ GL_CONTEXT_CORE_PROFILE_BIT,
+ 3, 3,
+#else
+ 0, // no profile bit
+ 2, 1,
+#endif
+ GHOST_OPENGL_CGL_CONTEXT_FLAGS,
+ GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext())
+ return context;
+ else
+ delete context;
+
+ return NULL;
+}
+
+/**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+GHOST_TSuccess
+GHOST_SystemCocoa::
+disposeContext(GHOST_IContext *context)
+{
+ delete context;
+
+ return GHOST_kSuccess;
+}
+
+/**
* \note : returns coordinates in Cocoa screen coordinates
*/
GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index b0dae432643..056b5536ab0 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -56,6 +56,12 @@
#include "GHOST_WindowManager.h"
#include "GHOST_WindowWin32.h"
+#if defined(WITH_GL_EGL)
+# include "GHOST_ContextEGL.h"
+#else
+# include "GHOST_ContextWGL.h"
+#endif
+
#ifdef WITH_INPUT_NDOF
#include "GHOST_NDOFManagerWin32.h"
#endif
@@ -299,6 +305,94 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(
}
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the window, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+GHOST_IContext *GHOST_SystemWin32::createOffscreenContext()
+{
+ bool debug_context = false; /* TODO: inform as a parameter */
+
+ GHOST_Context *context;
+
+#if defined(WITH_GL_PROFILE_CORE)
+ for (int minor = 5; minor >= 0; --minor) {
+ context = new GHOST_ContextWGL(
+ false, true, 0,
+ NULL, NULL,
+ WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ 4, minor,
+ (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+ else {
+ delete context;
+ }
+ }
+
+ context = new GHOST_ContextWGL(
+ false, true, 0,
+ NULL, NULL,
+ WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ 3, 3,
+ (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+ else {
+ MessageBox(
+ NULL,
+ "Blender requires a graphics driver with at least OpenGL 3.3 support.\n\n"
+ "The program will now close.",
+ "Blender - Unsupported Graphics Driver!",
+ MB_OK | MB_ICONERROR);
+ delete context;
+ exit();
+ }
+
+#elif defined(WITH_GL_PROFILE_COMPAT)
+ // ask for 2.1 context, driver gives any GL version >= 2.1 (hopefully the latest compatibility profile)
+ // 2.1 ignores the profile bit & is incompatible with core profile
+ context = new GHOST_ContextWGL(
+ false, true, 0,
+ NULL, NULL,
+ 0, // no profile bit
+ 2, 1,
+ (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+ else {
+ delete context;
+ }
+#else
+# error // must specify either core or compat at build time
+#endif
+
+ return NULL;
+}
+
+/**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+GHOST_TSuccess GHOST_SystemWin32::disposeContext(GHOST_IContext *context)
+{
+ delete context;
+
+ return GHOST_kSuccess;
+}
+
+
bool GHOST_SystemWin32::processEvents(bool waitForEvent)
{
MSG msg;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 099d14e68ae..6bf2c5b8d6f 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -132,6 +132,21 @@ public:
const bool exclusive = false,
const GHOST_TEmbedderWindowID parentWindow = 0);
+
+ /**
+ * Create a new offscreen context.
+ * Never explicitly delete the window, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ GHOST_IContext *createOffscreenContext();
+
+ /**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+ GHOST_TSuccess disposeContext(GHOST_IContext *context);
+
/***************************************************************************************
** Event management functionality
***************************************************************************************/
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 9b617a34e1a..0de6e2f7d4a 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -57,6 +57,12 @@
#include "GHOST_Debug.h"
+#if defined(WITH_GL_EGL)
+# include "GHOST_ContextEGL.h"
+#else
+# include "GHOST_ContextGLX.h"
+#endif
+
#ifdef WITH_XF86KEYSYM
#include <X11/XF86keysym.h>
#endif
@@ -113,6 +119,7 @@ GHOST_SystemX11(
: GHOST_System(),
m_start_time(0)
{
+ XInitThreads();
m_display = XOpenDisplay(NULL);
if (!m_display) {
@@ -379,6 +386,98 @@ createWindow(const STR_String& title,
return window;
}
+
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+GHOST_IContext *
+GHOST_SystemX11::
+createOffscreenContext()
+{
+ // During development:
+ // try 4.x compatibility profile
+ // try 3.3 compatibility profile
+ // fall back to 3.0 if needed
+ //
+ // Final Blender 2.8:
+ // try 4.x core profile
+ // try 3.3 core profile
+ // no fallbacks
+
+#if defined(WITH_GL_PROFILE_CORE)
+ {
+ const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR);
+ if (version_major != NULL && version_major[0] == '1') {
+ fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
+ abort();
+ }
+ }
+#endif
+
+ const int profile_mask =
+#if defined(WITH_GL_PROFILE_CORE)
+ GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+#elif defined(WITH_GL_PROFILE_COMPAT)
+ GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+#else
+# error // must specify either core or compat at build time
+#endif
+
+ GHOST_Context *context;
+
+ for (int minor = 5; minor >= 0; --minor) {
+ context = new GHOST_ContextGLX(
+ false,
+ 0,
+ (Window)NULL,
+ m_display,
+ (GLXFBConfig)NULL,
+ profile_mask,
+ 4, minor,
+ GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext())
+ return context;
+ else
+ delete context;
+ }
+
+ context = new GHOST_ContextGLX(
+ false,
+ 0,
+ (Window)NULL,
+ m_display,
+ (GLXFBConfig)NULL,
+ profile_mask,
+ 3, 3,
+ GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+ GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+
+ if (context->initializeDrawingContext())
+ return context;
+ else
+ delete context;
+
+ return NULL;
+}
+
+/**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+GHOST_TSuccess
+GHOST_SystemX11::
+disposeContext(GHOST_IContext *context)
+{
+ delete context;
+
+ return GHOST_kSuccess;
+}
+
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
{
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index e60cab6a194..1ad8277a431 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -171,6 +171,26 @@ public:
const GHOST_TEmbedderWindowID parentWindow = 0
);
+
+ /**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ GHOST_IContext *
+ createOffscreenContext(
+ );
+
+ /**
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+ GHOST_TSuccess
+ disposeContext(
+ GHOST_IContext *context
+ );
+
/**
* Retrieves events from the system and stores them in the queue.
* \param waitForEvent Flag to wait for an event (or return immediately).
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp
new file mode 100644
index 00000000000..b47068df39f
--- /dev/null
+++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp
@@ -0,0 +1,130 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Lukas Stockner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/intern/GHOST_TaskbarX11.cpp
+ * \ingroup GHOST
+ */
+
+#include "GHOST_TaskbarX11.h"
+
+#include <dlfcn.h>
+#include <cstdio>
+#include <cassert>
+#include <cstdlib>
+
+typedef void*(*unity_get_entry_t)(const char*);
+typedef void(*unity_set_progress_t)(void*, double);
+typedef void(*unity_set_progress_visible_t)(void*, int);
+typedef int(*unity_event_loop_t)(void*, int);
+
+static unity_get_entry_t unity_get_entry;
+static unity_set_progress_t unity_set_progress;
+static unity_set_progress_visible_t unity_set_progress_visible;
+static unity_event_loop_t unity_event_loop;
+
+static bool libunity_initialized = false;
+static bool libunity_available = false;
+void* libunity_handle = NULL;
+
+void GHOST_TaskBarX11::free()
+{
+ if(libunity_handle) {
+ dlclose(libunity_handle);
+ libunity_handle = NULL;
+ }
+}
+
+bool GHOST_TaskBarX11::init()
+{
+ if(libunity_initialized) {
+ return libunity_available;
+ }
+
+ libunity_initialized = true;
+
+ const char *libunity_names[] = {"libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", NULL};
+ for(int i = 0; libunity_names[i]; i++) {
+ libunity_handle = dlopen(libunity_names[i], RTLD_LAZY);
+ if(libunity_handle) {
+ break;
+ }
+ }
+
+ if(!libunity_handle) {
+ return false;
+ }
+
+ unity_get_entry = (unity_get_entry_t) dlsym(libunity_handle, "unity_launcher_entry_get_for_desktop_id");
+ if(!unity_get_entry) {
+ fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+ return false;
+ }
+ unity_set_progress = (unity_set_progress_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress");
+ if(!unity_set_progress) {
+ fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+ return false;
+ }
+ unity_set_progress_visible = (unity_set_progress_visible_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress_visible");
+ if(!unity_set_progress_visible) {
+ fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+ return false;
+ }
+ unity_event_loop = (unity_event_loop_t) dlsym(libunity_handle, "g_main_context_iteration");
+ if(!unity_event_loop) {
+ fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+ return false;
+ }
+
+ atexit(GHOST_TaskBarX11::free);
+
+ libunity_available = true;
+ return true;
+}
+
+GHOST_TaskBarX11::GHOST_TaskBarX11(const char *name)
+{
+ if(GHOST_TaskBarX11::init()) {
+ handle = unity_get_entry(name);
+ }
+ else {
+ handle = NULL;
+ }
+}
+
+bool GHOST_TaskBarX11::is_valid()
+{
+ return (handle != NULL);
+}
+
+void GHOST_TaskBarX11::set_progress(double progress)
+{
+ assert(is_valid());
+ unity_set_progress(handle, progress);
+}
+
+void GHOST_TaskBarX11::set_progress_enabled(bool enabled)
+{
+ assert(is_valid());
+ unity_set_progress_visible(handle, enabled ? 1 : 0);
+ unity_event_loop(NULL, 0);
+} \ No newline at end of file
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.h b/intern/ghost/intern/GHOST_TaskbarX11.h
new file mode 100644
index 00000000000..ed0e5f9b329
--- /dev/null
+++ b/intern/ghost/intern/GHOST_TaskbarX11.h
@@ -0,0 +1,45 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Lukas Stockner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/intern/GHOST_TaskbarX11.h
+ * \ingroup GHOST
+ */
+#ifndef __GHOST_TASKBARX11_H__
+#define __GHOST_TASKBARX11_H__
+
+class GHOST_TaskBarX11
+{
+public:
+ static bool init();
+ static void free();
+
+ GHOST_TaskBarX11(const char *name);
+
+ bool is_valid();
+ void set_progress(double progress);
+ void set_progress_enabled(bool enabled);
+private:
+ void *handle;
+};
+
+#endif /*__GHOST_TASKBARX11_H__*/
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 309c19f92af..2b986428fd3 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -1005,7 +1005,7 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
#if defined(WITH_GL_PROFILE_CORE)
GL_CONTEXT_CORE_PROFILE_BIT,
- 3, 2,
+ 3, 3,
#else
0, // no profile bit
2, 1,
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 78a1c841934..3c291bd5ec6 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -334,6 +334,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
m_empty_cursor(None),
m_custom_cursor(None),
m_visible_cursor(None),
+ m_taskbar("blender.desktop"),
#ifdef WITH_XDND
m_dropTarget(NULL),
#endif
@@ -1697,3 +1698,24 @@ getDPIHint()
int dpi = pixelDiagonal / inchDiagonal;
return dpi;
}
+
+GHOST_TSuccess GHOST_WindowX11::setProgressBar(float progress)
+{
+ if (m_taskbar.is_valid()) {
+ m_taskbar.set_progress(progress);
+ m_taskbar.set_progress_enabled(true);
+ return GHOST_kSuccess;
+ }
+
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_WindowX11::endProgressBar()
+{
+ if (m_taskbar.is_valid()) {
+ m_taskbar.set_progress_enabled(false);
+ return GHOST_kSuccess;
+ }
+
+ return GHOST_kFailure;
+}
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 5c54c1e8162..236fe0b76b0 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -41,6 +41,8 @@
# include <X11/extensions/XInput.h>
#endif
+#include "GHOST_TaskbarX11.h"
+
#include <map>
class STR_String;
@@ -166,6 +168,9 @@ public:
invalidate(
);
+ GHOST_TSuccess setProgressBar(float progress);
+ GHOST_TSuccess endProgressBar();
+
/**
* Destructor.
* Closes the window and disposes resources allocated.
@@ -347,6 +352,8 @@ private:
/** Cache of XC_* ID's to XCursor structures */
std::map<unsigned int, Cursor> m_standard_cursors;
+ GHOST_TaskBarX11 m_taskbar;
+
#ifdef WITH_XDND
GHOST_DropTargetX11 *m_dropTarget;
#endif
diff --git a/intern/openvdb/intern/openvdb_dense_convert.cc b/intern/openvdb/intern/openvdb_dense_convert.cc
index ef52408bd93..76fbbf88079 100644
--- a/intern/openvdb/intern/openvdb_dense_convert.cc
+++ b/intern/openvdb/intern/openvdb_dense_convert.cc
@@ -79,7 +79,8 @@ openvdb::GridBase *OpenVDB_export_vector_grid(
const int res[3],
float fluid_mat[4][4],
openvdb::VecType vec_type,
- const bool is_color,
+ const bool is_color,
+ const float clipping,
const openvdb::FloatGrid *mask)
{
using namespace openvdb;
@@ -92,15 +93,15 @@ openvdb::GridBase *OpenVDB_export_vector_grid(
grid[0] = FloatGrid::create(0.0f);
tools::Dense<const float, tools::LayoutXYZ> dense_grid_x(bbox, data_x);
- tools::copyFromDense(dense_grid_x, grid[0]->tree(), TOLERANCE);
+ tools::copyFromDense(dense_grid_x, grid[0]->tree(), clipping);
grid[1] = FloatGrid::create(0.0f);
tools::Dense<const float, tools::LayoutXYZ> dense_grid_y(bbox, data_y);
- tools::copyFromDense(dense_grid_y, grid[1]->tree(), TOLERANCE);
+ tools::copyFromDense(dense_grid_y, grid[1]->tree(), clipping);
grid[2] = FloatGrid::create(0.0f);
tools::Dense<const float, tools::LayoutXYZ> dense_grid_z(bbox, data_z);
- tools::copyFromDense(dense_grid_z, grid[2]->tree(), TOLERANCE);
+ tools::copyFromDense(dense_grid_z, grid[2]->tree(), clipping);
Vec3SGrid::Ptr vecgrid = Vec3SGrid::create(Vec3s(0.0f));
@@ -165,4 +166,19 @@ void OpenVDB_import_grid_vector(
}
}
+openvdb::Name do_name_versionning(const openvdb::Name &name)
+{
+ openvdb::Name temp_name = name;
+
+ if (temp_name.find("_low", temp_name.size() - 4, 4) == temp_name.size() - 4) {
+ return temp_name.replace(temp_name.size() - 4, 4, " low");
+ }
+
+ if (temp_name.find("_old", temp_name.size() - 4, 4) == temp_name.size() - 4) {
+ return temp_name.replace(temp_name.size() - 4, 4, " old");
+ }
+
+ return temp_name;
+}
+
} /* namespace internal */
diff --git a/intern/openvdb/intern/openvdb_dense_convert.h b/intern/openvdb/intern/openvdb_dense_convert.h
index 284fd1ceeae..e5e2965e708 100644
--- a/intern/openvdb/intern/openvdb_dense_convert.h
+++ b/intern/openvdb/intern/openvdb_dense_convert.h
@@ -36,10 +36,12 @@
#include <cstdio>
-#define TOLERANCE 1e-3f
-
namespace internal {
+/* Verify that the name does not correspond to the old format, in which case we
+ * need to replace the '_low' ending with ' low'. See T53802. */
+openvdb::Name do_name_versionning(const openvdb::Name &name);
+
openvdb::Mat4R convertMatrix(const float mat[4][4]);
template <typename GridType, typename T>
@@ -48,7 +50,8 @@ GridType *OpenVDB_export_grid(
const openvdb::Name &name,
const T *data,
const int res[3],
- float fluid_mat[4][4],
+ float fluid_mat[4][4],
+ const float clipping,
const openvdb::FloatGrid *mask)
{
using namespace openvdb;
@@ -60,7 +63,7 @@ GridType *OpenVDB_export_grid(
typename GridType::Ptr grid = GridType::create(T(0));
tools::Dense<const T, openvdb::tools::LayoutXYZ> dense_grid(bbox, data);
- tools::copyFromDense(dense_grid, grid->tree(), (T)TOLERANCE);
+ tools::copyFromDense(dense_grid, grid->tree(), static_cast<T>(clipping));
grid->setTransform(transform);
@@ -87,13 +90,19 @@ void OpenVDB_import_grid(
{
using namespace openvdb;
- if (!reader->hasGrid(name)) {
- std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str());
- memset(*data, 0, sizeof(T) * res[0] * res[1] * res[2]);
- return;
+ openvdb::Name temp_name = name;
+
+ if (!reader->hasGrid(temp_name)) {
+ temp_name = do_name_versionning(temp_name);
+
+ if (!reader->hasGrid(temp_name)) {
+ std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", temp_name.c_str());
+ memset(*data, 0, sizeof(T) * res[0] * res[1] * res[2]);
+ return;
+ }
}
- typename GridType::Ptr grid = gridPtrCast<GridType>(reader->getGrid(name));
+ typename GridType::Ptr grid = gridPtrCast<GridType>(reader->getGrid(temp_name));
typename GridType::ConstAccessor acc = grid->getConstAccessor();
math::Coord xyz;
@@ -109,15 +118,15 @@ void OpenVDB_import_grid(
}
}
-openvdb::GridBase *OpenVDB_export_vector_grid(
- OpenVDBWriter *writer,
- const openvdb::Name &name,
- const float *data_x, const float *data_y, const float *data_z,
- const int res[3],
- float fluid_mat[4][4],
- openvdb::VecType vec_type,
- const bool is_color,
- const openvdb::FloatGrid *mask);
+openvdb::GridBase *OpenVDB_export_vector_grid(OpenVDBWriter *writer,
+ const openvdb::Name &name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3],
+ float fluid_mat[4][4],
+ openvdb::VecType vec_type,
+ const bool is_color,
+ const float clipping,
+ const openvdb::FloatGrid *mask);
void OpenVDB_import_grid_vector(
diff --git a/intern/openvdb/openvdb_capi.cc b/intern/openvdb/openvdb_capi.cc
index ef4f8c8820f..1c8b51a23c4 100644
--- a/intern/openvdb/openvdb_capi.cc
+++ b/intern/openvdb/openvdb_capi.cc
@@ -39,7 +39,7 @@ int OpenVDB_getVersionHex()
OpenVDBFloatGrid *OpenVDB_export_grid_fl(
OpenVDBWriter *writer,
const char *name, float *data,
- const int res[3], float matrix[4][4],
+ const int res[3], float matrix[4][4], const float clipping,
OpenVDBFloatGrid *mask)
{
Timer(__func__);
@@ -53,6 +53,7 @@ OpenVDBFloatGrid *OpenVDB_export_grid_fl(
data,
res,
matrix,
+ clipping,
mask_grid);
return reinterpret_cast<OpenVDBFloatGrid *>(grid);
@@ -61,7 +62,7 @@ OpenVDBFloatGrid *OpenVDB_export_grid_fl(
OpenVDBIntGrid *OpenVDB_export_grid_ch(
OpenVDBWriter *writer,
const char *name, unsigned char *data,
- const int res[3], float matrix[4][4],
+ const int res[3], float matrix[4][4], const float clipping,
OpenVDBFloatGrid *mask)
{
Timer(__func__);
@@ -76,17 +77,17 @@ OpenVDBIntGrid *OpenVDB_export_grid_ch(
data,
res,
matrix,
+ clipping,
mask_grid);
return reinterpret_cast<OpenVDBIntGrid *>(grid);
}
-OpenVDBVectorGrid *OpenVDB_export_grid_vec(
- struct OpenVDBWriter *writer,
- const char *name,
- const float *data_x, const float *data_y, const float *data_z,
- const int res[3], float matrix[4][4], short vec_type,
- const bool is_color, OpenVDBFloatGrid *mask)
+OpenVDBVectorGrid *OpenVDB_export_grid_vec(struct OpenVDBWriter *writer,
+ const char *name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3], float matrix[4][4], short vec_type, const float clipping,
+ const bool is_color, OpenVDBFloatGrid *mask)
{
Timer(__func__);
@@ -105,6 +106,7 @@ OpenVDBVectorGrid *OpenVDB_export_grid_vec(
matrix,
static_cast<VecType>(vec_type),
is_color,
+ clipping,
mask_grid);
return reinterpret_cast<OpenVDBVectorGrid *>(grid);
diff --git a/intern/openvdb/openvdb_capi.h b/intern/openvdb/openvdb_capi.h
index 2d2feeadcf1..fe7af82769b 100644
--- a/intern/openvdb/openvdb_capi.h
+++ b/intern/openvdb/openvdb_capi.h
@@ -49,22 +49,20 @@ enum {
struct OpenVDBFloatGrid *OpenVDB_export_grid_fl(
struct OpenVDBWriter *writer,
const char *name, float *data,
- const int res[3], float matrix[4][4],
+ const int res[3], float matrix[4][4], const float clipping,
struct OpenVDBFloatGrid *mask);
-struct OpenVDBIntGrid *OpenVDB_export_grid_ch(
- struct OpenVDBWriter *writer,
- const char *name, unsigned char *data,
- const int res[3], float matrix[4][4],
- struct OpenVDBFloatGrid *mask);
+struct OpenVDBIntGrid *OpenVDB_export_grid_ch(struct OpenVDBWriter *writer,
+ const char *name, unsigned char *data,
+ const int res[3], float matrix[4][4], const float clipping,
+ struct OpenVDBFloatGrid *mask);
-struct OpenVDBVectorGrid *OpenVDB_export_grid_vec(
- struct OpenVDBWriter *writer,
- const char *name,
- const float *data_x, const float *data_y, const float *data_z,
- const int res[3], float matrix[4][4], short vec_type,
- const bool is_color,
- struct OpenVDBFloatGrid *mask);
+struct OpenVDBVectorGrid *OpenVDB_export_grid_vec(struct OpenVDBWriter *writer,
+ const char *name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3], float matrix[4][4], short vec_type, const float clipping,
+ const bool is_color,
+ struct OpenVDBFloatGrid *mask);
void OpenVDB_import_grid_fl(
struct OpenVDBReader *reader,
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject c93ed11a47b3016cf59711ec16de2e2e94c30e9
+Subproject 469c949d1ca882be19daa128842f813b72a944d
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 371960484a38fc64e0a2635170a41a0d8ab2f6b
+Subproject c88411ff7776a2db5d6ef6117a1b2faa42a9561
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject a8515cfdfe9a98127b592f36fcbe51b7e23b969
+Subproject 310578043dec1aae382eb6a447ae1d103792d7e
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 97fc45189f2..c74286c8fb6 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -352,6 +352,12 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
# 2) try register collected modules
# removed, addons need to handle own registration now.
+ use_owner = mod.bl_info.get("use_owner", True)
+ if use_owner:
+ from _bpy import _bl_owner_id_get, _bl_owner_id_set
+ owner_id_prev = _bl_owner_id_get()
+ _bl_owner_id_set(module_name)
+
# 3) try run the modules register function
try:
mod.register()
@@ -363,6 +369,9 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
if default_set:
_addon_remove(module_name)
return None
+ finally:
+ if use_owner:
+ _bl_owner_id_set(owner_id_prev)
# * OK loaded successfully! *
mod.__addon_enabled__ = True
@@ -473,6 +482,7 @@ def module_bl_info(mod, info_basis=None):
"category": "",
"warning": "",
"show_expanded": False,
+ "use_owner": True,
}
addon_info = getattr(mod, "bl_info", {})
@@ -490,5 +500,9 @@ def module_bl_info(mod, info_basis=None):
if not addon_info["name"]:
addon_info["name"] = mod.__name__
+ # Temporary auto-magic, don't use_owner for import export menus.
+ if mod.bl_info["category"] == "Import-Export":
+ mod.bl_info["use_owner"] = False
+
addon_info["_init"] = None
return addon_info
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 0bfb14e4e0d..a88e60d0022 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -187,7 +187,6 @@ clean_name._trans_cache = {}
def _clean_utf8(name):
- name = _os.path.splitext(basename(name))[0]
if type(name) == bytes:
return name.decode("utf8", "replace")
else:
@@ -207,6 +206,9 @@ def display_name(name):
mixed case names are kept as is. Intended for use with
filenames and module names.
"""
+
+ name = _os.path.splitext(basename(name))[0]
+
# string replacements
for disp_value, file_value in _display_name_literals.items():
name = name.replace(file_value, disp_value)
@@ -237,6 +239,7 @@ def display_name_from_filepath(name):
ensured to be utf8 compatible.
"""
+ name = _os.path.splitext(basename(name))[0]
name = _clean_utf8(name)
return name
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 6b06ff77ecd..5387af46d9d 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -766,7 +766,23 @@ class _GenericUI:
# ensure menus always get default context
operator_context_default = self.layout.operator_context
+ # Support filtering out by owner
+ workspace = context.workspace
+ if workspace.use_filter_by_owner:
+ owner_names = {owner_id.name for owner_id in workspace.owner_ids}
+ else:
+ owner_names = None
+
for func in draw_ls._draw_funcs:
+
+ # Begin 'owner_id' filter.
+ if owner_names is not None:
+ owner_id = getattr(func, "_owner", None)
+ if owner_id is not None:
+ if func._owner not in owner_names:
+ continue
+ # End 'owner_id' filter.
+
# so bad menu functions don't stop
# the entire menu from drawing
try:
@@ -782,6 +798,13 @@ class _GenericUI:
return draw_funcs
+ @staticmethod
+ def _dyn_owner_apply(draw_func):
+ from _bpy import _bl_owner_id_get
+ owner_id = _bl_owner_id_get()
+ if owner_id is not None:
+ draw_func._owner = owner_id
+
@classmethod
def is_extended(cls):
return bool(getattr(cls.draw, "_draw_funcs", None))
@@ -793,6 +816,7 @@ class _GenericUI:
takes the same arguments as the menus draw function
"""
draw_funcs = cls._dyn_ui_initialize()
+ cls._dyn_owner_apply(draw_func)
draw_funcs.append(draw_func)
@classmethod
@@ -802,6 +826,7 @@ class _GenericUI:
the menus draw function
"""
draw_funcs = cls._dyn_ui_initialize()
+ cls._dyn_owner_apply(draw_func)
draw_funcs.insert(0, draw_func)
@classmethod
diff --git a/release/scripts/presets/camera/1__colon__2.3_inch.py b/release/scripts/presets/camera/1_colon_2.3_inch.py
index 72548384401..72548384401 100644
--- a/release/scripts/presets/camera/1__colon__2.3_inch.py
+++ b/release/scripts/presets/camera/1_colon_2.3_inch.py
diff --git a/release/scripts/presets/camera/1__colon__2.5_inch.py b/release/scripts/presets/camera/1_colon_2.5_inch.py
index 90f60e7d7f0..90f60e7d7f0 100644
--- a/release/scripts/presets/camera/1__colon__2.5_inch.py
+++ b/release/scripts/presets/camera/1_colon_2.5_inch.py
diff --git a/release/scripts/presets/camera/2__colon__3_inch.py b/release/scripts/presets/camera/2_colon_3_inch.py
index 46436970efc..46436970efc 100644
--- a/release/scripts/presets/camera/2__colon__3_inch.py
+++ b/release/scripts/presets/camera/2_colon_3_inch.py
diff --git a/release/scripts/presets/camera/4__colon__3_inch.py b/release/scripts/presets/camera/4_colon_3_inch.py
index 88346c01ef8..88346c01ef8 100644
--- a/release/scripts/presets/camera/4__colon__3_inch.py
+++ b/release/scripts/presets/camera/4_colon_3_inch.py
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 9fa6dbf6eef..91a0120f6ac 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -388,102 +388,16 @@ class QuickSmoke(Operator):
node_out = nodes.new(type='ShaderNodeOutputMaterial')
node_out.location = grid_location(6, 1)
- # Add shader 1
- node_add_shader_1 = nodes.new(type='ShaderNodeAddShader')
- node_add_shader_1.location = grid_location(5, 1)
- links.new(node_add_shader_1.outputs["Shader"],
+ # Add Principled Volume
+ node_principled = nodes.new(type='ShaderNodeVolumePrincipled')
+ node_principled.location = grid_location(4, 1)
+ links.new(node_principled.outputs["Volume"],
node_out.inputs["Volume"])
- if self.style in {'SMOKE', 'FIRE', 'BOTH'}:
- # Smoke
-
- # Add shader 2
- node_add_shader_2 = nodes.new(type='ShaderNodeAddShader')
- node_add_shader_2.location = grid_location(4, 2)
- links.new(node_add_shader_2.outputs["Shader"],
- node_add_shader_1.inputs[0])
-
- # Volume scatter
- node_scatter = nodes.new(type='ShaderNodeVolumeScatter')
- node_scatter.location = grid_location(3, 3)
- links.new(node_scatter.outputs["Volume"],
- node_add_shader_2.inputs[0])
-
- # Volume absorption
- node_absorption = nodes.new(type='ShaderNodeVolumeAbsorption')
- node_absorption.location = grid_location(3, 2)
- links.new(node_absorption.outputs["Volume"],
- node_add_shader_2.inputs[1])
-
- # Density Multiplier
- node_densmult = nodes.new(type='ShaderNodeMath')
- node_densmult.location = grid_location(2, 2)
- node_densmult.operation = 'MULTIPLY'
- node_densmult.inputs[1].default_value = 5.0
- links.new(node_densmult.outputs["Value"],
- node_scatter.inputs["Density"])
- links.new(node_densmult.outputs["Value"],
- node_absorption.inputs["Density"])
-
- # Attribute "density"
- node_attrib_density = nodes.new(type='ShaderNodeAttribute')
- node_attrib_density.attribute_name = "density"
- node_attrib_density.location = grid_location(1, 2)
- links.new(node_attrib_density.outputs["Fac"],
- node_densmult.inputs[0])
-
- # Attribute "color"
- node_attrib_color = nodes.new(type='ShaderNodeAttribute')
- node_attrib_color.attribute_name = "color"
- node_attrib_color.location = grid_location(2, 3)
- links.new(node_attrib_color.outputs["Color"],
- node_scatter.inputs["Color"])
- links.new(node_attrib_color.outputs["Color"],
- node_absorption.inputs["Color"])
+ node_principled.inputs["Density"].default_value = 5.0
if self.style in {'FIRE', 'BOTH'}:
- # Fire
-
- # Emission
- node_emission = nodes.new(type='ShaderNodeEmission')
- node_emission.inputs["Color"].default_value = (0.8, 0.1, 0.01, 1.0)
- node_emission.location = grid_location(4, 1)
- links.new(node_emission.outputs["Emission"],
- node_add_shader_1.inputs[1])
-
- # Flame strength multiplier
- node_flame_strength_mult = nodes.new(type='ShaderNodeMath')
- node_flame_strength_mult.location = grid_location(3, 1)
- node_flame_strength_mult.operation = 'MULTIPLY'
- node_flame_strength_mult.inputs[1].default_value = 2.5
- links.new(node_flame_strength_mult.outputs["Value"],
- node_emission.inputs["Strength"])
-
- # Color ramp Flame
- node_flame_ramp = nodes.new(type='ShaderNodeValToRGB')
- node_flame_ramp.location = grid_location(1, 1)
- ramp = node_flame_ramp.color_ramp
- ramp.interpolation = 'EASE'
-
- # orange
- elem = ramp.elements.new(0.5)
- elem.color = (1.0, 0.128, 0.0, 1.0)
-
- # yellow
- elem = ramp.elements.new(0.9)
- elem.color = (0.9, 0.6, 0.1, 1.0)
-
- links.new(node_flame_ramp.outputs["Color"],
- node_emission.inputs["Color"])
-
- # Attribute "flame"
- node_attrib_flame = nodes.new(type='ShaderNodeAttribute')
- node_attrib_flame.attribute_name = "flame"
- node_attrib_flame.location = grid_location(0, 1)
- links.new(node_attrib_flame.outputs["Fac"],
- node_flame_ramp.inputs["Fac"])
- links.new(node_attrib_flame.outputs["Fac"],
- node_flame_strength_mult.inputs[0])
+ node_principled.inputs["Blackbody Intensity"].default_value = 1.0
# Blender Internal
else:
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 022ee1576d8..1bbb3e9883e 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1887,6 +1887,37 @@ class WM_OT_addon_disable(Operator):
return {'FINISHED'}
+class WM_OT_owner_enable(Operator):
+ """Enable workspace owner ID"""
+ bl_idname = "wm.owner_enable"
+ bl_label = "Enable Add-on"
+
+ owner_id = StringProperty(
+ name="UI Tag",
+ )
+
+ def execute(self, context):
+ workspace = context.workspace
+ workspace.owner_ids.new(self.owner_id)
+ return {'FINISHED'}
+
+
+class WM_OT_owner_disable(Operator):
+ """Enable workspace owner ID"""
+ bl_idname = "wm.owner_disable"
+ bl_label = "Disable UI Tag"
+
+ owner_id = StringProperty(
+ name="UI Tag",
+ )
+
+ def execute(self, context):
+ workspace = context.workspace
+ owner_id = workspace.owner_ids[self.owner_id]
+ workspace.owner_ids.remove(owner_id)
+ return {'FINISHED'}
+
+
class WM_OT_theme_install(Operator):
"""Load and apply a Blender XML theme file"""
bl_idname = "wm.theme_install"
@@ -2384,5 +2415,7 @@ classes = (
WM_OT_properties_remove,
WM_OT_sysinfo,
WM_OT_theme_install,
+ WM_OT_owner_disable,
+ WM_OT_owner_enable,
WM_OT_url_open,
)
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 32a1b3a771d..cd29c3f10e7 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -940,7 +940,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
scene = context.scene
- engine = scene.render.engine
+ engine = scene.view_render.engine
show_adaptive_options = (
engine == 'CYCLES' and md == ob.modifiers[-1] and
scene.cycles.feature_set == 'EXPERIMENTAL'
diff --git a/release/scripts/startup/bl_ui/properties_data_workspace.py b/release/scripts/startup/bl_ui/properties_data_workspace.py
index dae798bee95..c699fac7dd2 100644
--- a/release/scripts/startup/bl_ui/properties_data_workspace.py
+++ b/release/scripts/startup/bl_ui/properties_data_workspace.py
@@ -61,6 +61,61 @@ class WORKSPACE_PT_workspace(WorkSpaceButtonsPanel, Panel):
layout.prop(view_render, "engine", text="")
+class WORKSPACE_PT_owner_ids(WorkSpaceButtonsPanel, Panel):
+ bl_label = "Workspace Add-ons"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_header(self, context):
+ workspace = context.workspace
+ self.layout.prop(workspace, "use_filter_by_owner", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ # align just to pack more tightly
+ col = layout.box().column(align=True)
+
+ workspace = context.workspace
+ userpref = context.user_preferences
+
+ col.active = workspace.use_filter_by_owner
+
+ import addon_utils
+ addon_map = {mod.__name__: mod for mod in addon_utils.modules()}
+ owner_ids = {owner_id.name for owner_id in workspace.owner_ids}
+
+ for addon in userpref.addons:
+ module_name = addon.module
+ info = addon_utils.module_bl_info(addon_map[module_name])
+ if not info["use_owner"]:
+ continue
+ is_enabled = module_name in owner_ids
+ row = col.row()
+ row.operator(
+ "wm.owner_disable" if is_enabled else "wm.owner_enable",
+ icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT',
+ text="",
+ emboss=False,
+ ).owner_id = module_name
+ row.label("%s: %s" % (info["category"], info["name"]))
+ if is_enabled:
+ owner_ids.remove(module_name)
+
+ # Detect unused
+ if owner_ids:
+ layout.label(text="Unknown add-ons", icon='ERROR')
+ col = layout.box().column(align=True)
+ for module_name in sorted(owner_ids):
+ row = col.row()
+ row.operator(
+ "wm.owner_disable",
+ icon='CHECKBOX_HLT',
+ text="",
+ emboss=False,
+ ).owner_id = module_name
+ row.label(module_name)
+
+
+
class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel):
_context_path = "workspace"
_property_type = bpy.types.WorkSpace
@@ -69,6 +124,7 @@ class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel):
classes = (
WORKSPACE_PT_context,
WORKSPACE_PT_workspace,
+ WORKSPACE_PT_owner_ids,
WORKSPACE_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 2dc7bffa527..dfbf3eab244 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -183,7 +183,7 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
class MATERIAL_PT_preview(MaterialButtonsPanel, Panel):
bl_label = "Preview"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_EEVEE'}
def draw(self, context):
self.layout.template_preview(context.material)
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index 5cf89df63ab..d02bee3a0fa 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -68,6 +68,8 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
col.prop(domain, "time_scale", text="Scale")
col.label(text="Border Collisions:")
col.prop(domain, "collision_extents", text="")
+ col.label(text="Empty Space:")
+ col.prop(domain, "clipping")
col = split.column()
col.label(text="Behavior:")
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 94924106542..918ce0da32f 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -106,7 +106,7 @@ class SEQUENCER_HT_header(Header):
layout.prop(st, "preview_channels", expand=True, text="")
layout.prop(st, "display_channel", text="Channel")
- ed = context.scene.sequence_editor
+ ed = scene.sequence_editor
if ed:
row = layout.row(align=True)
row.prop(ed, "show_overlay", text="", icon='GHOST_ENABLED')
@@ -1076,7 +1076,7 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
- sequencer = context.scene.sequence_editor
+ ed = context.scene.sequence_editor
strip = act_strip(context)
@@ -1084,9 +1084,9 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
proxy = strip.proxy
flow = layout.column_flow()
- flow.prop(sequencer, "proxy_storage", text="Storage")
- if sequencer.proxy_storage == 'PROJECT':
- flow.prop(sequencer, "proxy_dir", text="Directory")
+ flow.prop(ed, "proxy_storage", text="Storage")
+ if ed.proxy_storage == 'PROJECT':
+ flow.prop(ed, "proxy_dir", text="Directory")
else:
flow.prop(proxy, "use_proxy_custom_directory")
flow.prop(proxy, "use_proxy_custom_file")
@@ -1192,7 +1192,7 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
layout = self.layout
strip = act_strip(context)
- sequencer = context.scene.sequence_editor
+ ed = context.scene.sequence_editor
layout.prop(strip, "use_linear_modifiers")
@@ -1223,9 +1223,9 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
row.prop(mod, "input_mask_type", expand=True)
if mod.input_mask_type == 'STRIP':
- sequences_object = sequencer
- if sequencer.meta_stack:
- sequences_object = sequencer.meta_stack[-1]
+ sequences_object = ed
+ if ed.meta_stack:
+ sequences_object = ed.meta_stack[-1]
box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
else:
box.prop(mod, "input_mask_id")
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index d1202adfce6..9026a93aa99 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -119,7 +119,7 @@ class TIME_MT_marker(Menu):
def draw(self, context):
layout = self.layout
- marker_menu_generic(layout, context)
+ marker_menu_generic(layout)
class TIME_MT_view(Menu):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index d24fafad661..77b54b3477a 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1524,12 +1524,15 @@ class USERPREF_PT_addons(Panel):
split.operator(
"wm.url_open", text="Documentation", icon='HELP',
).url = info["wiki_url"]
- split.operator(
- "wm.url_open", text="Report a Bug", icon='URL',
- ).url = info.get(
- "tracker_url",
- "https://developer.blender.org/maniphest/task/edit/form/2",
- )
+ # Only add "Report a Bug" button if tracker_url is set
+ # or the add-on is bundled (use official tracker then).
+ if info.get("tracker_url") or not user_addon:
+ split.operator(
+ "wm.url_open", text="Report a Bug", icon='URL',
+ ).url = info.get(
+ "tracker_url",
+ "https://developer.blender.org/maniphest/task/edit/form/2",
+ )
if user_addon:
split.operator(
"wm.addon_remove", text="Remove", icon='CANCEL',
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index dc8462f1af1..bb3eb1a7856 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -272,6 +272,7 @@ shader_node_categories = [
NodeItem("ShaderNodeHoldout", poll=object_cycles_shader_nodes_poll),
NodeItem("ShaderNodeVolumeAbsorption", poll=eevee_cycles_shader_nodes_poll),
NodeItem("ShaderNodeVolumeScatter", poll=eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeVolumePrincipled"),
NodeItem("ShaderNodeEeveeSpecular", poll=object_eevee_shader_nodes_poll),
]),
ShaderNewNodeCategory("SH_NEW_TEXTURE", "Texture", items=[
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index c3cea6c883c..9d48ddb4f32 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -167,7 +167,7 @@ typedef enum DMDirtyFlag {
DM_DIRTY_TESS_CDLAYERS = 1 << 0,
/* One of the MCOL layers have been updated, force updating of GPUDrawObject's colors buffer.
* This is necessary with modern, VBO draw code, as e.g. in vpaint mode me->mcol may be updated
- * without actually rebuilding dm (hence by defautl keeping same GPUDrawObject, and same colors
+ * without actually rebuilding dm (hence by default keeping same GPUDrawObject, and same colors
* buffer, which prevents update during a stroke!). */
DM_DIRTY_MCOL_UPDATE_DRAW = 1 << 1,
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index ceb466ebdcd..901f9e6d3ac 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 4
+#define BLENDER_SUBVERSION 5
/* 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_collection.h b/source/blender/blenkernel/BKE_collection.h
index 3bf14346ccb..af8047bf373 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -83,7 +83,7 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
-#define FOREACH_SCENE_COLLECTION(_id, _instance) \
+#define FOREACH_SCENE_COLLECTION_BEGIN(_id, _instance) \
ITER_BEGIN(BKE_scene_collections_iterator_begin, \
BKE_scene_collections_iterator_next, \
BKE_scene_collections_iterator_end, \
@@ -92,7 +92,7 @@ void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
#define FOREACH_SCENE_COLLECTION_END \
ITER_END
-#define FOREACH_SCENE_OBJECT(scene, _instance) \
+#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance) \
ITER_BEGIN(BKE_scene_objects_iterator_begin, \
BKE_scene_objects_iterator_next, \
BKE_scene_objects_iterator_end, \
diff --git a/source/blender/blenkernel/BKE_editlattice.h b/source/blender/blenkernel/BKE_editlattice.h
new file mode 100644
index 00000000000..476cf535e97
--- /dev/null
+++ b/source/blender/blenkernel/BKE_editlattice.h
@@ -0,0 +1,34 @@
+/*
+ * ***** 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 BKE_editlattice.h
+ * \ingroup bke
+ */
+
+#ifndef __BKE_EDITLATTICE_H__
+#define __BKE_EDITLATTICE_H__
+
+struct Object;
+
+void BKE_editlattice_free(struct Object *ob);
+void BKE_editlattice_make(struct Object *obedit);
+void BKE_editlattice_load(struct Object *obedit);
+
+#endif /* __BKE_EDITLATTICE_H__ */
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 80a8f750d20..9adc00a67e6 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -122,13 +122,21 @@ enum {
G_DEBUG_WM = (1 << 5), /* operator, undo */
G_DEBUG_JOBS = (1 << 6), /* jobs time profiling */
G_DEBUG_FREESTYLE = (1 << 7), /* freestyle messages */
- G_DEBUG_DEPSGRAPH = (1 << 8), /* depsgraph messages */
- G_DEBUG_SIMDATA = (1 << 9), /* sim debug data display */
- G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */
- G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* single threaded depsgraph */
- G_DEBUG_GPU = (1 << 12), /* gpu debug */
- G_DEBUG_IO = (1 << 13), /* IO Debugging (for Collada, ...)*/
- G_DEBUG_GPU_SHADERS = (1 << 14), /* GLSL shaders */
+ G_DEBUG_DEPSGRAPH_BUILD = (1 << 8), /* depsgraph construction messages */
+ G_DEBUG_DEPSGRAPH_EVAL = (1 << 9), /* depsgraph evaluation messages */
+ G_DEBUG_DEPSGRAPH_TAG = (1 << 10), /* depsgraph tagging messages */
+ G_DEBUG_DEPSGRAPH_TIME = (1 << 11), /* depsgraph timing statistics and messages */
+ G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 12), /* single threaded depsgraph */
+ G_DEBUG_DEPSGRAPH_PRETTY = (1 << 13), /* use pretty colors in depsgraph messages */
+ G_DEBUG_DEPSGRAPH = (G_DEBUG_DEPSGRAPH_BUILD |
+ G_DEBUG_DEPSGRAPH_EVAL |
+ G_DEBUG_DEPSGRAPH_TAG |
+ G_DEBUG_DEPSGRAPH_TIME),
+ G_DEBUG_SIMDATA = (1 << 14), /* sim debug data display */
+ G_DEBUG_GPU_MEM = (1 << 15), /* gpu memory in status bar */
+ G_DEBUG_GPU = (1 << 16), /* gpu debug */
+ G_DEBUG_IO = (1 << 17), /* IO Debugging (for Collada, ...)*/
+ G_DEBUG_GPU_SHADERS = (1 << 18), /* GLSL shaders */
};
#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 74255cfc941..a842bec7609 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -62,7 +62,7 @@ void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx,
/* Helper macros. */
-#define FOREACH_GROUP_BASE(_group, _base) \
+#define FOREACH_GROUP_BASE_BEGIN(_group, _base) \
for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \
_base; \
_base = _base->next) \
@@ -71,7 +71,7 @@ void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx,
#define FOREACH_GROUP_BASE_END \
}
-#define FOREACH_GROUP_OBJECT(_group, _object) \
+#define FOREACH_GROUP_OBJECT_BEGIN(_group, _object) \
for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \
_base; \
_base = _base->next) \
@@ -80,6 +80,6 @@ void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx,
BLI_assert(_object != NULL);
#define FOREACH_GROUP_OBJECT_END \
- }
+ } ((void)0)
#endif /* __BKE_GROUP_H__ */
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 39e6b145755..a9ca5cc8bbb 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -58,19 +58,19 @@ int BKE_icon_id_ensure(struct ID *id);
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
-struct Icon *BKE_icon_get(int icon_id);
+struct Icon *BKE_icon_get(const int icon_id);
/* set icon for id if not already defined */
/* used for inserting the internal icons */
-void BKE_icon_set(int icon_id, struct Icon *icon);
+void BKE_icon_set(const int icon_id, struct Icon *icon);
/* remove icon and free data if library object becomes invalid */
void BKE_icon_id_delete(struct ID *id);
-void BKE_icon_delete(int icon_id);
+void BKE_icon_delete(const int icon_id);
/* report changes - icon needs to be recalculated */
-void BKE_icon_changed(int icon_id);
+void BKE_icon_changed(const int icon_id);
/* free all icons */
void BKE_icons_free(void);
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 17b854e5bf7..59aec53aa1e 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -199,7 +199,7 @@ void BKE_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
void BKE_visible_bases_iterator_next(BLI_Iterator *iter);
void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
-#define FOREACH_SELECTED_OBJECT(view_layer, _instance) \
+#define FOREACH_SELECTED_OBJECT_BEGIN(view_layer, _instance) \
ITER_BEGIN(BKE_selected_objects_iterator_begin, \
BKE_selected_objects_iterator_next, \
BKE_selected_objects_iterator_end, \
@@ -208,7 +208,7 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_SELECTED_OBJECT_END \
ITER_END
-#define FOREACH_VISIBLE_OBJECT(view_layer, _instance) \
+#define FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, _instance) \
ITER_BEGIN(BKE_visible_objects_iterator_begin, \
BKE_visible_objects_iterator_next, \
BKE_visible_objects_iterator_end, \
@@ -217,7 +217,7 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_VISIBLE_OBJECT_END \
ITER_END
-#define FOREACH_SELECTED_BASE(view_layer, _instance) \
+#define FOREACH_SELECTED_BASE_BEGIN(view_layer, _instance) \
ITER_BEGIN(BKE_selected_bases_iterator_begin, \
BKE_selected_bases_iterator_next, \
BKE_selected_bases_iterator_end, \
@@ -226,7 +226,7 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_SELECTED_BASE_END \
ITER_END
-#define FOREACH_VISIBLE_BASE(view_layer, _instance) \
+#define FOREACH_VISIBLE_BASE_BEGIN(view_layer, _instance) \
ITER_BEGIN(BKE_visible_bases_iterator_begin, \
BKE_visible_bases_iterator_next, \
BKE_visible_bases_iterator_end, \
@@ -236,7 +236,7 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
ITER_END
-#define FOREACH_OBJECT(view_layer, _instance) \
+#define FOREACH_OBJECT_BEGIN(view_layer, _instance) \
{ \
Object *_instance; \
Base *_base; \
@@ -245,9 +245,9 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_OBJECT_END \
} \
-}
+} ((void)0)
-#define FOREACH_OBJECT_FLAG(scene, view_layer, flag, _instance) \
+#define FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, _instance) \
{ \
IteratorBeginCb func_begin; \
IteratorCb func_next, func_end; \
@@ -269,10 +269,10 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_OBJECT_FLAG_END \
- ITER_END \
-}
+ ITER_END; \
+} ((void)0)
-typedef struct ObjectsRenderableIteratorData {
+struct ObjectsRenderableIteratorData {
struct Scene *scene;
struct Base base_temp;
struct Scene scene_temp;
@@ -282,10 +282,11 @@ typedef struct ObjectsRenderableIteratorData {
struct Base *base;
struct Scene *set;
} iter;
-} ObjectsRenderableIteratorData;
+};
-#define FOREACH_OBJECT_RENDERABLE(scene_, _instance) \
- ObjectsRenderableIteratorData data_ = { \
+#define FOREACH_OBJECT_RENDERABLE_BEGIN(scene_, _instance) \
+{ \
+ struct ObjectsRenderableIteratorData data_ = { \
.scene = (scene_), \
}; \
ITER_BEGIN(BKE_renderable_objects_iterator_begin, \
@@ -295,7 +296,8 @@ typedef struct ObjectsRenderableIteratorData {
#define FOREACH_OBJECT_RENDERABLE_END \
- ITER_END
+ ITER_END; \
+} ((void)0)
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 5ee3b9be5f9..19caf30a280 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -193,6 +193,24 @@ void BKE_mesh_calc_normals_looptri(
const struct MLoop *mloop,
const struct MLoopTri *looptri, int looptri_num,
float (*r_tri_nors)[3]);
+void BKE_mesh_loop_tangents_ex(
+ const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
+ const int numLoops, const struct MPoly *mpolys, const int numPolys,
+ struct ReportList *reports);
+void BKE_mesh_loop_tangents(
+ struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
+void BKE_mesh_loop_manifold_fan_around_vert_next(
+ const struct MLoop *mloops, const struct MPoly *mpolys,
+ const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
+ const struct MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index);
+
+void BKE_edges_sharp_from_angle_set(
+ const struct MVert *mverts, const int numVerts,
+ struct MEdge *medges, const int numEdges,
+ struct MLoop *mloops, const int numLoops,
+ struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ const float split_angle);
/**
* References a contiguous loop-fan with normal offset vars.
@@ -203,17 +221,38 @@ typedef struct MLoopNorSpace {
float vec_ortho[3]; /* Third vector, orthogonal to vec_lnor and vec_ref. */
float ref_alpha; /* Reference angle, around vec_ortho, in ]0, pi] range (0.0 marks that space as invalid). */
float ref_beta; /* Reference angle, around vec_lnor, in ]0, 2pi] range (0.0 marks that space as invalid). */
- struct LinkNode *loops; /* All indices (uint_in_ptr) of loops using this lnor space (i.e. smooth fan of loops). */
+ /* All loops using this lnor space (i.e. smooth fan of loops),
+ * as (depending on owning MLoopNorSpaceArrary.data_type):
+ * - Indices (uint_in_ptr), or
+ * - BMLoop pointers. */
+ struct LinkNode *loops;
+ char flags;
} MLoopNorSpace;
/**
+ * MLoopNorSpace.flags
+ */
+enum {
+ MLNOR_SPACE_IS_SINGLE = 1 << 0,
+};
+
+/**
* Collection of #MLoopNorSpace basic storage & pre-allocation.
*/
typedef struct MLoopNorSpaceArray {
MLoopNorSpace **lspacearr; /* MLoop aligned array */
struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */
+ char data_type; /* Whether we store loop indices, or pointers to BMLoop. */
struct MemArena *mem;
} MLoopNorSpaceArray;
-void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops);
+/**
+ * MLoopNorSpaceArray.data_type
+ */
+enum {
+ MLNOR_SPACEARR_LOOP_INDEX = 0,
+ MLNOR_SPACEARR_BMLOOP_PTR = 1,
+};
+
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops, const char data_type);
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
@@ -221,7 +260,8 @@ void BKE_lnor_space_define(
MLoopNorSpace *lnor_space, const float lnor[3], float vec_ref[3], float vec_other[3],
struct BLI_Stack *edge_vectors);
void BKE_lnor_space_add_loop(
- MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int ml_index, const bool add_to_list);
+ MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space,
+ const int ml_index, void *bm_loop, const bool is_single);
void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3]);
void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2]);
@@ -234,7 +274,7 @@ void BKE_mesh_normals_loop_split(
const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- const bool use_split_normals, float split_angle,
+ const bool use_split_normals, const float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly);
void BKE_mesh_normals_loop_custom_set(
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 8ee67850e5f..e1ce58ba69b 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -34,8 +34,6 @@
struct ID;
struct DerivedMesh;
-struct DagForest;
-struct DagNode;
struct EvaluationContext;
struct Object;
struct Scene;
@@ -129,6 +127,12 @@ typedef enum ModifierApplyFlag {
} ModifierApplyFlag;
+typedef struct ModifierUpdateDepsgraphContext {
+ struct Scene *scene;
+ struct Object *object;
+ struct DepsNodeHandle *node;
+} ModifierUpdateDepsgraphContext;
+
typedef struct ModifierTypeInfo {
/* The user visible name for this modifier */
char name[32];
@@ -268,11 +272,8 @@ typedef struct ModifierTypeInfo {
* This function is optional.
*/
void (*updateDepsgraph)(struct ModifierData *md,
- struct Main *bmain,
- struct Scene *scene,
- struct Object *ob,
- struct DepsNodeHandle *node);
-
+ const ModifierUpdateDepsgraphContext *ctx);
+
/* Should return true if the modifier needs to be recalculated on time
* changes.
*
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index bd193b82b9e..818f79ad8ac 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -60,6 +60,7 @@ struct ImBuf *BKE_movieclip_get_ibuf_flag(struct MovieClip *clip, struct MovieCl
void BKE_movieclip_get_size(struct MovieClip *clip, struct MovieClipUser *user, int *width, int *height);
void BKE_movieclip_get_size_fl(struct MovieClip *clip, struct MovieClipUser *user, float size[2]);
int BKE_movieclip_get_duration(struct MovieClip *clip);
+float BKE_movieclip_get_fps(struct MovieClip *clip);
void BKE_movieclip_get_aspect(struct MovieClip *clip, float *aspx, float *aspy);
bool BKE_movieclip_has_frame(struct MovieClip *clip, struct MovieClipUser *user);
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr);
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 8d9fc8ff6cf..4509d374b02 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -46,18 +46,18 @@ struct PropertyRNA;
/* ----------------------------- */
/* Data Management */
-void free_nlastrip(ListBase *strips, struct NlaStrip *strip);
-void free_nlatrack(ListBase *tracks, struct NlaTrack *nlt);
-void free_nladata(ListBase *tracks);
-
-struct NlaStrip *copy_nlastrip(struct NlaStrip *strip, const bool use_same_action);
-struct NlaTrack *copy_nlatrack(struct NlaTrack *nlt, const bool use_same_actions);
-void copy_nladata(ListBase *dst, ListBase *src);
-
-struct NlaTrack *add_nlatrack(struct AnimData *adt, struct NlaTrack *prev);
-struct NlaStrip *add_nlastrip(struct bAction *act);
-struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act);
-struct NlaStrip *add_nla_soundstrip(struct Scene *scene, struct Speaker *spk);
+void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip);
+void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt);
+void BKE_nla_tracks_free(ListBase *tracks);
+
+struct NlaStrip *BKE_nlastrip_copy(struct NlaStrip *strip, const bool use_same_action);
+struct NlaTrack *BKE_nlatrack_copy(struct NlaTrack *nlt, const bool use_same_actions);
+void BKE_nla_tracks_copy(ListBase *dst, ListBase *src);
+
+struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, struct NlaTrack *prev);
+struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
+struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt, struct bAction *act);
+struct NlaStrip *BKE_nla_add_soundstrip(struct Scene *scene, struct Speaker *spk);
/* ----------------------------- */
/* API */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 770b2b4a185..6427a87a182 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -575,7 +575,6 @@ void BKE_node_preview_set_pixel(struct bNodePreview *preview, const f
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Node Type Access
* \{ */
@@ -605,6 +604,7 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufu
void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *));
void node_type_compatibility(struct bNodeType *ntype, short compatibility);
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Generic Functions
@@ -701,7 +701,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, c
/* -------------------------------------------------------------------- */
/** \name Shader Nodes
- */
+ * \{ */
struct ShadeInput;
struct ShadeResult;
@@ -802,6 +802,7 @@ struct ShadeResult;
#define SH_NODE_BEVEL 197
#define SH_NODE_DISPLACEMENT 198
#define SH_NODE_VECTOR_DISPLACEMENT 199
+#define SH_NODE_VOLUME_PRINCIPLED 200
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -826,7 +827,7 @@ void ntreeGPUMaterialDomain(struct bNodeTree *ntree, bool *has_surfac
/* -------------------------------------------------------------------- */
/** \name Composite Nodes
- */
+ * \{ */
/* output socket defines */
#define RRES_OUT_IMAGE 0
@@ -1010,7 +1011,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
/* -------------------------------------------------------------------- */
/** \name Texture Nodes
- */
+ * \{ */
struct TexResult;
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 536b21e83ce..11e259e0318 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -146,13 +146,19 @@ bool BKE_object_pose_context_check(struct Object *ob);
struct Object *BKE_object_pose_armature_get(struct Object *ob);
struct Object *BKE_object_pose_armature_get_visible(struct Object *ob, struct ViewLayer *view_layer);
-void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob,
- struct Object *par, float parentmat[4][4]);
-void BKE_object_where_is_calc(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
-void BKE_object_where_is_calc_ex(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
-void BKE_object_where_is_calc_time(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, float ctime);
-void BKE_object_where_is_calc_time_ex(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, float ctime,
- struct RigidBodyWorld *rbw, float r_originmat[3][3]);
+void BKE_object_get_parent_matrix(
+ struct Scene *scene, struct Object *ob,
+ struct Object *par, float parentmat[4][4]);
+void BKE_object_where_is_calc(
+ const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
+void BKE_object_where_is_calc_ex(
+ const struct EvaluationContext *eval_ctx, struct Scene *scene, struct RigidBodyWorld *rbw,
+ struct Object *ob, float r_originmat[3][3]);
+void BKE_object_where_is_calc_time(
+ const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, float ctime);
+void BKE_object_where_is_calc_time_ex(
+ const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, float ctime,
+ struct RigidBodyWorld *rbw, float r_originmat[3][3]);
void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float obmat[4][4]);
/* possibly belong in own moduke? */
@@ -168,14 +174,17 @@ void BKE_object_dimensions_set(struct Object *ob, const float value[3]);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
-bool BKE_object_minmax_dupli(struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
+bool BKE_object_minmax_dupli(
+ struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
/* sometimes min-max isn't enough, we need to loop over each point */
-void BKE_object_foreach_display_point(struct Object *ob, float obmat[4][4],
- void (*func_cb)(const float[3], void *), void *user_data);
-void BKE_scene_foreach_display_point(struct Scene *scene,
- struct ViewLayer *view_layer,
- void (*func_cb)(const float[3], void *), void *user_data);
+void BKE_object_foreach_display_point(
+ struct Object *ob, float obmat[4][4],
+ void (*func_cb)(const float[3], void *), void *user_data);
+void BKE_scene_foreach_display_point(
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ void (*func_cb)(const float[3], void *), void *user_data);
bool BKE_object_parent_loop_check(const struct Object *parent, const struct Object *ob);
@@ -191,48 +200,61 @@ typedef struct ObjectTfmProtectedChannels {
float rotAngle, drotAngle;
} ObjectTfmProtectedChannels;
-void BKE_object_tfm_protected_backup(const struct Object *ob,
- ObjectTfmProtectedChannels *obtfm);
+void BKE_object_tfm_protected_backup(
+ const struct Object *ob,
+ ObjectTfmProtectedChannels *obtfm);
-void BKE_object_tfm_protected_restore(struct Object *ob,
- const ObjectTfmProtectedChannels *obtfm,
- const short protectflag);
+void BKE_object_tfm_protected_restore(
+ struct Object *ob,
+ const ObjectTfmProtectedChannels *obtfm,
+ const short protectflag);
/* Dependency graph evaluation callbacks. */
-void BKE_object_eval_local_transform(const struct EvaluationContext *eval_ctx,
- struct Object *ob);
-void BKE_object_eval_parent(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-void BKE_object_eval_constraints(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
+void BKE_object_eval_local_transform(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *ob);
+void BKE_object_eval_parent(
+ const struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_constraints(
+ const struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
void BKE_object_eval_done(const struct EvaluationContext *eval_ctx, struct Object *ob);
-bool BKE_object_eval_proxy_copy(const struct EvaluationContext *eval_ct,
- struct Object *object);
-void BKE_object_eval_uber_transform(const struct EvaluationContext *eval_ctx,
- struct Object *ob);
-void BKE_object_eval_uber_data(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
+bool BKE_object_eval_proxy_copy(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *object);
+void BKE_object_eval_uber_transform(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *ob);
+void BKE_object_eval_uber_data(
+ const struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
-void BKE_object_eval_cloth(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *object);
+void BKE_object_eval_cloth(
+ const struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *object);
-void BKE_object_eval_transform_all(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *object);
+void BKE_object_eval_transform_all(
+ const struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *object);
-void BKE_object_eval_update_shading(const struct EvaluationContext *eval_ctx,
- struct Object *object);
-void BKE_object_data_select_update(const struct EvaluationContext *eval_ctx,
- struct ID *object_data);
+void BKE_object_eval_update_shading(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *object);
+void BKE_object_data_select_update(
+ const struct EvaluationContext *eval_ctx,
+ struct ID *object_data);
-void BKE_object_eval_flush_base_flags(const struct EvaluationContext *eval_ctx,
- struct Object *object, struct Base *base,
- const bool is_from_set);
+void BKE_object_eval_flush_base_flags(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *object, struct Base *base,
+ const bool is_from_set);
void BKE_object_handle_data_update(
const struct EvaluationContext *eval_ctx,
@@ -246,7 +268,6 @@ void BKE_object_handle_update_ex(
struct Scene *scene, struct Object *ob,
struct RigidBodyWorld *rbw,
const bool do_proxy_update);
-
void BKE_object_sculpt_modifiers_changed(struct Object *ob);
int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
@@ -289,7 +310,8 @@ typedef enum eObjectSet {
OB_SET_ALL /* All Objects */
} eObjectSet;
-struct LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter);
+struct LinkNode *BKE_object_relational_superset(
+ struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter);
struct LinkNode *BKE_object_groups(struct Object *ob);
void BKE_object_groups_clear(struct Object *object);
@@ -297,8 +319,9 @@ struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
-bool BKE_object_modifier_update_subframe(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob,
- bool update_mesh, int parent_recursion, float frame, int type);
+bool BKE_object_modifier_update_subframe(
+ const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob,
+ bool update_mesh, int parent_recursion, float frame, int type);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index 19a2220006a..ab54330cf53 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -54,7 +54,8 @@ void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked);
void BKE_object_defgroup_remove_all(struct Object *ob);
-
+int *BKE_object_defgroup_index_map_create(struct Object *ob_src, struct Object *ob_dst, int *r_map_len);
+void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert, int dvert_len, const int *map, int map_len);
/* Select helpers */
enum eVGroupSelect;
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index bb435df136d..bd36bb000b4 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -111,6 +111,9 @@ void BKE_scene_object_base_flag_sync_from_object(struct Base *base);
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
+struct ToolSettings *BKE_toolsettings_copy(struct ToolSettings *toolsettings, const int flag);
+void BKE_toolsettings_free(struct ToolSettings *toolsettings);
+
void BKE_scene_copy_data(struct Main *bmain, struct Scene *sce_dst, const struct Scene *sce_src, const int flag);
struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type);
void BKE_scene_groups_relink(struct Scene *sce);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 94d78ae47e3..edf86de1783 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -195,6 +195,7 @@ typedef struct PanelType {
char translation_context[BKE_ST_MAXNAME];
char context[BKE_ST_MAXNAME]; /* for buttons window */
char category[BKE_ST_MAXNAME]; /* for category tabs */
+ char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */
int space_type;
int region_type;
@@ -266,6 +267,7 @@ typedef struct MenuType {
char idname[BKE_ST_MAXNAME]; /* unique name */
char label[BKE_ST_MAXNAME]; /* for button text */
char translation_context[BKE_ST_MAXNAME];
+ char owner_id[BKE_ST_MAXNAME]; /* optional, see: #wmOwnerID */
const char *description;
/* verify if the menu should draw or not */
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 2264167eca1..62e09809dea 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -405,6 +405,8 @@ struct Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine);
void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq);
void BKE_sequence_init_colorspace(struct Sequence *seq);
+float BKE_sequence_get_fps(struct Scene *scene, struct Sequence *seq);
+
/* RNA enums, just to be more readable */
enum {
SEQ_SIDE_NONE = 0,
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index b309ae838d6..0aff79b7e30 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -136,6 +136,9 @@ void BKE_workspace_update_object_mode(
struct Object *BKE_workspace_edit_object(
struct WorkSpace *workspace, struct Scene *scene);
+bool BKE_workspace_owner_id_check(
+ const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL();
+
#undef GETTER_ATTRS
#undef SETTER_ATTRS
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 3f6bb5b9954..f36a9e99a64 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -103,6 +103,7 @@ set(SRC
intern/displist.c
intern/dynamicpaint.c
intern/editderivedmesh.c
+ intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
intern/editmesh_tangent.c
@@ -238,6 +239,7 @@ set(SRC
BKE_deform.h
BKE_displist.h
BKE_dynamicpaint.h
+ BKE_editlattice.h
BKE_editmesh.h
BKE_editmesh_bvh.h
BKE_editmesh_tangent.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 67463ffe915..3001b1f05d5 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -3489,17 +3489,25 @@ void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
{
int i;
if (attribs->totorco) {
- glUniform1i(attribs->orco.gl_info_index, 0);
+ if (attribs->orco.gl_info_index != -1) {
+ glUniform1i(attribs->orco.gl_info_index, 0);
+ }
}
for (i = 0; i < attribs->tottface; i++) {
- glUniform1i(attribs->tface[i].gl_info_index, 0);
+ if (attribs->tface[i].gl_info_index != -1) {
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
+ }
}
for (i = 0; i < attribs->totmcol; i++) {
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ if (attribs->mcol[i].gl_info_index != -1) {
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ }
}
for (i = 0; i < attribs->tottang; i++) {
- glUniform1i(attribs->tang[i].gl_info_index, 0);
+ if (attribs->tang[i].gl_info_index != -1) {
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 844a2a50bb3..ecdb180d2ed 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -77,6 +77,8 @@
#include "atomic_ops.h"
+#include "DEG_depsgraph.h"
+
/* ***************************************** */
/* AnimData API */
@@ -245,7 +247,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
}
/* free nla data */
- free_nladata(&adt->nla_tracks);
+ BKE_nla_tracks_free(&adt->nla_tracks);
/* free drivers - stored as a list of F-Curves */
free_fcurves(&adt->drivers);
@@ -284,7 +286,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
}
/* duplicate NLA data */
- copy_nladata(&dadt->nla_tracks, &adt->nla_tracks);
+ BKE_nla_tracks_copy(&dadt->nla_tracks, &adt->nla_tracks);
/* duplicate drivers (F-Curves) */
copy_fcurves(&dadt->drivers, &adt->drivers);
@@ -366,7 +368,7 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a
if (src->nla_tracks.first) {
ListBase tracks = {NULL, NULL};
- copy_nladata(&tracks, &src->nla_tracks);
+ BKE_nla_tracks_copy(&tracks, &src->nla_tracks);
BLI_movelisttolist(&dst->nla_tracks, &tracks);
}
@@ -2879,18 +2881,34 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* ************** */
/* Evaluation API */
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
-
void BKE_animsys_eval_animdata(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 dependency graph instead...
*/
- DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime);
+ DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime);
BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
}
+/* TODO(sergey): This is slow lookup of driver from CoW datablock.
+ * Keep this for until we've got something smarter for depsgraph
+ * building.\
+ */
+static FCurve *find_driver_from_evaluated_id(ID *id, FCurve *fcu)
+{
+ /* We've got non-CoW datablock, can use f-curve as-is. */
+ if (id->orig_id == NULL) {
+ return fcu;
+ }
+ /*const*/ ID *id_orig = id->orig_id;
+ const AnimData *adt_orig = BKE_animdata_from_id(id_orig);
+ const AnimData *adt_cow = BKE_animdata_from_id(id);
+ const int fcu_index = BLI_findindex(&adt_orig->drivers, fcu);
+ BLI_assert(fcu_index != -1);
+ return BLI_findlink(&adt_cow->drivers, fcu_index);
+}
+
void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx,
ID *id,
FCurve *fcu)
@@ -2900,11 +2918,10 @@ void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx,
PointerRNA id_ptr;
bool ok = false;
- DEBUG_PRINT("%s on %s (%s[%d])\n",
- __func__,
- id->name,
- fcu->rna_path,
- fcu->array_index);
+ fcu = find_driver_from_evaluated_id(id, fcu);
+
+ DEG_debug_print_eval_subdata_index(
+ __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
RNA_id_pointer_create(id, &id_ptr);
@@ -2937,5 +2954,3 @@ void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx,
}
}
}
-
-#undef DEBUG_PRINT
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index de0dfe2530d..bf065ef992c 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -50,7 +50,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#include "DEG_depsgraph.h"
/* ********************** SPLINE IK SOLVER ******************* */
@@ -566,7 +566,7 @@ void BKE_pose_eval_init(const struct EvaluationContext *UNUSED(eval_ctx),
{
bPoseChannel *pchan;
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
@@ -588,7 +588,7 @@ void BKE_pose_eval_init_ik(const struct EvaluationContext *eval_ctx,
Object *ob,
bPose *UNUSED(pose))
{
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
@@ -609,7 +609,8 @@ void BKE_pose_eval_bone(const struct EvaluationContext *eval_ctx,
Object *ob,
bPoseChannel *pchan)
{
- DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ DEG_debug_print_eval_subdata(
+ __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
BLI_assert(ob->type == OB_ARMATURE);
bArmature *arm = (bArmature *)ob->data;
if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
@@ -644,7 +645,8 @@ void BKE_pose_constraints_evaluate(const struct EvaluationContext *eval_ctx,
Object *ob,
bPoseChannel *pchan)
{
- DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ DEG_debug_print_eval_subdata(
+ __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
@@ -664,7 +666,7 @@ void BKE_pose_bone_done(const struct EvaluationContext *UNUSED(eval_ctx),
bPoseChannel *pchan)
{
float imat[4][4];
- DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name);
+ DEG_debug_print_eval(__func__, pchan->name, pchan);
if (pchan->bone) {
invert_m4_m4(imat, pchan->bone->arm_mat);
mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
@@ -676,7 +678,8 @@ void BKE_pose_iktree_evaluate(const struct EvaluationContext *eval_ctx,
Object *ob,
bPoseChannel *rootchan)
{
- DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ DEG_debug_print_eval_subdata(
+ __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
@@ -690,8 +693,10 @@ void BKE_pose_splineik_evaluate(const struct EvaluationContext *eval_ctx,
Scene *scene,
Object *ob,
bPoseChannel *rootchan)
+
{
- DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ DEG_debug_print_eval_subdata(
+ __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
@@ -707,7 +712,7 @@ void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx),
bPose *UNUSED(pose))
{
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
/* 6. release the IK tree */
@@ -717,7 +722,7 @@ void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
ob->id.name + 2, ob->proxy_from->id.name + 2);
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index c92096efd07..fb27249402b 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -218,7 +218,7 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc)
ListBase collection_objects;
BLI_duplicatelist(&collection_objects, &sc->objects);
- FOREACH_SCENE_COLLECTION(owner_id, scene_collection_iter)
+ FOREACH_SCENE_COLLECTION_BEGIN(owner_id, scene_collection_iter)
{
if (scene_collection_iter == sc) {
continue;
@@ -236,7 +236,7 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc)
link = link_next;
}
}
- FOREACH_SCENE_COLLECTION_END
+ FOREACH_SCENE_COLLECTION_END;
for (LinkData *link = collection_objects.first; link; link = link->next) {
BKE_collection_object_add(owner_id, sc_master, link->data);
@@ -405,13 +405,13 @@ bool BKE_collection_object_add(const ID *owner_id, SceneCollection *sc, Object *
*/
void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst)
{
- FOREACH_SCENE_COLLECTION(scene, sc)
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, sc)
{
if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) {
collection_object_add(&scene->id, sc, ob_dst);
}
}
- FOREACH_SCENE_COLLECTION_END
+ FOREACH_SCENE_COLLECTION_END;
for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
Base *base_src = BKE_view_layer_base_find(view_layer, ob_src);
@@ -480,11 +480,11 @@ bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const
BLI_assert(GS(owner_id->name) == ID_GR);
}
- FOREACH_SCENE_COLLECTION(owner_id, sc)
+ FOREACH_SCENE_COLLECTION_BEGIN(owner_id, sc)
{
removed |= BKE_collection_object_remove(bmain, owner_id, sc, ob, free_us);
}
- FOREACH_SCENE_COLLECTION_END
+ FOREACH_SCENE_COLLECTION_END;
return removed;
}
@@ -552,11 +552,11 @@ Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *l
sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name);
BKE_collection_copy_data(sc_dst, sc_src, 0);
- FOREACH_SCENE_COLLECTION(&group->id, sc_group)
+ FOREACH_SCENE_COLLECTION_BEGIN(&group->id, sc_group)
{
sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL;
}
- FOREACH_SCENE_COLLECTION_END
+ FOREACH_SCENE_COLLECTION_END;
lc_dst = BKE_collection_link(group->view_layer, sc_dst);
layer_collection_sync(lc_dst, lc_src);
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 21945f07a10..c1872c92418 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -506,11 +506,11 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
Group *group= ob->dup_group;
/* add objects */
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
add_collision_object(objs, numobj, maxobj, object, self, level+1, modifier_type);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
@@ -527,11 +527,11 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsi
/* gather all collision objects */
if (group) {
/* use specified group */
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
add_collision_object(&objs, &numobj, &maxobj, object, self, level, modifier_type);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
else {
Scene *sce_iter;
@@ -584,11 +584,11 @@ static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self,
Group *group= ob->dup_group;
/* add objects */
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
add_collider_cache_object(objs, object, self, level+1);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
@@ -598,11 +598,11 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
/* add object in same layer in scene */
if (group) {
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
add_collider_cache_object(&objs, object, self, 0);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
else {
Scene *sce_iter;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index b8dc7944a75..b070ccdd4eb 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -1917,14 +1917,15 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *
bSameVolumeConstraint *data = con->data;
float volume = data->volume;
- float fac = 1.0f;
+ float fac = 1.0f, total_scale;
float obsize[3];
mat4_to_size(obsize, cob->matrix);
/* calculate normalizing scale factor for non-essential values */
- if (obsize[data->flag] != 0)
- fac = sqrtf(volume / obsize[data->flag]);
+ total_scale = obsize[0] * obsize[1] * obsize[2];
+ if (total_scale != 0)
+ fac = sqrtf(volume / total_scale);
/* apply scaling factor to the channels not being kept */
switch (data->flag) {
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 2a27bad0fb5..0c4dbdf7763 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -5258,9 +5258,7 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
void BKE_curve_eval_geometry(const EvaluationContext *UNUSED(eval_ctx),
Curve *curve)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s\n", __func__, curve->id.name);
- }
+ DEG_debug_print_eval(__func__, curve->id.name, curve);
if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
BKE_curve_texspace_calc(curve);
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 349f995819c..22a1f9b4b18 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -3348,7 +3348,7 @@ typedef struct BrushMaterials {
/* Initialize materials for brush object:
* Calculates inverse matrices for linked objects, updates
* volume caches etc. */
-static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
+static void dynamicPaint_updateBrushMaterials(const EvaluationContext *eval_ctx, Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
{
/* Calculate inverse transformation matrix
* for this object */
@@ -3363,13 +3363,13 @@ static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat,
if (tot) {
bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
for (i = 0; i < tot; i++) {
- bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene);
+ bMats->ob_mats[i] = RE_sample_material_init(eval_ctx, give_current_material(brushOb, (i + 1)), scene);
}
}
bMats->tot = tot;
}
else {
- bMats->mat = RE_sample_material_init(ui_mat, scene);
+ bMats->mat = RE_sample_material_init(eval_ctx, ui_mat, scene);
}
}
@@ -6087,7 +6087,7 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene *
}
/* Prepare materials if required */
if (brush_usesMaterial(brush, scene))
- dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats);
+ dynamicPaint_updateBrushMaterials(eval_ctx, brushObj, brush->mat, scene, &bMats);
/* Apply brush on the surface depending on it's collision type */
if (brush->psys && brush->psys->part &&
diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c
new file mode 100644
index 00000000000..cef3c970c7a
--- /dev/null
+++ b/source/blender/blenkernel/intern/editlattice.c
@@ -0,0 +1,147 @@
+/*
+ * ***** 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/blenkernel/intern/editlattice.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_curve_types.h"
+
+#include "BLI_math_vector.h"
+#include "BLI_listbase.h"
+
+#include "BKE_deform.h"
+#include "BKE_key.h"
+
+#include "BKE_editlattice.h" /* own include */
+
+void BKE_editlattice_free(Object *ob)
+{
+ Lattice *lt = ob->data;
+
+ if (lt->editlatt) {
+ Lattice *editlt = lt->editlatt->latt;
+
+ if (editlt->def) {
+ MEM_freeN(editlt->def);
+ }
+ if (editlt->dvert) {
+ BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
+ }
+ MEM_freeN(editlt);
+ MEM_freeN(lt->editlatt);
+
+ lt->editlatt = NULL;
+ }
+}
+
+void BKE_editlattice_make(Object *obedit)
+{
+ Lattice *lt = obedit->data;
+ KeyBlock *actkey;
+
+ BKE_editlattice_free(obedit);
+
+ actkey = BKE_keyblock_from_object(obedit);
+ if (actkey) {
+ BKE_keyblock_convert_to_lattice(actkey, lt);
+ }
+ lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt");
+ lt->editlatt->latt = MEM_dupallocN(lt);
+ lt->editlatt->latt->def = MEM_dupallocN(lt->def);
+
+ if (lt->dvert) {
+ int tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
+ BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot);
+ }
+
+ if (lt->key) {
+ lt->editlatt->shapenr = obedit->shapenr;
+ }
+}
+
+void BKE_editlattice_load(Object *obedit)
+{
+ Lattice *lt, *editlt;
+ KeyBlock *actkey;
+ BPoint *bp;
+ float *fp;
+ int tot;
+
+ lt = obedit->data;
+ editlt = lt->editlatt->latt;
+
+ if (lt->editlatt->shapenr) {
+ actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
+
+ /* active key: vertices */
+ tot = editlt->pntsu * editlt->pntsv * editlt->pntsw;
+
+ if (actkey->data) {
+ MEM_freeN(actkey->data);
+ }
+
+ fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data");
+ actkey->totelem = tot;
+
+ bp = editlt->def;
+ while (tot--) {
+ copy_v3_v3(fp, bp->vec);
+ fp += 3;
+ bp++;
+ }
+ }
+ else {
+ MEM_freeN(lt->def);
+
+ lt->def = MEM_dupallocN(editlt->def);
+
+ lt->flag = editlt->flag;
+
+ lt->pntsu = editlt->pntsu;
+ lt->pntsv = editlt->pntsv;
+ lt->pntsw = editlt->pntsw;
+
+ lt->typeu = editlt->typeu;
+ lt->typev = editlt->typev;
+ lt->typew = editlt->typew;
+ lt->actbp = editlt->actbp;
+ }
+
+ if (lt->dvert) {
+ BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ lt->dvert = NULL;
+ }
+
+ if (editlt->dvert) {
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
+ BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot);
+ }
+}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 9c85a26b58a..905f103250a 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -804,7 +804,7 @@ void bezt_add_to_cfra_elem(ListBase *lb, BezTriple *bezt)
for (ce = lb->first; ce; ce = ce->next) {
/* double key? */
- if (ce->cfra == bezt->vec[1][0]) {
+ if (IS_EQT(ce->cfra, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
if (bezt->f2 & SELECT) ce->sel = bezt->f2;
return;
}
@@ -1590,11 +1590,9 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
return 0.0f;
}
else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) {
- /* extract scale, and choose the right axis */
- float scale[3];
-
- mat4_to_size(scale, mat);
- return scale[dtar->transChan - DTAR_TRANSCHAN_SCALEX];
+ /* Extract scale, and choose the right axis,
+ * inline 'mat4_to_size'. */
+ return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
}
else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
/* extract rotation as eulers (if needed)
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index c615f67fe42..20da1e7b7ac 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -55,7 +55,7 @@
#include "BKE_object.h"
#include "BKE_scene.h"
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#include "DEG_depsgraph.h"
/** Free (or release) any data used by this group (does not free the group itself). */
void BKE_group_free(Group *group)
@@ -213,13 +213,13 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group)
if (dup_group == group)
return true;
else {
- FOREACH_GROUP_OBJECT(dup_group, group_object)
+ FOREACH_GROUP_OBJECT_BEGIN(dup_group, group_object)
{
if (group_object_cyclic_check_internal(group_object, dup_group)) {
return true;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
/* un-flag the object, it's allowed to have the same group multiple times in parallel */
@@ -278,13 +278,13 @@ Group *BKE_group_object_find(Group *group, Object *ob)
bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
{
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
if (object->proxy) {
return true;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
return false;
}
@@ -369,13 +369,13 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx
#endif
{
/* only do existing tags, as set by regular depsgraph */
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
if (object->id.recalc & ID_RECALC_ALL) {
BKE_object_handle_update(eval_ctx, scene, object);
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
@@ -403,7 +403,7 @@ static void group_eval_layer_collections(
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);
+ DEG_debug_print_eval(__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,
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index a407fd0bae8..f3ff2c4425a 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -433,23 +433,28 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
}
}
-void BKE_icon_changed(int id)
+void BKE_icon_changed(const int icon_id)
{
Icon *icon = NULL;
- if (!id || G.background) return;
+ if (!icon_id || G.background) return;
- icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id));
+ icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
if (icon) {
- PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj);
+ /* We *only* expect ID-tied icons here, not non-ID icon/preview! */
+ BLI_assert(icon->type != 0);
+
+ /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
+ * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
+ PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj);
- /* all previews changed */
- if (prv) {
+ /* If we have previews, they all are now invalid changed. */
+ if (p_prv && *p_prv) {
int i;
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv->flag[i] |= PRV_CHANGED;
- prv->changed_timestamp[i]++;
+ (*p_prv)->flag[i] |= PRV_CHANGED;
+ (*p_prv)->changed_timestamp[i]++;
}
}
}
@@ -549,7 +554,7 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return preview->icon_id;
}
-Icon *BKE_icon_get(int icon_id)
+Icon *BKE_icon_get(const int icon_id)
{
Icon *icon = NULL;
@@ -563,7 +568,7 @@ Icon *BKE_icon_get(int icon_id)
return icon;
}
-void BKE_icon_set(int icon_id, struct Icon *icon)
+void BKE_icon_set(const int icon_id, struct Icon *icon)
{
void **val_p;
@@ -586,7 +591,7 @@ void BKE_icon_id_delete(struct ID *id)
/**
* Remove icon and free data.
*/
-void BKE_icon_delete(int icon_id)
+void BKE_icon_delete(const int icon_id)
{
Icon *icon;
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 33a665ba06e..87e5ed8cc1e 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -905,9 +905,10 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
if (prop1->len != prop2->len)
return false;
- for (i = 0; i < prop1->len; i++)
- if (!IDP_EqualsProperties(&array1[i], &array2[i]))
+ for (i = 0; i < prop1->len; i++) {
+ if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict))
return false;
+ }
return true;
}
case IDP_ID:
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 00cf40f06cd..fcbc25ebad5 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1663,7 +1663,7 @@ static void nlastrips_to_animdata(ID *id, ListBase *strips)
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
- nlt = add_nlatrack(adt, NULL);
+ nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 8e7b7f5456b..78af18fa362 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -57,8 +57,6 @@
#include "MEM_guardedalloc.h"
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
-
/* prototype */
struct EngineSettingsCB_Type;
static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src);
@@ -2137,7 +2135,7 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter))
void BKE_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- ObjectsRenderableIteratorData *data = data_in;
+ struct ObjectsRenderableIteratorData *data = data_in;
/* Tag objects to prevent going over the same object twice. */
for (Scene *scene = data->scene; scene; scene = scene->set) {
@@ -2165,7 +2163,7 @@ void BKE_renderable_objects_iterator_next(BLI_Iterator *iter)
/* Set it early in case we need to exit and we are running from within a loop. */
iter->skip = true;
- ObjectsRenderableIteratorData *data = iter->data;
+ struct ObjectsRenderableIteratorData *data = iter->data;
Base *base = data->iter.base->next;
/* There is still a base in the current scene layer. */
@@ -2245,7 +2243,7 @@ static void idproperty_reset(IDProperty **props, IDProperty *props_ref)
void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *UNUSED(eval_ctx),
ID *owner_id, ViewLayer *view_layer)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer);
+ DEG_debug_print_eval(__func__, view_layer->name, view_layer);
Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
@@ -2289,14 +2287,17 @@ void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx,
LayerCollection *layer_collection,
LayerCollection *parent_layer_collection)
{
- DEBUG_PRINT("%s on %s (%p) [%s], parent %s (%p) [%s]\n",
- __func__,
- layer_collection->scene_collection->name,
- layer_collection->scene_collection,
- collection_type_lookup[layer_collection->scene_collection->type],
- (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE",
- (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL,
- (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : "");
+ if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
+ /* TODO)sergey): Try to make it more generic and handled by depsgraph messaging. */
+ printf("%s on %s (%p) [%s], parent %s (%p) [%s]\n",
+ __func__,
+ layer_collection->scene_collection->name,
+ layer_collection->scene_collection,
+ collection_type_lookup[layer_collection->scene_collection->type],
+ (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE",
+ (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL,
+ (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : "");
+ }
BLI_assert(layer_collection != parent_layer_collection);
/* visibility */
@@ -2345,7 +2346,7 @@ void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx,
void BKE_layer_eval_layer_collection_post(const struct EvaluationContext *UNUSED(eval_ctx),
ViewLayer *view_layer)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer);
+ DEG_debug_print_eval(__func__, view_layer->name, view_layer);
/* if base is not selectabled, clear select */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
if ((base->flag & BASE_SELECTABLED) == 0) {
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 419ed8246db..27a2916ef92 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -440,13 +440,13 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
- FOREACH_SCENE_COLLECTION(scene, sc)
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, sc)
{
for (LinkData *link = sc->objects.first; link; link = link->next) {
CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER);
}
}
- FOREACH_SCENE_COLLECTION_END
+ FOREACH_SCENE_COLLECTION_END;
ViewLayer *view_layer;
for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
@@ -765,7 +765,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_GR:
{
Group *group = (Group *) id;
- FOREACH_GROUP_BASE(group, base)
+ FOREACH_GROUP_BASE_BEGIN(group, base)
{
CALLBACK_INVOKE(base->object, IDWALK_CB_USER_ONE);
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 6d4c4082810..483500cf67d 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -279,6 +279,26 @@ static void libblock_remap_data_preprocess_scene_object_unlink(
}
}
+static void libblock_remap_data_preprocess_group_unlink(
+ IDRemap *r_id_remap_data, Object *ob, const bool skip_indirect, const bool is_indirect)
+{
+ Main *bmain = r_id_remap_data->bmain;
+ for (Group *group = bmain->group.first; group; group = group->id.next) {
+ if (BKE_group_object_exists(group, ob)) {
+ if (skip_indirect && is_indirect) {
+ r_id_remap_data->skipped_indirect++;
+ r_id_remap_data->skipped_refcounted++;
+ }
+ else {
+ BKE_collections_object_remove(bmain, &group->id, ob, false);
+ if (!is_indirect) {
+ r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+ }
+}
+
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
switch (GS(r_id_remap_data->id->name)) {
@@ -293,19 +313,24 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
/* In case we are unlinking... */
if (!r_id_remap_data->old_id) {
/* ... everything from scene. */
- FOREACH_SCENE_OBJECT(sce, ob_iter)
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob_iter)
{
libblock_remap_data_preprocess_scene_object_unlink(
r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect);
+ libblock_remap_data_preprocess_group_unlink(
+ r_id_remap_data, ob_iter, skip_indirect, is_indirect);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
/* ... a specific object from scene. */
Object *old_ob = (Object *)r_id_remap_data->old_id;
libblock_remap_data_preprocess_scene_object_unlink(
r_id_remap_data, sce, old_ob, skip_indirect, is_indirect);
+ libblock_remap_data_preprocess_group_unlink(
+ r_id_remap_data, old_ob, skip_indirect, is_indirect);
}
+
}
break;
}
@@ -366,7 +391,7 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai
{
/* Note that here we assume no object has no base (i.e. all objects are assumed instanced
* in one scene...). */
- FOREACH_SCENE_OBJECT(sce, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
{
if (ob->flag & OB_FROMGROUP) {
Group *grp = BKE_group_object_find(NULL, ob);
@@ -380,7 +405,7 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id)
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index f60d87f2464..7d977463abf 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -47,7 +47,6 @@
#include "DEG_depsgraph.h"
-
unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
{
float max_segment = 0.01f;
@@ -898,11 +897,9 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
}
}
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
-
void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask);
+ DEG_debug_print_eval(__func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
@@ -913,7 +910,7 @@ void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask);
+ DEG_debug_print_eval(__func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 7235aa0aaf6..a0059a99473 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -72,6 +72,7 @@
#include "BKE_editmesh.h"
#include "BKE_font.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "GPU_material.h"
@@ -98,6 +99,9 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->ramp_col);
MEM_SAFE_FREE(ma->ramp_spec);
+
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
/* is no lib link block, but material extension */
if (ma->nodetree) {
@@ -108,8 +112,6 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
- GPU_material_free(&ma->gpumaterial);
-
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
@@ -1709,13 +1711,14 @@ void paste_matcopybuf(Material *ma)
MEM_freeN(mtex);
}
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
+
if (ma->nodetree) {
ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
- GPU_material_free(&ma->gpumaterial);
-
id = (ma->id);
memcpy(ma, &matcopybuf, sizeof(Material));
(ma->id) = id;
@@ -1772,9 +1775,7 @@ bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image)
void BKE_material_eval(const struct EvaluationContext *UNUSED(eval_ctx), Material *material)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s (%p)\n", __func__, material->id.name, material);
- }
+ DEG_debug_print_eval(__func__, material->id.name, material);
if ((BLI_listbase_is_empty(&material->gpumaterial) == false)) {
GPU_material_uniform_buffer_tag_dirty(&material->gpumaterial);
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index d3c74f71f78..abbf073f646 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2205,6 +2205,8 @@ static int split_faces_prepare_new_verts(
MLoop *ml = mloop;
MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+ BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
+
for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
const int vert_idx = ml->v;
@@ -2214,7 +2216,15 @@ static int split_faces_prepare_new_verts(
BLI_assert(*lnor_space);
- if ((*lnor_space)->loops) {
+ if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) {
+ /* Single loop in this fan... */
+ BLI_assert(GET_INT_FROM_POINTER((*lnor_space)->loops) == loop_idx);
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
+ }
+ }
+ else {
for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
@@ -2223,13 +2233,6 @@ static int split_faces_prepare_new_verts(
}
}
}
- else {
- /* Single loop in this fan... */
- BLI_BITMAP_ENABLE(done_loops, loop_idx);
- if (vert_used) {
- ml->v = new_vert_idx;
- }
- }
if (!vert_used) {
BLI_BITMAP_ENABLE(verts_used, vert_idx);
@@ -2667,9 +2670,7 @@ Mesh *BKE_mesh_new_from_object(
void BKE_mesh_eval_geometry(const EvaluationContext *UNUSED(eval_ctx),
Mesh *mesh)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s\n", __func__, mesh->id.name);
- }
+ DEG_debug_print_eval(__func__, mesh->id.name, mesh);
if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(mesh);
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index c7678be18c7..01cee2a19ff 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -444,7 +444,7 @@ cleanup:
MEM_freeN(fnors);
}
-void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops)
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops, const char data_type)
{
if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) {
MemArena *mem;
@@ -456,6 +456,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
}
+ BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
+ lnors_spacearr->data_type = data_type;
}
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
@@ -549,12 +551,32 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3],
}
}
-void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int ml_index,
- const bool do_add_loop)
+/**
+ * Add a new given loop to given lnor_space.
+ * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct (in case of BMLOOP_PTR),
+ * or NULL (in case of LOOP_INDEX), loop index is then stored in pointer.
+ * If \a is_single is set, the BMLoop or loop index is directly stored in \a lnor_space->loops pointer (since there
+ * is only one loop in this fan), else it is added to the linked list of loops in the fan.
+ */
+void BKE_lnor_space_add_loop(
+ MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space,
+ const int ml_index, void *bm_loop, const bool is_single)
{
+ BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == NULL) ||
+ (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != NULL));
+
lnors_spacearr->lspacearr[ml_index] = lnor_space;
- if (do_add_loop) {
- BLI_linklist_prepend_nlink(&lnor_space->loops, SET_INT_IN_POINTER(ml_index), &lnors_spacearr->loops_pool[ml_index]);
+ if (bm_loop == NULL) {
+ bm_loop = SET_INT_IN_POINTER(ml_index);
+ }
+ if (is_single) {
+ BLI_assert(lnor_space->loops == NULL);
+ lnor_space->flags |= MLNOR_SPACE_IS_SINGLE;
+ lnor_space->loops = bm_loop;
+ }
+ else {
+ BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0);
+ BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]);
}
}
@@ -680,10 +702,11 @@ typedef struct LoopSplitTaskDataCommon {
const MEdge *medges;
const MLoop *mloops;
const MPoly *mpolys;
- const int (*edge_to_loops)[2];
- const int *loop_to_poly;
+ int (*edge_to_loops)[2];
+ int *loop_to_poly;
const float (*polynors)[3];
+ int numEdges;
int numLoops;
int numPolys;
} LoopSplitTaskDataCommon;
@@ -693,7 +716,154 @@ typedef struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
-static void loop_manifold_fan_around_vert_next(
+static void mesh_edges_sharp_tag(
+ LoopSplitTaskDataCommon *data,
+ const bool check_angle, const float split_angle, const bool do_sharp_edges_tag)
+{
+ const MVert *mverts = data->mverts;
+ const MEdge *medges = data->medges;
+ const MLoop *mloops = data->mloops;
+
+ const MPoly *mpolys = data->mpolys;
+
+ const int numEdges = data->numEdges;
+ const int numPolys = data->numPolys;
+
+ float (*loopnors)[3] = data->loopnors; /* Note: loopnors may be NULL here. */
+ const float (*polynors)[3] = data->polynors;
+
+ int (*edge_to_loops)[2] = data->edge_to_loops;
+ int *loop_to_poly = data->loop_to_poly;
+
+ BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : NULL;
+
+ const MPoly *mp;
+ int mp_index;
+
+ const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
+
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ const MLoop *ml_curr;
+ int *e2l;
+ int ml_curr_index = mp->loopstart;
+ const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
+
+ ml_curr = &mloops[ml_curr_index];
+
+ for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) {
+ e2l = edge_to_loops[ml_curr->e];
+
+ loop_to_poly[ml_curr_index] = mp_index;
+
+ /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute
+ * those later!
+ */
+ if (loopnors) {
+ normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
+ }
+
+ /* Check whether current edge might be smooth or sharp */
+ if ((e2l[0] | e2l[1]) == 0) {
+ /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
+ e2l[0] = ml_curr_index;
+ /* We have to check this here too, else we might miss some flat faces!!! */
+ e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
+ }
+ else if (e2l[1] == INDEX_UNSET) {
+ const bool is_angle_sharp = (check_angle &&
+ dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle_cos);
+
+ /* Second loop using this edge, time to test its sharpness.
+ * An edge is sharp if it is tagged as such, or its face is not smooth,
+ * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex,
+ * or angle between both its polys' normals is above split_angle value.
+ */
+ if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) ||
+ ml_curr->v == mloops[e2l[0]].v ||
+ is_angle_sharp)
+ {
+ /* Note: we are sure that loop != 0 here ;) */
+ e2l[1] = INDEX_INVALID;
+
+ /* We want to avoid tagging edges as sharp when it is already defined as such by
+ * other causes than angle threshold... */
+ if (do_sharp_edges_tag && is_angle_sharp) {
+ BLI_BITMAP_SET(sharp_edges, ml_curr->e, true);
+ }
+ }
+ else {
+ e2l[1] = ml_curr_index;
+ }
+ }
+ else if (!IS_EDGE_SHARP(e2l)) {
+ /* More than two loops using this edge, tag as sharp if not yet done. */
+ e2l[1] = INDEX_INVALID;
+
+ /* We want to avoid tagging edges as sharp when it is already defined as such by
+ * other causes than angle threshold... */
+ if (do_sharp_edges_tag) {
+ BLI_BITMAP_SET(sharp_edges, ml_curr->e, false);
+ }
+ }
+ /* Else, edge is already 'disqualified' (i.e. sharp)! */
+ }
+ }
+
+ /* If requested, do actual tagging of edges as sharp in another loop. */
+ if (do_sharp_edges_tag) {
+ MEdge *me;
+ int me_index;
+ for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) {
+ if (BLI_BITMAP_TEST(sharp_edges, me_index)) {
+ me->flag |= ME_SHARP;
+ }
+ }
+
+ MEM_freeN(sharp_edges);
+ }
+}
+
+/** Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer, to keep same shading as with autosmooth!
+ */
+void BKE_edges_sharp_from_angle_set(
+ const struct MVert *mverts, const int UNUSED(numVerts),
+ struct MEdge *medges, const int numEdges,
+ struct MLoop *mloops, const int numLoops,
+ struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ const float split_angle)
+{
+ if (split_angle >= (float)M_PI) {
+ /* Nothing to do! */
+ return;
+ }
+
+ /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */
+ 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 = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ LoopSplitTaskDataCommon common_data = {
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numEdges = numEdges,
+ .numPolys = numPolys,
+ };
+
+ mesh_edges_sharp_tag(&common_data, true, split_angle, true);
+
+ MEM_freeN(edge_to_loops);
+ MEM_freeN(loop_to_poly);
+}
+
+void BKE_mesh_loop_manifold_fan_around_vert_next(
const MLoop *mloops, const MPoly *mpolys,
const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
const MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index)
@@ -782,7 +952,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL);
/* We know there is only one loop in this space, no need to create a linklist in this case... */
- BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, false);
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, NULL, true);
if (clnors_data) {
BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
@@ -915,7 +1085,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
if (lnors_spacearr) {
/* Assign current lnor space to current 'vertex' loop. */
- BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, true);
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, NULL, false);
if (me_curr != me_org) {
/* We store here all edges-normalized vectors processed. */
BLI_stack_push(edge_vectors, vec_curr);
@@ -933,7 +1103,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
copy_v3_v3(vec_prev, vec_curr);
/* Find next loop of the smooth fan. */
- loop_manifold_fan_around_vert_next(
+ BKE_mesh_loop_manifold_fan_around_vert_next(
mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
&mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
@@ -1070,7 +1240,7 @@ static bool loop_split_generator_check_cyclic_smooth_fan(
while (true) {
/* Find next loop of the smooth fan. */
- loop_manifold_fan_around_vert_next(
+ BKE_mesh_loop_manifold_fan_around_vert_next(
mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
&mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
@@ -1264,7 +1434,7 @@ void BKE_mesh_normals_loop_split(
const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- const bool use_split_normals, float split_angle,
+ const bool use_split_normals, const float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
{
/* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
@@ -1313,9 +1483,6 @@ void BKE_mesh_normals_loop_split(
/* Simple mapping from a loop to its polygon index. */
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;
-
/* When using custom loop normals, disable the angle feature! */
const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
@@ -1325,67 +1492,12 @@ void BKE_mesh_normals_loop_split(
TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
#endif
- if (check_angle) {
- split_angle = cosf(split_angle);
- }
-
if (!r_lnors_spacearr && clnors_data) {
/* We need to compute lnor spacearr if some custom lnor data are given to us! */
r_lnors_spacearr = &_lnors_spacearr;
}
if (r_lnors_spacearr) {
- BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops);
- }
-
- /* This first loop check which edges are actually smooth, and compute edge vectors. */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- MLoop *ml_curr;
- int *e2l;
- int ml_curr_index = mp->loopstart;
- const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
-
- ml_curr = &mloops[ml_curr_index];
-
- for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) {
- e2l = edge_to_loops[ml_curr->e];
-
- loop_to_poly[ml_curr_index] = mp_index;
-
- /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute
- * those later!
- */
- normal_short_to_float_v3(r_loopnors[ml_curr_index], mverts[ml_curr->v].no);
-
- /* Check whether current edge might be smooth or sharp */
- if ((e2l[0] | e2l[1]) == 0) {
- /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
- e2l[0] = ml_curr_index;
- /* We have to check this here too, else we might miss some flat faces!!! */
- e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
- }
- else if (e2l[1] == INDEX_UNSET) {
- /* Second loop using this edge, time to test its sharpness.
- * An edge is sharp if it is tagged as such, or its face is not smooth,
- * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex,
- * or angle between both its polys' normals is above split_angle value.
- */
- if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) ||
- ml_curr->v == mloops[e2l[0]].v ||
- (check_angle && dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle))
- {
- /* Note: we are sure that loop != 0 here ;) */
- e2l[1] = INDEX_INVALID;
- }
- else {
- e2l[1] = ml_curr_index;
- }
- }
- else if (!IS_EDGE_SHARP(e2l)) {
- /* More than two loops using this edge, tag as sharp if not yet done. */
- e2l[1] = INDEX_INVALID;
- }
- /* Else, edge is already 'disqualified' (i.e. sharp)! */
- }
+ BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX);
}
/* Init data common to all tasks. */
@@ -1397,13 +1509,17 @@ void BKE_mesh_normals_loop_split(
.medges = medges,
.mloops = mloops,
.mpolys = mpolys,
- .edge_to_loops = (const int(*)[2])edge_to_loops,
+ .edge_to_loops = edge_to_loops,
.loop_to_poly = loop_to_poly,
.polynors = polynors,
+ .numEdges = numEdges,
.numLoops = numLoops,
.numPolys = numPolys,
};
+ /* This first loop check which edges are actually smooth, and compute edge vectors. */
+ mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
+
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead... */
loop_split_generator(NULL, &common_data);
@@ -1495,6 +1611,8 @@ static void mesh_normals_loop_custom_set(
}
}
+ BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
+
/* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors
* are not (enough) equal, add sharp edges as needed.
* This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching
@@ -1518,7 +1636,7 @@ static void mesh_normals_loop_custom_set(
if (!BLI_BITMAP_TEST(done_loops, i)) {
/* Notes:
- * * In case of mono-loop smooth fan, loops is NULL, so everything is fine (we have nothing to do).
+ * * In case of mono-loop smooth fan, we have nothing to do.
* * Loops in this linklist are ordered (in reversed order compared to how they were discovered by
* BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a
* mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/
@@ -1526,6 +1644,11 @@ static void mesh_normals_loop_custom_set(
* * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding
* up into a real big one in the end!
*/
+ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_BITMAP_ENABLE(done_loops, i);
+ continue;
+ }
+
LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
MLoop *prev_ml = NULL;
const float *org_nor = NULL;
@@ -1573,9 +1696,6 @@ static void mesh_normals_loop_custom_set(
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
}
}
-
- /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */
- BLI_BITMAP_ENABLE(done_loops, i);
}
}
@@ -1605,7 +1725,15 @@ static void mesh_normals_loop_custom_set(
* computed 2D factors).
*/
LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
- if (loops) {
+ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_assert(GET_INT_FROM_POINTER(loops) == i);
+ const int nidx = use_vertices ? (int)mloops[i].v : i;
+ float *nor = r_custom_loopnors[nidx];
+
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
+ BLI_BITMAP_DISABLE(done_loops, i);
+ }
+ else {
int nbr_nors = 0;
float avg_nor[3];
short clnor_data_tmp[2], *clnor_data;
@@ -1632,13 +1760,6 @@ static void mesh_normals_loop_custom_set(
clnor_data[1] = clnor_data_tmp[1];
}
}
- else {
- const int nidx = use_vertices ? (int)mloops[i].v : i;
- float *nor = r_custom_loopnors[nidx];
-
- BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
- BLI_BITMAP_DISABLE(done_loops, i);
- }
}
}
@@ -2266,6 +2387,7 @@ void BKE_mesh_calc_volume(
}
}
+/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index 0838630a6cb..a1172d3f110 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -62,7 +62,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
{
MVert *mv, *mvert;
MEdge *me, *medge;
- MPoly /* *mpoly, */ /* UNUSED */ *mp;
+ MPoly *mpoly, *mp;
MLoop *mloop;
BMVert *v, **vtable;
BMEdge *e, **etable;
@@ -70,7 +70,6 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
BMFace *f;
int i, j, totvert, totedge /* , totface */ /* UNUSED */ ;
bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0);
- bool is_cddm = (dm->type == DM_TYPE_CDDM); /* duplicate the arrays for non cddm */
char has_orig_htype = 0;
int cd_vert_bweight_offset;
@@ -106,7 +105,8 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
etable = MEM_mallocN(sizeof(*etable) * totedge, __func__);
/*do verts*/
- mv = mvert = is_cddm ? dm->getVertArray(dm) : dm->dupVertArray(dm);
+ bool vert_allocated;
+ mv = mvert = DM_get_vert_array(dm, &vert_allocated);;
for (i = 0; i < totvert; i++, mv++) {
v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD);
normal_short_to_float_v3(v->no, mv->no);
@@ -124,11 +124,12 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
*orig_index = ORIGINDEX_NONE;
}
}
- if (!is_cddm) MEM_freeN(mvert);
+ if (vert_allocated) MEM_freeN(mvert);
if (is_init) bm->elem_index_dirty &= ~BM_VERT;
/*do edges*/
- me = medge = is_cddm ? dm->getEdgeArray(dm) : dm->dupEdgeArray(dm);
+ bool edge_allocated;
+ me = medge = DM_get_edge_array(dm, &edge_allocated);
for (i = 0; i < totedge; i++, me++) {
//BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL);
e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD);
@@ -147,13 +148,14 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
*orig_index = ORIGINDEX_NONE;
}
}
- if (!is_cddm) MEM_freeN(medge);
+ if (edge_allocated) MEM_freeN(medge);
if (is_init) bm->elem_index_dirty &= ~BM_EDGE;
/* do faces */
/* note: i_alt is aligned with bmesh faces which may not always align with mpolys */
- mp = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
+ bool poly_allocated, loop_allocated;
+ mpoly = mp = DM_get_poly_array(dm, &poly_allocated);
+ mloop = DM_get_loop_array(dm, &loop_allocated);
face_normals = (dm->dirty & DM_DIRTY_NORMALS) ? NULL : CustomData_get_layer(&dm->polyData, CD_NORMAL);
for (i = 0; i < dm->numPolyData; i++, mp++) {
BMLoop *l_iter;
@@ -194,6 +196,8 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
*orig_index = ORIGINDEX_NONE;
}
}
+ if (poly_allocated) MEM_freeN(mpoly);
+ if (loop_allocated) MEM_freeN(mloop);
if (is_init) bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
MEM_freeN(vtable);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index a416de07c6d..9ed715d7591 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -73,12 +73,12 @@
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_OPENEXR
# include "intern/openexr/openexr_multi.h"
#endif
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
-
/*********************** movieclip buffer loaders *************************/
static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
@@ -1202,6 +1202,23 @@ int BKE_movieclip_get_duration(MovieClip *clip)
return clip->len;
}
+float BKE_movieclip_get_fps(MovieClip *clip)
+{
+ if (clip->source != MCLIP_SRC_MOVIE) {
+ return 0.0f;
+ }
+ movieclip_open_anim_file(clip);
+ if (clip->anim == NULL) {
+ return 0.0f;
+ }
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(clip->anim, &frs_sec, &frs_sec_base, true)) {
+ return (float)frs_sec / frs_sec_base;
+ }
+ return 0.0f;
+}
+
void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
{
*aspx = 1.0;
@@ -1594,6 +1611,6 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, clip->id.name, clip);
+ DEG_debug_print_eval(__func__, clip->id.name, clip);
BKE_tracking_dopesheet_tag_update(&clip->tracking);
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index cbb7a766dfe..777c2a580fd 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -75,7 +75,7 @@
/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
* and the strip itself.
*/
-void free_nlastrip(ListBase *strips, NlaStrip *strip)
+void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
{
NlaStrip *cs, *csn;
@@ -86,7 +86,7 @@ void free_nlastrip(ListBase *strips, NlaStrip *strip)
/* free child-strips */
for (cs = strip->strips.first; cs; cs = csn) {
csn = cs->next;
- free_nlastrip(&strip->strips, cs);
+ BKE_nlastrip_free(&strip->strips, cs);
}
/* remove reference to action */
@@ -113,7 +113,7 @@ void free_nlastrip(ListBase *strips, NlaStrip *strip)
/* Remove the given NLA track from the set of NLA tracks, free the track's data,
* and the track itself.
*/
-void free_nlatrack(ListBase *tracks, NlaTrack *nlt)
+void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
{
NlaStrip *strip, *stripn;
@@ -124,7 +124,7 @@ void free_nlatrack(ListBase *tracks, NlaTrack *nlt)
/* free strips */
for (strip = nlt->strips.first; strip; strip = stripn) {
stripn = strip->next;
- free_nlastrip(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip);
}
/* free NLA track itself now */
@@ -137,7 +137,7 @@ void free_nlatrack(ListBase *tracks, NlaTrack *nlt)
/* Free the elements of type NLA Tracks provided in the given list, but do not free
* the list itself since that is not free-standing
*/
-void free_nladata(ListBase *tracks)
+void BKE_nla_tracks_free(ListBase *tracks)
{
NlaTrack *nlt, *nltn;
@@ -148,7 +148,7 @@ void free_nladata(ListBase *tracks)
/* free tracks one by one */
for (nlt = tracks->first; nlt; nlt = nltn) {
nltn = nlt->next;
- free_nlatrack(tracks, nlt);
+ BKE_nlatrack_free(tracks, nlt);
}
/* clear the list's pointers to be safe */
@@ -162,7 +162,7 @@ void free_nladata(ListBase *tracks)
*
* \param use_same_action When true, the existing action is used (instead of being duplicated)
*/
-NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action)
+NlaStrip *BKE_nlastrip_copy(NlaStrip *strip, const bool use_same_action)
{
NlaStrip *strip_d;
NlaStrip *cs, *cs_d;
@@ -195,7 +195,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action)
BLI_listbase_clear(&strip_d->strips);
for (cs = strip->strips.first; cs; cs = cs->next) {
- cs_d = copy_nlastrip(cs, use_same_action);
+ cs_d = BKE_nlastrip_copy(cs, use_same_action);
BLI_addtail(&strip_d->strips, cs_d);
}
@@ -204,7 +204,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action)
}
/* Copy NLA Track */
-NlaTrack *copy_nlatrack(NlaTrack *nlt, const bool use_same_actions)
+NlaTrack *BKE_nlatrack_copy(NlaTrack *nlt, const bool use_same_actions)
{
NlaStrip *strip, *strip_d;
NlaTrack *nlt_d;
@@ -221,7 +221,7 @@ NlaTrack *copy_nlatrack(NlaTrack *nlt, const bool use_same_actions)
BLI_listbase_clear(&nlt_d->strips);
for (strip = nlt->strips.first; strip; strip = strip->next) {
- strip_d = copy_nlastrip(strip, use_same_actions);
+ strip_d = BKE_nlastrip_copy(strip, use_same_actions);
BLI_addtail(&nlt_d->strips, strip_d);
}
@@ -230,7 +230,7 @@ NlaTrack *copy_nlatrack(NlaTrack *nlt, const bool use_same_actions)
}
/* Copy all NLA data */
-void copy_nladata(ListBase *dst, ListBase *src)
+void BKE_nla_tracks_copy(ListBase *dst, ListBase *src)
{
NlaTrack *nlt, *nlt_d;
@@ -245,7 +245,7 @@ void copy_nladata(ListBase *dst, ListBase *src)
for (nlt = src->first; nlt; nlt = nlt->next) {
/* make a copy, and add the copy to the destination list */
// XXX: we need to fix this sometime
- nlt_d = copy_nlatrack(nlt, true);
+ nlt_d = BKE_nlatrack_copy(nlt, true);
BLI_addtail(dst, nlt_d);
}
}
@@ -255,7 +255,7 @@ void copy_nladata(ListBase *dst, ListBase *src)
/* Add a NLA Track to the given AnimData
* - prev: NLA-Track to add the new one after
*/
-NlaTrack *add_nlatrack(AnimData *adt, NlaTrack *prev)
+NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev)
{
NlaTrack *nlt;
@@ -285,8 +285,8 @@ NlaTrack *add_nlatrack(AnimData *adt, NlaTrack *prev)
return nlt;
}
-/* Add a NLA Strip referencing the given Action */
-NlaStrip *add_nlastrip(bAction *act)
+/* Create a NLA Strip referencing the given Action */
+NlaStrip *BKE_nlastrip_new(bAction *act)
{
NlaStrip *strip;
@@ -327,7 +327,7 @@ NlaStrip *add_nlastrip(bAction *act)
}
/* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
-NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act)
+NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act)
{
NlaStrip *strip;
NlaTrack *nlt;
@@ -337,7 +337,7 @@ NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act)
return NULL;
/* create a new NLA strip */
- strip = add_nlastrip(act);
+ strip = BKE_nlastrip_new(act);
if (strip == NULL)
return NULL;
@@ -346,7 +346,7 @@ NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act)
/* trying to add to the last track failed (no track or no space),
* so add a new track to the stack, and add to that...
*/
- nlt = add_nlatrack(adt, NULL);
+ nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
}
@@ -358,7 +358,7 @@ NlaStrip *add_nlastrip_to_stack(AnimData *adt, bAction *act)
}
/* Add a NLA Strip referencing the given speaker's sound */
-NlaStrip *add_nla_soundstrip(Scene *scene, Speaker *speaker)
+NlaStrip *BKE_nla_add_soundstrip(Scene *scene, Speaker *speaker)
{
NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
@@ -751,7 +751,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
}
/* free the meta-strip now */
- free_nlastrip(strips, strip);
+ BKE_nlastrip_free(strips, strip);
}
/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
@@ -1392,7 +1392,12 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* store path - make copy, and store that */
fcu->rna_path = BLI_strdupn("influence", 9);
- /* TODO: insert a few keyframes to ensure default behavior? */
+ /* insert keyframe to ensure current value stays on first refresh */
+ fcu->bezt = MEM_callocN(sizeof(BezTriple), "nlastrip influence bezt");
+ fcu->totvert = 1;
+
+ fcu->bezt->vec[1][0] = strip->start;
+ fcu->bezt->vec[1][1] = strip->influence;
}
}
@@ -1709,7 +1714,7 @@ bool BKE_nla_action_stash(AnimData *adt)
}
}
- nlt = add_nlatrack(adt, prev_track);
+ nlt = BKE_nlatrack_add(adt, prev_track);
BLI_assert(nlt != NULL);
/* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */
@@ -1724,7 +1729,7 @@ bool BKE_nla_action_stash(AnimData *adt)
/* add the action as a strip in this new track
* NOTE: a new user is created here
*/
- strip = add_nlastrip(adt->action);
+ strip = BKE_nlastrip_new(adt->action);
BLI_assert(strip != NULL);
BKE_nlatrack_add_strip(nlt, strip);
@@ -1760,7 +1765,8 @@ bool BKE_nla_action_stash(AnimData *adt)
void BKE_nla_action_pushdown(AnimData *adt)
{
NlaStrip *strip;
-
+ const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
+
/* sanity checks */
/* TODO: need to report the error for this */
if (ELEM(NULL, adt, adt->action))
@@ -1776,7 +1782,7 @@ void BKE_nla_action_pushdown(AnimData *adt)
}
/* add a new NLA strip to the track, which references the active action */
- strip = add_nlastrip_to_stack(adt, adt->action);
+ strip = BKE_nlastack_add_strip(adt, adt->action);
/* do other necessary work on strip */
if (strip) {
@@ -1784,6 +1790,32 @@ void BKE_nla_action_pushdown(AnimData *adt)
id_us_min(&adt->action->id);
adt->action = NULL;
+ /* copy current "action blending" settings from adt to the strip,
+ * as it was keyframed with these settings, so omitting them will
+ * change the effect [T54233]
+ *
+ * NOTE: We only do this when there are no tracks
+ */
+ if (is_first == false) {
+ strip->blendmode = adt->act_blendmode;
+ strip->influence = adt->act_influence;
+ strip->extendmode = adt->act_extendmode;
+
+ if (adt->act_influence < 1.0f) {
+ /* enable "user-controlled" influence (which will insert a default keyframe)
+ * so that the influence doesn't get lost on the new update
+ *
+ * NOTE: An alternative way would have been to instead hack the influence
+ * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
+ * is disabled but auto-blending isn't being used. However, that approach
+ * is a bit hacky/hard to discover, and may cause backwards compatability issues,
+ * so it's better to just do it this way.
+ */
+ strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
+ BKE_nlastrip_validate_fcurves(strip);
+ }
+ }
+
/* if the strip is the first one in the track it lives in, check if there
* are strips in any other tracks that may be before this, and set the extend
* mode accordingly
@@ -1793,7 +1825,8 @@ void BKE_nla_action_pushdown(AnimData *adt)
* so that it doesn't override strips in previous tracks
*/
/* FIXME: this needs to be more automated, since user can rearrange strips */
- strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
+ if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
+ strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
}
/* make strip the active one... */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index c2d74739beb..41b7cd1f48e 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -75,6 +75,8 @@
#include "NOD_shader.h"
#include "NOD_texture.h"
+#include "DEG_depsgraph.h"
+
#define NODE_DEFAULT_MAX_WIDTH 700
/* Fallback types for undefined tree, nodes, sockets */
@@ -3616,6 +3618,7 @@ static void registerShaderNodes(void)
register_node_type_sh_holdout();
register_node_type_sh_volume_absorption();
register_node_type_sh_volume_scatter();
+ register_node_type_sh_volume_principled();
register_node_type_sh_subsurface_scattering();
register_node_type_sh_mix_shader();
register_node_type_sh_add_shader();
@@ -3870,8 +3873,6 @@ void BKE_nodetree_shading_params_eval(const struct EvaluationContext *UNUSED(eva
bNodeTree *ntree_dst,
const bNodeTree *ntree_src)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s (%p)\n", __func__, ntree_src->id.name, ntree_dst);
- }
+ DEG_debug_print_eval(__func__, ntree_src->id.name, ntree_dst);
BKE_nodetree_copy_default_values(ntree_dst, ntree_src);
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a0d2e7d76c8..73f47dec9cb 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -2321,7 +2321,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {-1.0f, -1.0f, -1.0f};
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
@@ -2770,7 +2770,7 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx,
* which is only in BKE_object_where_is_calc now */
/* XXX: should this case be OB_RECALC_OB instead? */
if (recalc_object || recalc_data) {
- if (G.debug & G_DEBUG_DEPSGRAPH) {
+ if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
printf("recalcob %s\n", ob->id.name + 2);
}
/* Handle proxy copy for target. */
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index ffe45d42677..fb2e824b299 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -460,6 +460,70 @@ void BKE_object_defgroup_remove_all(struct Object *ob)
BKE_object_defgroup_remove_all_ex(ob, false);
}
+/**
+ * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
+ * Returns null if no remapping is required.
+ * The returned array has to be freed.
+ */
+int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
+{
+ /* Build src to merged mapping of vgroup indices. */
+ if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) {
+ *r_map_len = 0;
+ return NULL;
+ }
+
+ bDeformGroup *dg_src;
+ *r_map_len = BLI_listbase_count(&ob_src->defbase);
+ int *vgroup_index_map = MEM_malloc_arrayN(*r_map_len, sizeof(*vgroup_index_map), "defgroup index map create");
+ bool is_vgroup_remap_needed = false;
+ int i;
+
+ for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) {
+ vgroup_index_map[i] = defgroup_name_index(ob_dst, dg_src->name);
+ is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i);
+ }
+
+ if (!is_vgroup_remap_needed) {
+ MEM_freeN(vgroup_index_map);
+ vgroup_index_map = NULL;
+ *r_map_len = 0;
+ }
+
+ return vgroup_index_map;
+}
+
+void BKE_object_defgroup_index_map_apply(MDeformVert *dvert, int dvert_len, const int *map, int map_len)
+{
+ if (map == NULL || map_len == 0) {
+ return;
+ }
+
+ MDeformVert *dv = dvert;
+ for (int i = 0; i < dvert_len; i++, dv++) {
+ int totweight = dv->totweight;
+ for (int j = 0; j < totweight; j++) {
+ int def_nr = dv->dw[j].def_nr;
+ if ((uint)def_nr < (uint)map_len && map[def_nr] != -1) {
+ dv->dw[j].def_nr = map[def_nr];
+ }
+ else {
+ totweight--;
+ dv->dw[j] = dv->dw[totweight];
+ j--;
+ }
+ }
+ if (totweight != dv->totweight) {
+ if (totweight) {
+ dv->dw = MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight);
+ }
+ else {
+ MEM_SAFE_FREE(dv->dw);
+ }
+ dv->totweight = totweight;
+ }
+ }
+}
/**
* Get MDeformVert vgroup data from given object. Should only be used in Object mode.
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 2d655913b3e..7419efba065 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -246,7 +246,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
if (ctx->group) {
int groupid = 0;
- FOREACH_GROUP_BASE(ctx->group, base)
+ FOREACH_GROUP_BASE_BEGIN(ctx->group, base)
{
Object *ob = base->object;
if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) {
@@ -932,12 +932,12 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
totgroup += dw->count;
}
else {
- FOREACH_GROUP_OBJECT(part->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object)
{
(void) object;
totgroup++;
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
/* we also copy the actual objects to restore afterwards, since
@@ -957,7 +957,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
else {
a = 0;
- FOREACH_GROUP_OBJECT(part->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object)
{
oblist[a] = object;
obcopylist[a] = *object;
@@ -967,7 +967,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
continue;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
else {
@@ -1057,7 +1057,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
b = 0;
- FOREACH_GROUP_OBJECT(part->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object)
{
copy_m4_m4(tmat, oblist[b]->obmat);
@@ -1082,7 +1082,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
b++;
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
else {
/* to give ipos in object correct offset */
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 52c85011b6a..2a33937e6ed 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -65,12 +65,11 @@
#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
void BKE_object_eval_local_transform(const EvaluationContext *UNUSED(eval_ctx),
Object *ob)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
/* calculate local matrix */
BKE_object_to_mat4(ob, ob->obmat);
@@ -88,7 +87,7 @@ void BKE_object_eval_parent(const EvaluationContext *UNUSED(eval_ctx),
float tmat[4][4];
float locmat[4][4];
- DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
/* get local matrix (but don't calculate it, as that was done already!) */
// XXX: redundant?
@@ -117,7 +116,7 @@ void BKE_object_eval_constraints(const EvaluationContext *eval_ctx,
bConstraintOb *cob;
float ctime = BKE_scene_frame_get(scene);
- DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
/* evaluate constraints stack */
/* TODO: split this into:
@@ -135,7 +134,7 @@ void BKE_object_eval_constraints(const EvaluationContext *eval_ctx,
void BKE_object_eval_done(const EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
/* Set negative scale flag in object. */
if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
@@ -152,7 +151,7 @@ void BKE_object_handle_data_update(
Key *key;
float ctime = BKE_scene_frame_get(scene);
- if (G.debug & G_DEBUG_DEPSGRAPH)
+ if (G.debug & G_DEBUG_DEPSGRAPH_EVAL)
printf("recalcdata %s\n", ob->id.name + 2);
/* TODO(sergey): Only used by legacy depsgraph. */
@@ -305,7 +304,7 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx,
Scene *scene,
Object *ob)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
BLI_assert(ob->type != OB_ARMATURE);
BKE_object_handle_data_update(eval_ctx, scene, ob);
@@ -383,7 +382,7 @@ void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *object)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object);
+ DEG_debug_print_eval(__func__, object->id.name, object);
BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
@@ -406,7 +405,7 @@ void BKE_object_eval_transform_all(const EvaluationContext *eval_ctx,
void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx),
Object *object)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object);
+ DEG_debug_print_eval(__func__, object->id.name, object);
if (object->type == OB_MESH) {
BKE_mesh_batch_cache_dirty(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
}
@@ -415,7 +414,7 @@ void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx),
void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx),
struct ID *object_data)
{
- DEBUG_PRINT("%s on %s (%p)\n", __func__, object_data->name, object_data);
+ DEG_debug_print_eval(__func__, object_data->name, object_data);
switch (GS(object_data->name)) {
case ID_ME:
BKE_mesh_batch_cache_dirty((Mesh *)object_data,
@@ -437,7 +436,7 @@ void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx),
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);
+ DEG_debug_print_eval(__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.
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index c9507ac1a36..94f37c3e02c 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -351,7 +351,7 @@ void psys_check_group_weights(ParticleSettings *part)
}
/* then add objects in the group to new list */
- FOREACH_GROUP_OBJECT(part->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object)
{
dw = part->dupliweights.first;
while (dw && dw->ob != object) {
@@ -365,7 +365,7 @@ void psys_check_group_weights(ParticleSettings *part)
BLI_addtail(&part->dupliweights, dw);
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
dw = part->dupliweights.first;
for (; dw; dw = dw->next) {
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 28bdde4e5f5..c2640e9b9e2 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -394,7 +394,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
}
- if (use_length_check && k > 1) {
+ if (use_length_check && k > 0) {
float dvec[3];
/* check if path needs to be cut before actual end of data points */
if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec)) {
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 767a17a34e7..f411a605c7f 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -1101,7 +1101,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
* distribution (see T47983 and its two example files). It allows us to consider pos as
* 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
- * and avoid stumbling over float imprecisions in element_sum.
+ * and avoid stumbling over float impression in element_sum.
* Note: moved face and volume distribution to this as well (instead of starting at zero),
* for the same reasons, see T52682. */
pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 9bc4da6f0d5..f27a570ca29 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -95,6 +95,7 @@
#include "PIL_time.h"
#include "RE_shader_ext.h"
+#include "DEG_depsgraph.h"
/* fluid sim particle import */
#ifdef WITH_MOD_FLUID
@@ -2956,7 +2957,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
/* particle instance modifier with "path" option need cached paths even if particle system doesn't */
- FOREACH_SCENE_OBJECT(sim->scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob)
{
ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance);
if (md) {
@@ -2967,7 +2968,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
if (!skip) {
psys_cache_paths(sim, cfra, use_render_params);
@@ -4419,18 +4420,14 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
void BKE_particle_system_settings_eval(const struct EvaluationContext *UNUSED(eval_ctx),
ParticleSystem *psys)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s (%p)\n", __func__, psys->name, psys);
- }
+ DEG_debug_print_eval(__func__, psys->name, psys);
psys->recalc |= psys->part->recalc;
}
void BKE_particle_system_settings_recalc_clear(struct EvaluationContext *UNUSED(eval_ctx),
ParticleSettings *particle_settings)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s (%p)\n", __func__, particle_settings->id.name, particle_settings);
- }
+ DEG_debug_print_eval(__func__, particle_settings->id.name, particle_settings);
particle_settings->recalc = 0;
}
@@ -4438,8 +4435,6 @@ void BKE_particle_system_eval_init(const struct EvaluationContext *UNUSED(eval_c
Scene *scene,
Object *ob)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s (%p)\n", __func__, ob->id.name, ob);
- }
+ DEG_debug_print_eval(__func__, ob->id.name, ob);
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 169b1b10024..c8a2a8b5542 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -972,20 +972,20 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
- wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, NULL);
+ wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL);
clip_grid = wt_density_grid;
if (fluid_fields & SM_ACTIVE_FIRE) {
- OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
- OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
- OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
- OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid);
+ OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, sds->clipping, wt_density_grid);
}
- OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid);
+ OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, sds->clipping, wt_density_grid);
}
if (sds->fluid) {
@@ -999,33 +999,33 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
- const char *name = (!sds->wt) ? "density" : "density low";
- density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, NULL);
+ const char *name = (!sds->wt) ? "density" : "density_low";
+ density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL);
clip_grid = sds->wt ? clip_grid : density_grid;
- OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, NULL);
+ OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL);
if (fluid_fields & SM_ACTIVE_HEAT) {
- OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, clip_grid);
- OpenVDB_export_grid_fl(writer, "heat old", heatold, sds->res, sds->fluidmat, clip_grid);
+ OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ OpenVDB_export_grid_fl(writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid);
}
if (fluid_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame low";
- OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, density_grid);
- name = (!sds->wt) ? "fuel" : "fuel low";
- OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, density_grid);
- name = (!sds->wt) ? "react" : "react low";
- OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, density_grid);
+ name = (!sds->wt) ? "flame" : "flame_low";
+ OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ name = (!sds->wt) ? "fuel" : "fuel_low";
+ OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ name = (!sds->wt) ? "react" : "react_low";
+ OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color low";
- OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid);
+ name = (!sds->wt) ? "color" : "color_low";
+ OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, sds->clipping, density_grid);
}
- OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid);
- OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, NULL);
+ OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, sds->clipping, clip_grid);
+ OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL);
}
return 1;
@@ -1104,25 +1104,25 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
- const char *name = (!sds->wt) ? "density" : "density low";
+ const char *name = (!sds->wt) ? "density" : "density_low";
OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
if (cache_fields & SM_ACTIVE_HEAT) {
OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
- OpenVDB_import_grid_fl(reader, "heat old", &heatold, sds->res);
+ OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res);
}
if (cache_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame low";
+ name = (!sds->wt) ? "flame" : "flame_low";
OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
- name = (!sds->wt) ? "fuel" : "fuel low";
+ name = (!sds->wt) ? "fuel" : "fuel_low";
OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
- name = (!sds->wt) ? "react" : "react low";
+ name = (!sds->wt) ? "react" : "react_low";
OpenVDB_import_grid_fl(reader, name, &react, sds->res);
}
if (cache_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color low";
+ name = (!sds->wt) ? "color" : "color_low";
OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 4a52c4f7d14..69e36f66dad 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -66,6 +66,8 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
/* ************************************** */
/* Memory Management */
@@ -92,7 +94,7 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
if (rbw->physics_world) {
/* free physics references, we assume that all physics objects in will have been added to the world */
if (rbw->constraints) {
- FOREACH_GROUP_OBJECT(rbw->constraints, object)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, object)
{
if (object->rigidbody_constraint) {
RigidBodyCon *rbc = object->rigidbody_constraint;
@@ -101,11 +103,11 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
}
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
if (rbw->group) {
- FOREACH_GROUP_OBJECT(rbw->group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->group, object)
{
if (object->rigidbody_object) {
RigidBodyOb *rbo = object->rigidbody_object;
@@ -114,7 +116,7 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
}
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
/* free dynamics world */
RB_dworld_delete(rbw->physics_world);
@@ -1148,7 +1150,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
/* remove object from rigid body constraints */
if (rbw->constraints) {
- FOREACH_GROUP_OBJECT(rbw->constraints, obt)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, obt)
{
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
@@ -1157,7 +1159,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
}
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
@@ -1201,12 +1203,12 @@ static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
}
i = 0;
- FOREACH_GROUP_OBJECT(rbw->group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->group, object)
{
rbw->objects[i] = object;
i++;
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
@@ -1332,7 +1334,7 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx
* Memory management needs redesign here, this is just a dirty workaround.
*/
if (rebuild && rbw->constraints) {
- FOREACH_GROUP_OBJECT(rbw->constraints, ob)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, ob)
{
RigidBodyCon *rbc = ob->rigidbody_constraint;
if (rbc && rbc->physics_constraint) {
@@ -1341,11 +1343,11 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx
rbc->physics_constraint = NULL;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
/* update objects */
- FOREACH_GROUP_OBJECT(rbw->group, ob)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->group, ob)
{
if (ob->type == OB_MESH) {
/* validate that we've got valid object set up here... */
@@ -1388,13 +1390,13 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx
rigidbody_update_sim_ob(eval_ctx, scene, rbw, ob, rbo);
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
- FOREACH_GROUP_OBJECT(rbw->constraints, ob)
+ FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, ob)
{
/* validate that we've got valid object set up here... */
RigidBodyCon *rbc = ob->rigidbody_constraint;
@@ -1422,12 +1424,12 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx
rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw)
{
- FOREACH_GROUP_BASE(rbw->group, base)
+ FOREACH_GROUP_BASE_BEGIN(rbw->group, base)
{
Object *ob = base->object;
RigidBodyOb *rbo = ob->rigidbody_object;
@@ -1688,11 +1690,7 @@ void BKE_rigidbody_rebuild_sim(const struct EvaluationContext *eval_ctx,
Scene *scene)
{
float ctime = BKE_scene_frame_get(scene);
-
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s at %f\n", __func__, ctime);
- }
-
+ DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
/* rebuild sim data (i.e. after resetting to start of timeline) */
if (BKE_scene_check_rigidbody_active(scene)) {
BKE_rigidbody_rebuild_world(eval_ctx, scene, ctime);
@@ -1703,11 +1701,7 @@ void BKE_rigidbody_eval_simulation(const struct EvaluationContext *eval_ctx,
Scene *scene)
{
float ctime = BKE_scene_frame_get(scene);
-
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s at %f\n", __func__, ctime);
- }
-
+ DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
/* evaluate rigidbody sim */
if (BKE_scene_check_rigidbody_active(scene)) {
BKE_rigidbody_do_simulation(eval_ctx, scene, ctime);
@@ -1720,11 +1714,7 @@ void BKE_rigidbody_object_sync_transforms(const struct EvaluationContext *UNUSED
{
RigidBodyWorld *rbw = scene->rigidbody_world;
float ctime = BKE_scene_frame_get(scene);
-
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s on %s\n", __func__, ob->id.name);
- }
-
+ DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime);
/* read values pushed into RBO from sim/cache... */
BKE_rigidbody_sync_transforms(rbw, ob, ctime);
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 899a911270f..ca9cddde65a 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -151,6 +151,83 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
+/* flag -- copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */
+ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
+{
+ if (toolsettings == NULL) {
+ return NULL;
+ }
+ ToolSettings *ts = MEM_dupallocN(toolsettings);
+ if (ts->vpaint) {
+ ts->vpaint = MEM_dupallocN(ts->vpaint);
+ BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag);
+ }
+ if (ts->wpaint) {
+ ts->wpaint = MEM_dupallocN(ts->wpaint);
+ BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag);
+ }
+ if (ts->sculpt) {
+ ts->sculpt = MEM_dupallocN(ts->sculpt);
+ BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag);
+ }
+ if (ts->uvsculpt) {
+ ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
+ BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
+ }
+
+ BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
+ ts->imapaint.paintcursor = NULL;
+ ts->particle.paintcursor = NULL;
+ ts->particle.scene = NULL;
+ ts->particle.object = NULL;
+
+ /* duplicate Grease Pencil Drawing Brushes */
+ BLI_listbase_clear(&ts->gp_brushes);
+ for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) {
+ bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
+ BLI_addtail(&ts->gp_brushes, newbrush);
+ }
+
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ return ts;
+}
+
+void BKE_toolsettings_free(ToolSettings *toolsettings)
+{
+ if (toolsettings == NULL) {
+ return;
+ }
+ if (toolsettings->vpaint) {
+ BKE_paint_free(&toolsettings->vpaint->paint);
+ MEM_freeN(toolsettings->vpaint);
+ }
+ if (toolsettings->wpaint) {
+ BKE_paint_free(&toolsettings->wpaint->paint);
+ MEM_freeN(toolsettings->wpaint);
+ }
+ if (toolsettings->sculpt) {
+ BKE_paint_free(&toolsettings->sculpt->paint);
+ MEM_freeN(toolsettings->sculpt);
+ }
+ if (toolsettings->uvsculpt) {
+ BKE_paint_free(&toolsettings->uvsculpt->paint);
+ MEM_freeN(toolsettings->uvsculpt);
+ }
+ BKE_paint_free(&toolsettings->imapaint.paint);
+
+ /* free Grease Pencil Drawing Brushes */
+ BKE_gpencil_free_brushes(&toolsettings->gp_brushes);
+ BLI_freelistN(&toolsettings->gp_brushes);
+
+ /* free Grease Pencil interpolation curve */
+ if (toolsettings->gp_interpolate.custom_ipo) {
+ curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
+ }
+
+ MEM_freeN(toolsettings);
+}
+
/**
* Only copy internal data of Scene ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -223,41 +300,7 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve);
/* tool settings */
- if (sce_dst->toolsettings != NULL) {
- ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings);
- if (ts->vpaint) {
- ts->vpaint = MEM_dupallocN(ts->vpaint);
- BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata);
- }
- if (ts->wpaint) {
- ts->wpaint = MEM_dupallocN(ts->wpaint);
- BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata);
- }
- if (ts->sculpt) {
- ts->sculpt = MEM_dupallocN(ts->sculpt);
- BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag_subdata);
- }
- if (ts->uvsculpt) {
- ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
- BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag_subdata);
- }
-
- BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag_subdata);
- ts->imapaint.paintcursor = NULL;
- ts->particle.paintcursor = NULL;
- ts->particle.scene = NULL;
- ts->particle.object = NULL;
-
- /* duplicate Grease Pencil Drawing Brushes */
- BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = sce_src->toolsettings->gp_brushes.first; brush; brush = brush->next) {
- bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
- BLI_addtail(&ts->gp_brushes, newbrush);
- }
-
- /* duplicate Grease Pencil interpolation curve */
- ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
- }
+ sce_dst->toolsettings = BKE_toolsettings_copy(sce_dst->toolsettings, flag_subdata);
/* make a private copy of the avicodecdata */
if (sce_src->r.avicodecdata) {
@@ -296,7 +339,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* TODO this should/could most likely be replaced by call to more generic code at some point...
* But for now, let's keep it well isolated here. */
if (type == SCE_COPY_EMPTY) {
- ToolSettings *ts;
ListBase rv;
sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
@@ -331,46 +373,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
/* tool settings */
- sce_copy->toolsettings = MEM_dupallocN(sce->toolsettings);
-
- ts = sce_copy->toolsettings;
- if (ts) {
- if (ts->vpaint) {
- ts->vpaint = MEM_dupallocN(ts->vpaint);
- BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0);
- }
- if (ts->wpaint) {
- ts->wpaint = MEM_dupallocN(ts->wpaint);
- BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0);
- }
- if (ts->sculpt) {
- ts->sculpt = MEM_dupallocN(ts->sculpt);
- BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, 0);
- }
- if (ts->uvsculpt) {
- ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
- BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, 0);
- }
-
- BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, 0);
- ts->imapaint.paintcursor = NULL;
- id_us_plus((ID *)ts->imapaint.stencil);
- id_us_plus((ID *)ts->imapaint.clone);
- id_us_plus((ID *)ts->imapaint.canvas);
- ts->particle.paintcursor = NULL;
- ts->particle.scene = NULL;
- ts->particle.object = NULL;
-
- /* duplicate Grease Pencil Drawing Brushes */
- BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
- bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
- BLI_addtail(&ts->gp_brushes, newbrush);
- }
-
- /* duplicate Grease Pencil interpolation curve */
- ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
- }
+ sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0);
/* make a private copy of the avicodecdata */
if (sce->r.avicodecdata) {
@@ -492,37 +495,8 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->r.views);
- if (sce->toolsettings) {
- if (sce->toolsettings->vpaint) {
- BKE_paint_free(&sce->toolsettings->vpaint->paint);
- MEM_freeN(sce->toolsettings->vpaint);
- }
- if (sce->toolsettings->wpaint) {
- BKE_paint_free(&sce->toolsettings->wpaint->paint);
- MEM_freeN(sce->toolsettings->wpaint);
- }
- if (sce->toolsettings->sculpt) {
- BKE_paint_free(&sce->toolsettings->sculpt->paint);
- MEM_freeN(sce->toolsettings->sculpt);
- }
- if (sce->toolsettings->uvsculpt) {
- BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
- MEM_freeN(sce->toolsettings->uvsculpt);
- }
- BKE_paint_free(&sce->toolsettings->imapaint.paint);
-
- /* free Grease Pencil Drawing Brushes */
- BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes);
- BLI_freelistN(&sce->toolsettings->gp_brushes);
-
- /* free Grease Pencil interpolation curve */
- if (sce->toolsettings->gp_interpolate.custom_ipo) {
- curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo);
- }
-
- MEM_freeN(sce->toolsettings);
- sce->toolsettings = NULL;
- }
+ BKE_toolsettings_free(sce->toolsettings);
+ sce->toolsettings = NULL;
BKE_scene_free_depsgraph_hash(sce);
@@ -987,11 +961,11 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
/* group flags again */
for (group = bmain->group.first; group; group = group->id.next) {
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
object->flag |= OB_FROMGROUP;
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
/* copy layers and flags from bases to objects */
@@ -1376,7 +1350,10 @@ static bool check_rendered_viewport_visible(Main *bmain)
return false;
}
-static void prepare_mesh_for_viewport_render(Main *bmain, const EvaluationContext *eval_ctx)
+/* TODO(campbell): shouldn't we be able to use 'eval_ctx->view_layer' here?
+ * Currently this is NULL on load, so don't. */
+static void prepare_mesh_for_viewport_render(
+ Main *bmain, const EvaluationContext *eval_ctx, const ViewLayer *view_layer)
{
/* This is needed to prepare mesh to be used by the render
* engine from the viewport rendering. We do loading here
@@ -1387,7 +1364,8 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const EvaluationContex
* call loading of the edit data for the mesh objects.
*/
- Object *obedit = OBEDIT_FROM_EVAL_CTX(eval_ctx);
+ /* Expanded 'OBEDIT_FROM_EVAL_CTX' */
+ Object *obedit = (eval_ctx->object_mode & OB_MODE_EDIT) ? OBACT(view_layer) : NULL;
if (obedit) {
Mesh *mesh = obedit->data;
if ((obedit->type == OB_MESH) &&
@@ -1429,7 +1407,7 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx,
/* Uncomment this to check if graph was properly tagged for update. */
// DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
/* Flush editing data if needed. */
- prepare_mesh_for_viewport_render(bmain, eval_ctx);
+ prepare_mesh_for_viewport_render(bmain, eval_ctx, view_layer);
/* Flush recalc flags to dependencies. */
DEG_graph_flush_update(bmain, depsgraph);
/* Update all objects: drivers, matrices, displists, etc. flags set
@@ -1451,11 +1429,6 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx,
Scene *scene,
ViewLayer *view_layer)
{
- /* TODO(sergey): Temporary solution for until pipeline.c is ported. */
- if (view_layer == NULL) {
- view_layer = DEG_get_evaluated_view_layer(depsgraph);
- BLI_assert(view_layer != NULL);
- }
/* TODO(sergey): Some functions here are changing global state,
* for example, clearing update tags from bmain.
*/
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 424f4269f3c..66221dd470f 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1680,6 +1680,11 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
else if (seq->type == SEQ_TYPE_IMAGE) {
fname[0] = 0;
}
+ else {
+ /* We could make a name here, except non-movie's don't generate proxies,
+ * cancel until other types of sequence strips are supported. */
+ return false;
+ }
BLI_path_append(dir, sizeof(dir), fname);
BLI_path_abs(name, G.main->name);
}
@@ -3264,9 +3269,10 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
// have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */
have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
- /* Get depsgraph and scene layer for the strip. */
+ /* Get view layer for the strip. */
ViewLayer *view_layer = BKE_view_layer_from_scene_get(scene);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ /* Depsgraph will be NULL when doing rendering. */
+ Depsgraph *depsgraph = NULL;
orig_data.scemode = scene->r.scemode;
orig_data.cfra = scene->r.cfra;
@@ -3324,6 +3330,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
/* opengl offscreen render */
context->eval_ctx->engine_type = RE_engines_find(scene->view_render.engine_id);
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
@@ -3355,15 +3362,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
if (re == NULL)
re = RE_NewSceneRender(scene);
- /* NOTE: Without this tag rendering from command line fails.
- * TODO(sergey): Need some proper solution with ported
- * BKE_scene_set_background() or DEG_on_visible_change() ?
- */
- RE_SetDepsgraph(re, depsgraph);
- DEG_graph_id_tag_update(context->bmain, depsgraph, &scene->id, 0);
-
- BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer);
- RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false);
+ RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, scene->lay, frame, false);
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
@@ -3421,7 +3420,7 @@ finally:
scene->r.cfra = orig_data.cfra;
scene->r.subframe = orig_data.subframe;
- if (is_frame_update) {
+ if (is_frame_update && (depsgraph != NULL)) {
BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer);
}
@@ -5167,6 +5166,40 @@ void BKE_sequence_init_colorspace(Sequence *seq)
}
}
+float BKE_sequence_get_fps(Scene *scene, Sequence *seq)
+{
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE:
+ {
+ seq_open_anim_file(scene, seq, true);
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ return 0.0f;
+ }
+ StripAnim *strip_anim = seq->anims.first;
+ if (strip_anim->anim == NULL) {
+ return 0.0f;
+ }
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) {
+ return (float)frs_sec / frs_sec_base;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIECLIP:
+ if (seq->clip != NULL) {
+ return BKE_movieclip_get_fps(seq->clip);
+ }
+ break;
+ case SEQ_TYPE_SCENE:
+ if (seq->scene != NULL) {
+ return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base;
+ }
+ break;
+ }
+ return 0.0f;
+}
+
/* NOTE: this function doesn't fill in image names */
Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 9b11b66cedd..6fec55200d6 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -525,8 +525,8 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->burning_rate = 0.75f;
smd->domain->flame_smoke = 1.0f;
smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.25f;
- smd->domain->flame_max_temp = 1.75f;
+ smd->domain->flame_ignition = 1.5f;
+ smd->domain->flame_max_temp = 3.0f;
/* color */
smd->domain->flame_smoke_color[0] = 0.7f;
smd->domain->flame_smoke_color[1] = 0.7f;
@@ -553,6 +553,8 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->coba = NULL;
smd->domain->coba_field = FLUID_FIELD_DENSITY;
+
+ smd->domain->clipping = 1e-3f;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 71b90641e02..0e2ac811a41 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -1207,17 +1207,17 @@ void BKE_texture_get_value(
BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management);
}
-static void texture_nodes_fetch_images_for_pool(bNodeTree *ntree, struct ImagePool *pool)
+static void texture_nodes_fetch_images_for_pool(Tex *texture, bNodeTree *ntree, struct ImagePool *pool)
{
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
Image *image = (Image *)node->id;
- BKE_image_pool_acquire_ibuf(image, NULL, pool);
+ BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool);
}
else if (node->type == NODE_GROUP && node->id != NULL) {
/* TODO(sergey): Do we need to control recursion here? */
bNodeTree *nested_tree = (bNodeTree *)node->id;
- texture_nodes_fetch_images_for_pool(nested_tree, pool);
+ texture_nodes_fetch_images_for_pool(texture, nested_tree, pool);
}
}
}
@@ -1226,12 +1226,12 @@ static void texture_nodes_fetch_images_for_pool(bNodeTree *ntree, struct ImagePo
void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
{
if (texture->nodetree != NULL) {
- texture_nodes_fetch_images_for_pool(texture->nodetree, pool);
+ texture_nodes_fetch_images_for_pool(texture, texture->nodetree, pool);
}
else {
if (texture->type == TEX_IMAGE) {
if (texture->ima != NULL) {
- BKE_image_pool_acquire_ibuf(texture->ima, NULL, pool);
+ BKE_image_pool_acquire_ibuf(texture->ima, &texture->iuser, pool);
}
}
}
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index dd7def16ca8..106dd125575 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -189,7 +189,7 @@ void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
options->image1_mask = NULL;
}
-/* Peform tracking from a reference_marker to destination_ibuf.
+/* Perform tracking from a reference_marker to destination_ibuf.
* Uses marker as an initial position guess.
*
* Returns truth if tracker returned success, puts result
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 9251c6630a5..301084e22fc 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -169,6 +169,7 @@ void BKE_workspace_free(WorkSpace *workspace)
BKE_workspace_relations_free(&workspace->hook_layout_relations);
BKE_workspace_relations_free(&workspace->scene_viewlayer_relations);
+ BLI_freelistN(&workspace->owner_ids);
BLI_freelistN(&workspace->layouts);
BLI_freelistN(&workspace->transform_orientations);
@@ -535,3 +536,16 @@ Object *BKE_workspace_edit_object(WorkSpace *workspace, Scene *scene)
return NULL;
}
+bool BKE_workspace_owner_id_check(
+ const WorkSpace *workspace, const char *owner_id)
+{
+ if ((*owner_id == '\0') ||
+ ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0))
+ {
+ return true;
+ }
+ else {
+ /* we could use hash lookup, for now this list is highly under < ~16 items. */
+ return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
+ }
+}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 5da8dc563e2..a57fc1fe027 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -196,7 +196,7 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
void BKE_world_eval(const struct EvaluationContext *UNUSED(eval_ctx), World *world)
{
- if (G.debug & G_DEBUG_DEPSGRAPH) {
+ if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
printf("%s on %s (%p)\n", __func__, world->id.name, world);
}
if (!BLI_listbase_is_empty(&world->gpumaterial)) {
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 825acb18e91..8e94b8197ef 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -62,9 +62,10 @@
* Doing the realloc in a macro isn't so simple,
* so use a function the macros can use.
*/
-void _bli_array_grow_func(void **arr_p, const void *arr_static,
- const int sizeof_arr_p, const int arr_count, const int num,
- const char *alloc_str);
+void _bli_array_grow_func(
+ void **arr_p, const void *arr_static,
+ const int sizeof_arr_p, const int arr_len, const int num,
+ const char *alloc_str);
/* -------------------------------------------------------------------- */
@@ -74,18 +75,18 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
/** use ``sizeof(*(arr))`` to ensure the array exists and is an array */
#define BLI_array_declare(arr) \
- int _##arr##_count = ((void)(sizeof(*(arr))), 0); \
+ int _##arr##_len = ((void)(sizeof(*(arr))), 0); \
void *_##arr##_static = NULL
/**
* this will use stack space, up to maxstatic array elements, before
* switching to dynamic heap allocation */
#define BLI_array_staticdeclare(arr, maxstatic) \
- int _##arr##_count = 0; \
+ int _##arr##_len = 0; \
char _##arr##_static[maxstatic * sizeof(*(arr))]
/** returns the logical size of the array, not including buffering. */
-#define BLI_array_count(arr) ((void)0, _##arr##_count)
+#define BLI_array_len(arr) ((void)0, _##arr##_len)
/**
* Grow the array by a fixed number of items.
@@ -95,23 +96,23 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
#define BLI_array_reserve(arr, num) (void)( \
(((void *)(arr) == NULL) && \
((void *)(_##arr##_static) != NULL) && \
- /* don't add _##arr##_count below because it must be zero */ \
- (_bli_array_totalsize_static(arr) >= _##arr##_count + (num))) ? \
+ /* don't add _##arr##_len below because it must be zero */ \
+ (_bli_array_totalsize_static(arr) >= _##arr##_len + (num))) ? \
/* we have an empty array and a static var big enough */ \
(void)(arr = (void *)_##arr##_static) \
: \
/* use existing static array or allocate */ \
- (LIKELY(_bli_array_totalsize(arr) >= _##arr##_count + (num)) ? \
+ (LIKELY(_bli_array_totalsize(arr) >= _##arr##_len + (num)) ? \
(void)0 /* do nothing */ : \
_bli_array_grow_func((void **)&(arr), _##arr##_static, \
- sizeof(*(arr)), _##arr##_count, num, \
+ sizeof(*(arr)), _##arr##_len, num, \
"BLI_array." #arr)) \
)
/** returns length of array */
#define BLI_array_grow_items(arr, num) \
- (BLI_array_reserve(arr, num), (_##arr##_count += num))
+ (BLI_array_reserve(arr, num), (_##arr##_len += num))
#define BLI_array_grow_one(arr) \
BLI_array_grow_items(arr, 1)
@@ -119,7 +120,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
/** appends an item to the array. */
#define BLI_array_append(arr, item) ( \
(void) BLI_array_grow_one(arr), \
- (void) (arr[_##arr##_count - 1] = item) \
+ (void) (arr[_##arr##_len - 1] = item) \
)
/**
@@ -127,13 +128,13 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
* item is not a pointer, but actual data value.*/
#define BLI_array_append_r(arr, item) ( \
(void) BLI_array_grow_one(arr), \
- (void) (arr[_##arr##_count - 1] = item), \
- (&arr[_##arr##_count - 1]) \
+ (void) (arr[_##arr##_len - 1] = item), \
+ (&arr[_##arr##_len - 1]) \
)
/** appends (grows) & returns a pointer to the uninitialized memory */
#define BLI_array_append_ret(arr) \
- (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)])
+ (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
#define BLI_array_free(arr) { \
if (arr && (char *)arr != _##arr##_static) { \
@@ -143,26 +144,26 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
} ((void)0)
#define BLI_array_pop(arr) ( \
- (arr && _##arr##_count) ? \
- arr[--_##arr##_count] : \
+ (arr && _##arr##_len) ? \
+ arr[--_##arr##_len] : \
NULL \
)
/**
- * resets the logical size of an array to zero, but doesn't
+ * Resets the logical size of an array to zero, but doesn't
* free the memory. */
#define BLI_array_clear(arr) \
- { _##arr##_count = 0; } (void)0
+ { _##arr##_len = 0; } ((void)0)
/**
- * set the count of the array, doesn't actually increase the allocated array
+ * Set the length of the array, doesn't actually increase the allocated array
* size. don't use this unless you know what you're doing. */
-#define BLI_array_count_set(arr, count) \
- { _##arr##_count = (count); }(void)0
+#define BLI_array_len_set(arr, len) \
+ { _##arr##_len = (len); } ((void)0)
/** only to prevent unused warnings */
#define BLI_array_fake_user(arr) \
- ((void)_##arr##_count, \
+ ((void)_##arr##_len, \
(void)_##arr##_static)
/** \} */
@@ -191,7 +192,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
#define BLI_array_fixedstack_free(arr) \
if (_##arr##_is_static) { \
MEM_freeN(arr); \
- } (void)0
+ } ((void)0)
/** \} */
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
new file mode 100644
index 00000000000..9fb0954e77f
--- /dev/null
+++ b/source/blender/blenlib/BLI_assert.h
@@ -0,0 +1,111 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ASSERT_H__
+#define __BLI_ASSERT_H__
+
+/** \file BLI_assert.h
+ * \ingroup bli
+ *
+ * Defines:
+ * - #BLI_assert
+ * - #BLI_STATIC_ASSERT
+ * - #BLI_STATIC_ASSERT_ALIGN
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NDEBUG /* for BLI_assert */
+#include <stdio.h>
+#endif
+
+/* BLI_assert(), default only to print
+ * for aborting need to define WITH_ASSERT_ABORT
+ */
+/* For 'abort' only. */
+#include <stdlib.h>
+
+#ifndef NDEBUG
+# include "BLI_system.h"
+# ifdef WITH_ASSERT_ABORT
+# define _BLI_DUMMY_ABORT abort
+# else
+# define _BLI_DUMMY_ABORT() (void)0
+# endif
+# if defined(__GNUC__) || defined(_MSC_VER) /* check __func__ is available */
+# define BLI_assert(a) \
+ (void)((!(a)) ? ( \
+ ( \
+ BLI_system_backtrace(stderr), \
+ fprintf(stderr, \
+ "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", \
+ __FILE__, __LINE__, __func__, "" #a), \
+ _BLI_DUMMY_ABORT(), \
+ NULL)) : NULL)
+# else
+# define BLI_assert(a) \
+ (void)((!(a)) ? ( \
+ ( \
+ fprintf(stderr, \
+ "BLI_assert failed: %s:%d, at \'%s\'\n", \
+ __FILE__, __LINE__, "" #a), \
+ _BLI_DUMMY_ABORT(), \
+ NULL)) : NULL)
+# endif
+#else
+# define BLI_assert(a) (void)0
+#endif
+
+/* C++ can't use _Static_assert, expects static_assert() but c++0x only,
+ * Coverity also errors out. */
+#if (!defined(__cplusplus)) && \
+ (!defined(__COVERITY__)) && \
+ (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */
+# define BLI_STATIC_ASSERT(a, msg) __extension__ _Static_assert(a, msg);
+#else
+/* Code adapted from http://www.pixelbeat.org/programming/gcc/static_assert.html */
+/* Note we need the two concats below because arguments to ## are not expanded, so we need to
+ * expand __LINE__ with one indirection before doing the actual concatenation. */
+# define ASSERT_CONCAT_(a, b) a##b
+# define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
+ /* These can't be used after statements in c89. */
+# if defined(__COUNTER__) /* MSVC */
+# define BLI_STATIC_ASSERT(a, msg) \
+ ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(a)) };
+# else /* older gcc, clang... */
+ /* This can't be used twice on the same line so ensure if using in headers
+ * that the headers are not included twice (by wrapping in #ifndef...#endif)
+ * Note it doesn't cause an issue when used on same line of separate modules
+ * compiled with gcc -combine -fwhole-program. */
+# define BLI_STATIC_ASSERT(a, msg) \
+ ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(a)) };
+# endif
+#endif
+
+#define BLI_STATIC_ASSERT_ALIGN(st, align) \
+ BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned")
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_ASSERT_H__ */
diff --git a/source/blender/blenlib/BLI_console.h b/source/blender/blenlib/BLI_console.h
new file mode 100644
index 00000000000..bf433f78f70
--- /dev/null
+++ b/source/blender/blenlib/BLI_console.h
@@ -0,0 +1,42 @@
+/*
+ * ***** 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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Srrgey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_CONSOLE_H__
+#define __BLI_CONSOLE_H__
+
+/** \file BLI_console.h
+ * \ingroup bli
+ * \brief Set of utility functions and constants to work with consoles.
+ */
+
+/* Format string where one could BLI_snprintf() R, G and B values
+ * and get proper marker to start colored output in the console.
+ */
+#define TRUECOLOR_ANSI_COLOR_FORMAT "\x1b[38;2;%d;%d;%dm"
+
+/* Marker which indicates that colored output is finished. */
+#define TRUECOLOR_ANSI_COLOR_FINISH "\x1b[0m"
+
+#endif /* __BLI_CONSOLE_H__ */
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index ec591c6bb48..7003eb039dd 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -199,6 +199,8 @@ void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
void *BLI_gset_lookup(GSet *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/** \} */
+
/** \name GSet Iterator
* \{ */
@@ -286,7 +288,7 @@ double BLI_gset_calc_quality(GSet *gs);
*
* \note '_p' suffix denotes void pointer arg,
* so we can have functions that take correctly typed args too.
- * \{ */
+ */
unsigned int BLI_ghashutil_ptrhash(const void *key);
bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
index fa79481e25c..f74010479a9 100644
--- a/source/blender/blenlib/BLI_hash.h
+++ b/source/blender/blenlib/BLI_hash.h
@@ -68,4 +68,16 @@ BLI_INLINE float BLI_hash_int_01(unsigned int k)
return (float)BLI_hash_int(k) * (1.0f / (float)0xFFFFFFFF);
}
+BLI_INLINE void BLI_hash_pointer_to_color(const void *ptr, int *r, int *g, int *b)
+{
+ size_t val = (size_t)ptr;
+ const size_t hash_a = BLI_hash_int(val & 0x0000ffff);
+ const size_t hash_b = BLI_hash_int((uint)((val & 0xffff0000) >> 32));
+ const size_t hash =
+ hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+ *r = (hash & 0xff0000) >> 16;
+ *g = (hash & 0x00ff00) >> 8;
+ *b = hash & 0x0000ff;
+}
+
#endif // __BLI_HASH_H__
diff --git a/source/blender/blenlib/BLI_iterator.h b/source/blender/blenlib/BLI_iterator.h
index 49a3cea58bc..d3d375122a1 100644
--- a/source/blender/blenlib/BLI_iterator.h
+++ b/source/blender/blenlib/BLI_iterator.h
@@ -57,6 +57,6 @@ typedef void (*IteratorBeginCb)(BLI_Iterator *iter, void *data_in);
#define ITER_END \
} \
callback_end_func(&iter_macro); \
-}
+} ((void)0)
#endif /* __BLI_ITERATOR_H__ */
diff --git a/source/blender/blenlib/BLI_link_utils.h b/source/blender/blenlib/BLI_link_utils.h
index d469b105f93..5322547ac08 100644
--- a/source/blender/blenlib/BLI_link_utils.h
+++ b/source/blender/blenlib/BLI_link_utils.h
@@ -35,6 +35,18 @@
list = link; \
} (void)0
+/* Use for append (single linked list, storing the last element). */
+#define BLI_LINKS_APPEND(list, link) { \
+ (link)->next = NULL; \
+ if ((list)->first) { \
+ (list)->last->next = link; \
+ } \
+ else { \
+ (list)->first = link; \
+ } \
+ (list)->last = link; \
+} (void)0
+
#define BLI_LINKS_FREE(list) { \
while (list) { \
void *next = list->next; \
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 3b24cae018d..6f8e48d83b2 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -35,6 +35,7 @@
#endif
#include <math.h>
+#include "BLI_assert.h"
#include "BLI_math_inline.h"
#ifndef M_PI
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index 278771e9611..73b52125904 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -18,8 +18,8 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BLI_POLYFILL2D_BEAUTIFY_H__
-#define __BLI_POLYFILL2D_BEAUTIFY_H__
+#ifndef __BLI_POLYFILL_2D_BEAUTIFY_H__
+#define __BLI_POLYFILL_2D_BEAUTIFY_H__
struct Heap;
struct MemArena;
@@ -42,4 +42,4 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(
/* avoid realloc's when creating new structures for polyfill ngons */
#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64
-#endif /* __BLI_POLYFILL2D_BEAUTIFY_H__ */
+#endif /* __BLI_POLYFILL_2D_BEAUTIFY_H__ */
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index ee1acc5afdd..11c8a586784 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -41,9 +41,8 @@ extern "C" {
#include "BLI_compiler_compat.h"
#include "BLI_utildefines_variadic.h"
-#ifndef NDEBUG /* for BLI_assert */
-#include <stdio.h>
-#endif
+/* We could remove in future. */
+#include "BLI_assert.h"
/* useful for finding bad use of min/max */
#if 0
@@ -615,74 +614,6 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
# define UNUSED_VARS_NDEBUG UNUSED_VARS
#endif
-
-/* BLI_assert(), default only to print
- * for aborting need to define WITH_ASSERT_ABORT
- */
-/* For 'abort' only. */
-#include <stdlib.h>
-
-#ifndef NDEBUG
-# include "BLI_system.h"
-# ifdef WITH_ASSERT_ABORT
-# define _BLI_DUMMY_ABORT abort
-# else
-# define _BLI_DUMMY_ABORT() (void)0
-# endif
-# if defined(__GNUC__) || defined(_MSC_VER) /* check __func__ is available */
-# define BLI_assert(a) \
- (void)((!(a)) ? ( \
- ( \
- BLI_system_backtrace(stderr), \
- fprintf(stderr, \
- "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", \
- __FILE__, __LINE__, __func__, STRINGIFY(a)), \
- _BLI_DUMMY_ABORT(), \
- NULL)) : NULL)
-# else
-# define BLI_assert(a) \
- (void)((!(a)) ? ( \
- ( \
- fprintf(stderr, \
- "BLI_assert failed: %s:%d, at \'%s\'\n", \
- __FILE__, __LINE__, STRINGIFY(a)), \
- _BLI_DUMMY_ABORT(), \
- NULL)) : NULL)
-# endif
-#else
-# define BLI_assert(a) (void)0
-#endif
-
-/* C++ can't use _Static_assert, expects static_assert() but c++0x only,
- * Coverity also errors out. */
-#if (!defined(__cplusplus)) && \
- (!defined(__COVERITY__)) && \
- (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */
-# define BLI_STATIC_ASSERT(a, msg) __extension__ _Static_assert(a, msg);
-#else
-/* Code adapted from http://www.pixelbeat.org/programming/gcc/static_assert.html */
-/* Note we need the two concats below because arguments to ## are not expanded, so we need to
- * expand __LINE__ with one indirection before doing the actual concatenation. */
-# define ASSERT_CONCAT_(a, b) a##b
-# define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
- /* These can't be used after statements in c89. */
-# if defined(__COUNTER__) /* MSVC */
-# define BLI_STATIC_ASSERT(a, msg) \
- ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(a)) };
-# else /* older gcc, clang... */
- /* This can't be used twice on the same line so ensure if using in headers
- * that the headers are not included twice (by wrapping in #ifndef...#endif)
- * Note it doesn't cause an issue when used on same line of separate modules
- * compiled with gcc -combine -fwhole-program. */
-# define BLI_STATIC_ASSERT(a, msg) \
- ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(a)) };
-# endif
-#endif
-
-
-#define BLI_STATIC_ASSERT_ALIGN(st, align) \
- BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned")
-
/* hints for branch prediction, only use in code that runs a _lot_ where */
#ifdef __GNUC__
# define LIKELY(x) __builtin_expect(!!(x), 1)
diff --git a/source/blender/blenlib/BLI_voronoi_2d.h b/source/blender/blenlib/BLI_voronoi_2d.h
index 51d1d5aa88e..8d1ff2d4c2b 100644
--- a/source/blender/blenlib/BLI_voronoi_2d.h
+++ b/source/blender/blenlib/BLI_voronoi_2d.h
@@ -23,8 +23,8 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BLI_VORONOI_H__
-#define __BLI_VORONOI_H__
+#ifndef __BLI_VORONOI_2D_H__
+#define __BLI_VORONOI_2D_H__
struct ListBase;
@@ -67,4 +67,4 @@ void BLI_voronoi_triangulate(const VoronoiSite *sites, int sites_total, struct L
VoronoiTriangulationPoint **triangulated_points_r, int *triangulated_points_total_r,
int (**triangles_r)[3], int *triangles_total_r);
-#endif /* __BLI_VORONOI_H__ */
+#endif /* __BLI_VORONOI_2D_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index ef36b5ac6bd..5bcf4303a84 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -139,6 +139,7 @@ set(SRC
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
+ BLI_console.h
BLI_convexhull_2d.h
BLI_dial_2d.h
BLI_dlrbTree.h
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index f681d222e69..d16dd36763d 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -66,21 +66,23 @@
/**
* This function is only to be called via macros.
*
- * \note The caller must adjust \a arr_count
+ * \note The caller must adjust \a arr_len
*/
-void _bli_array_grow_func(void **arr_p, const void *arr_static,
- const int sizeof_arr_p, const int arr_count, const int num,
- const char *alloc_str)
+void _bli_array_grow_func(
+ void **arr_p, const void *arr_static,
+ const int sizeof_arr_p, const int arr_len, const int num,
+ const char *alloc_str)
{
void *arr = *arr_p;
void *arr_tmp;
- arr_tmp = MEM_mallocN(sizeof_arr_p *
- ((num < arr_count) ?
- (arr_count * 2 + 2) : (arr_count + num)), alloc_str);
+ arr_tmp = MEM_mallocN(
+ sizeof_arr_p *
+ ((num < arr_len) ?
+ (arr_len * 2 + 2) : (arr_len + num)), alloc_str);
if (arr) {
- memcpy(arr_tmp, arr, sizeof_arr_p * arr_count);
+ memcpy(arr_tmp, arr, sizeof_arr_p * arr_len);
if (arr != arr_static) {
MEM_freeN(arr);
@@ -91,6 +93,6 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
/* caller must do */
#if 0
- arr_count += num;
+ arr_len += num;
#endif
}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index fc8e786e5ff..ec75c140159 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -1345,7 +1345,7 @@ void *BLI_gset_lookup(GSet *gs, const void *key)
/**
* Returns the pointer to the key if it's found, removing it from the GSet.
- * \node Caller must handle freeing.
+ * \note Caller must handle freeing.
*/
void *BLI_gset_pop_key(GSet *gs, const void *key)
{
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index d6c58780603..06e8ade68a2 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -856,9 +856,8 @@ static void non_recursive_bvh_div_nodes_task_cb(
else {
break;
}
-
- parent->totnode = (char)(k + 1);
}
+ parent->totnode = (char)k;
}
/**
@@ -1924,6 +1923,7 @@ void BLI_bvhtree_ray_cast_all(
BLI_bvhtree_ray_cast_all_ex(tree, co, dir, radius, hit_dist, callback, userdata, BVH_RAYCAST_DEFAULT);
}
+/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index acf15b1c892..df93dad4c32 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -299,7 +299,7 @@ typedef struct BChunk {
} BChunk;
/**
- * Links to store #BChunk data in #BChunkList.chunks.
+ * Links to store #BChunk data in #BChunkList.chunk_refs.
*/
typedef struct BChunkRef {
struct BChunkRef *next, *prev;
@@ -749,6 +749,7 @@ static void bchunk_list_fill_from_array(
ASSERT_CHUNKLIST_DATA(chunk_list, data);
}
+/** \} */
/* ---------------------------------------------------------------------------
* Internal Table Lookup Functions
@@ -1013,6 +1014,10 @@ static const BChunkRef *table_lookup(
/** \} */
+/** \name Main Data De-Duplication Function
+ *
+ * \{ */
+
/**
* \param data: Data to store in the returned value.
* \param data_len_original: Length of data in bytes.
@@ -1504,6 +1509,8 @@ void BLI_array_store_clear(
BLI_mempool_clear(bs->memory.chunk);
}
+/** \} */
+
/** \name BArrayStore Statistics
* \{ */
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index b3beff0b78b..cf9e29209fb 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenlib/intern/boxpack2d.c
+/** \file blender/blenlib/intern/boxpack_2d.c
* \ingroup bli
*/
diff --git a/source/blender/blenlib/intern/jitter_2d.c b/source/blender/blenlib/intern/jitter_2d.c
index 6c51eeb36d9..26351f52c7f 100644
--- a/source/blender/blenlib/intern/jitter_2d.c
+++ b/source/blender/blenlib/intern/jitter_2d.c
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenlib/intern/jitter.c
+/** \file blender/blenlib/intern/jitter_2d.c
* \ingroup bli
* \brief Jitter offset table
*/
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 1f517471407..eed06c7841b 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -368,10 +368,8 @@ MINLINE int compare_ff_relative(float a, float b, const float max_diff, const in
{
union {float f; int i;} ua, ub;
-#if 0 /* No BLI_assert in INLINE :/ */
BLI_assert(sizeof(float) == sizeof(int));
BLI_assert(max_ulps < (1 << 22));
-#endif
if (fabsf(a - b) <= max_diff) {
return 1;
diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c
index 37fdcd7878a..9b16756134e 100644
--- a/source/blender/blenlib/intern/math_bits_inline.c
+++ b/source/blender/blenlib/intern/math_bits_inline.c
@@ -34,7 +34,7 @@
MINLINE int bitscan_forward_i(int a)
{
BLI_assert(a != 0);
-# ifdef _MSC_VER
+#ifdef _MSC_VER
unsigned long ctz;
_BitScanForward(&ctz, a);
return ctz;
@@ -63,7 +63,7 @@ MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a)
MINLINE int bitscan_reverse_i(int a)
{
BLI_assert(a != 0);
-# ifdef _MSC_VER
+#ifdef _MSC_VER
unsigned long clz;
_BitScanReverse(&clz, a);
return clz;
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index cb39134af45..534abeb913d 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -656,135 +656,80 @@ void rgb_to_lab(float r, float g, float b, float *ll, float *la, float *lb)
xyz_to_lab(x, y, z, ll, la, lb);
}
-static void xyz_to_lms(float x, float y, float z, float *l, float *m, float *s)
-{
- *l = 0.3897f * x + 0.6890f * y - 0.0787f * z;
- *m = -0.2298f * x + 1.1834f * y + 0.0464f * z;
- *s = z;
-}
-
-static void lms_to_xyz(float l, float m, float s, float *x, float *y, float *z)
-{
- *x = 1.9102f * l - 1.1121f * m + 0.2019f * s;
- *y = 0.3709f * l + 0.6290f * m + 0.0000f * s;
- *z = s;
-}
-
-static void normalize_rgb(float rgb[3])
-{
- const float max = max_fff(rgb[0], rgb[1], rgb[2]);
+/* ****************************** blackbody ******************************** */
- if (max > 0.0f) {
- mul_v3_fl(rgb, 1.0f / max);
- }
-}
-
-/* Color rendering of spectra, adapted from public domain code by John Walker,
- * http://www.fourmilab.ch/
+/* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
+ * which is enough to get the same 8 bit/channel color.
*/
-static void spectrum_to_xyz(float temperature, float xyz[3])
-{
- int i;
- float lambda, x = 0.0f, y = 0.0f, z = 0.0f, xyz_sum;
-
- /* CIE colour matching functions xBar, yBar, and zBar for wavelengths from
- * 380 through 780 nanometers, every 5 nanometers.
- * For a wavelength lambda in this range:
- *
- * cie_colour_match[(lambda - 380) / 5][0] = xBar
- * cie_colour_match[(lambda - 380) / 5][1] = yBar
- * cie_colour_match[(lambda - 380) / 5][2] = zBar
- */
-
- const float cie_colour_match[81][3] = {
- {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
- {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
- {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
- {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
- {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
- {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
- {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
- {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
- {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
- {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
- {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
- {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
- {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
- {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
- {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
- {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
- {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
- {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
- {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
- {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
- {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
- {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
- {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
- {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
- {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
- {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
- {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}
- };
-
- for (i = 0, lambda = 380.0f; lambda < 780.1f; i++, lambda += 5.0f) {
- /* wavelength in meter */
- const float wlm = lambda * 1e-9f;
- const float Me = (3.74183e-16f * powf(wlm, -5.0f)) / (expf(1.4388e-2f / (wlm * temperature)) - 1.0f);
-
- x += Me * cie_colour_match[i][0];
- y += Me * cie_colour_match[i][1];
- z += Me * cie_colour_match[i][2];
+static const float blackbody_table_r[6][3] = {
+ { 2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f },
+ { 3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f },
+ { 4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f },
+ { 4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f },
+ { 4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f },
+ { 3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f },
+};
+
+static const float blackbody_table_g[6][3] = {
+ { -7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f },
+ { -1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f },
+ { -1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f },
+ { -1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f },
+ { -1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f },
+ { -5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f },
+};
+
+static const float blackbody_table_b[6][4] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { -2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f },
+ { -2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f },
+ { 6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f },
+};
+
+static void blackbody_temperature_to_rgb(float rgb[3], float t)
+{
+ if(t >= 12000.0f) {
+ rgb[0] = 0.826270103f;
+ rgb[1] = 0.994478524f;
+ rgb[2] = 1.56626022f;
+ }
+ else if(t < 965.0f) {
+ rgb[0] = 4.70366907f;
+ rgb[1] = 0.0f;
+ rgb[2] = 0.0f;
+ }
+ else {
+ int i = (t >= 6365.0f)? 5:
+ (t >= 3315.0f)? 4:
+ (t >= 1902.0f)? 3:
+ (t >= 1449.0f)? 2:
+ (t >= 1167.0f)? 1: 0;
+
+ const float *r = blackbody_table_r[i];
+ const float *g = blackbody_table_g[i];
+ const float *b = blackbody_table_b[i];
+
+ const float t_inv = 1.0f / t;
+ rgb[0] = r[0] * t_inv + r[1] * t + r[2];
+ rgb[1] = g[0] * t_inv + g[1] * t + g[2];
+ rgb[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
}
-
- xyz_sum = (x + y + z);
-
- xyz[0] = x / xyz_sum;
- xyz[1] = y / xyz_sum;
- xyz[2] = z / xyz_sum;
}
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max)
{
- int i, j = 0, dj = 1;
- float rgb[3], xyz[3], lms[3], lms_w[3];
- float bb_temp;
-
- if (min < max) {
- SWAP(float, min, max);
- j = width - 1;
- dj = -1;
- }
+ for (int i = 0; i < width; i++) {
+ float temperature = min + (max - min) / (float)width * (float)i;
- for (i = 0; i < width; i++, j += dj) {
- bb_temp = min + (max - min) / (float)width * (float)i;
+ float rgb[3];
+ blackbody_temperature_to_rgb(rgb, temperature);
- /* integrate blackbody radiation spectrum to XYZ */
- spectrum_to_xyz(bb_temp, xyz);
-
- /* normalize highest temperature to white (in LMS system) */
- xyz_to_lms(xyz[0], xyz[1], xyz[2], &lms[0], &lms[1], &lms[2]);
-
- if (i == 0) {
- lms_w[0] = 1.0f / lms[0];
- lms_w[1] = 1.0f / lms[1];
- lms_w[2] = 1.0f / lms[2];
- }
-
- mul_v3_v3(lms, lms_w);
-
- lms_to_xyz(lms[0], lms[1], lms[2], &xyz[0], &xyz[1], &xyz[2]);
-
- /* convert to RGB */
- xyz_to_rgb(xyz[0], xyz[1], xyz[2], &rgb[0], &rgb[1], &rgb[2], BLI_XYZ_CIE);
- constrain_rgb(&rgb[0], &rgb[1], &rgb[2]);
- normalize_rgb(rgb);
-
- copy_v3_v3(&r_table[(j << 2)], rgb);
-
- if (rgb[2] > 0.1f)
- r_table[(j << 2) + 3] = rgb[2];
- else
- r_table[(j << 2) + 3] = 0.0f;
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
}
}
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index 93bfb02bce4..17f3205aaff 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -18,7 +18,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenlib/intern/polyfill2d_beautify.c
+/** \file blender/blenlib/intern/polyfill_2d_beautify.c
* \ingroup bli
*
* This function is to improve the tessellation resulting from polyfill2d,
@@ -265,7 +265,8 @@ static void polyedge_rotate(
struct HalfEdge *e)
{
/** CCW winding, rotate internal edge to new vertical state.
- * <pre>
+ *
+ * \code{.unparsed}
* Before After
* X X
* / \ /|\
@@ -276,7 +277,7 @@ static void polyedge_rotate(
* e2\ /e1 e2\ | /e1
* \ / \|/
* X X
- * </pre>
+ * \endcode
*/
struct HalfEdge *ed[6];
uint ed_index[6];
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 1a178db1413..700524965f0 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -386,6 +386,8 @@ void BLI_halton_1D(unsigned int prime, double offset, int n, double *r)
{
const double invprime = 1.0 / (double)prime;
+ *r = 0.0;
+
for (int s = 0; s < n; s++) {
*r = halton_ex(invprime, &offset);
}
@@ -395,6 +397,8 @@ void BLI_halton_2D(unsigned int prime[2], double offset[2], int n, double *r)
{
const double invprimes[2] = {1.0 / (double)prime[0], 1.0 / (double)prime[1]};
+ r[0] = r[1] = 0.0;
+
for (int s = 0; s < n; s++) {
for (int i = 0; i < 2; i++) {
r[i] = halton_ex(invprimes[i], &offset[i]);
@@ -406,6 +410,8 @@ void BLI_halton_3D(unsigned int prime[3], double offset[3], int n, double *r)
{
const double invprimes[3] = {1.0 / (double)prime[0], 1.0 / (double)prime[1], 1.0 / (double)prime[2]};
+ r[0] = r[1] = r[2] = 0.0;
+
for (int s = 0; s < n; s++) {
for (int i = 0; i < 3; i++) {
r[i] = halton_ex(invprimes[i], &offset[i]);
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index c08329ef34f..f69b35ce5a9 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -185,7 +185,7 @@ size_t BLI_file_size(const char *path)
}
/**
- * Returns the st_mode from statting the specified path name, or 0 if it couldn't be statted
+ * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
* (most likely doesn't exist or no access).
*/
int BLI_exists(const char *name)
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 6022732025b..c0e4b8f8168 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -208,7 +208,7 @@ size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
}
/**
- * Portable replacement for #vsnprintf
+ * Portable replacement for `vsnprintf`.
*/
size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
{
@@ -503,7 +503,7 @@ int BLI_strcaseeq(const char *a, const char *b)
}
/**
- * Portable replacement for #strcasestr (not available in MSVC)
+ * Portable replacement for `strcasestr` (not available in MSVC)
*/
char *BLI_strcasestr(const char *s, const char *find)
{
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 53c0c560c0d..5d3c6b35ac1 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -1310,11 +1310,11 @@ static void parallel_mempool_func(
/**
* This function allows to parallelize for loops over Mempool items.
*
- * \param pool The iterable BLI_mempool to loop over.
- * \param userdata Common userdata passed to all instances of \a func.
- * \param func Callback function.
- * \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 mempool: The iterable BLI_mempool to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param use_threading: If \a true, actually split-execute loop in threads, else just do a sequential for loop
+ * (allows caller to use any kind of test to switch on parallelization or not).
*
* \note There is no static scheduling here.
*/
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e5708ec4df0..33f15c8473b 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2904,6 +2904,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main
link_list(fd, &workspace->hook_layout_relations);
link_list(fd, &workspace->scene_viewlayer_relations);
link_list(fd, BKE_workspace_transform_orientations_get(workspace));
+ link_list(fd, &workspace->owner_ids);
for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first;
relation;
@@ -5287,6 +5288,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->domain->shadow = NULL;
smd->domain->tex = NULL;
smd->domain->tex_shadow = NULL;
+ smd->domain->tex_flame = NULL;
smd->domain->tex_wt = NULL;
smd->domain->coba = newdataadr(fd, smd->domain->coba);
@@ -7082,6 +7084,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
}
win->ghostwin = NULL;
+ win->gwnctx = NULL;
win->eventstate = NULL;
win->tweak = NULL;
#ifdef WIN32
@@ -8545,6 +8548,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->icon_id = 0;
id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
id->orig_id = NULL;
+ id->recalc = 0;
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 044c47847be..bd4e4c2e35c 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1756,6 +1756,24 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
+ if (!MAIN_VERSION_ATLEAST(main, 279, 3)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "clipping")) {
+ Object *ob;
+ ModifierData *md;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->domain) {
+ smd->domain->clipping = 1e-3f;
+ }
+ }
+ }
+ }
+ }
+ }
+
{
/* Fix for invalid state of screen due to bug in older versions. */
for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index f3b6b157413..9590d5eeb05 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1346,13 +1346,13 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
if (dw->ob != NULL) {
dw->index = 0;
if (part->dup_group) { /* can be NULL if lining fails or set to None */
- FOREACH_GROUP_OBJECT(part->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object)
{
if (object != dw->ob) {
dw->index++;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
@@ -3796,6 +3796,7 @@ static void write_workspace(WriteData *wd, WorkSpace *workspace)
writelist(wd, DATA, WorkSpaceLayout, layouts);
writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations);
writelist(wd, DATA, WorkSpaceDataRelation, &workspace->scene_viewlayer_relations);
+ writelist(wd, DATA, wmOwnerID, &workspace->owner_ids);
writelist(wd, DATA, TransformOrientation, transform_orientations);
}
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index aba0160622f..c4b29e91fb4 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -1282,8 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
}
/* create region face */
- f_new = BLI_array_count(edges) ?
- BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL;
+ f_new = BLI_array_len(edges) ?
+ BM_face_create_ngon(bm, v1, v2, edges, BLI_array_len(edges), faces[0], BM_CREATE_NOP) : NULL;
if (UNLIKELY(f_new == NULL)) {
/* Invalid boundary region to join faces */
goto error;
@@ -1347,11 +1347,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
/* delete old geometry */
if (do_del) {
- for (i = 0; i < BLI_array_count(deledges); i++) {
+ for (i = 0; i < BLI_array_len(deledges); i++) {
BM_edge_kill(bm, deledges[i]);
}
- for (i = 0; i < BLI_array_count(delverts); i++) {
+ for (i = 0; i < BLI_array_len(delverts); i++) {
BM_vert_kill(bm, delverts[i]);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 8533083af22..ef7b54195ff 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -521,21 +521,19 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
}
/**
- * Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normals_vnos
+ * Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normal_vcos
*/
static void bm_mesh_edges_sharp_tag(
- BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
- float (*r_lnos)[3])
+ BMesh *bm,
+ const float (*vnos)[3], const float (*fnos)[3], float (*r_lnos)[3],
+ const float split_angle, const bool do_sharp_edges_tag)
{
BMIter eiter;
BMEdge *e;
int i;
const bool check_angle = (split_angle < (float)M_PI);
-
- if (check_angle) {
- split_angle = cosf(split_angle);
- }
+ const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
{
char htype = BM_VERT | BM_LOOP;
@@ -560,7 +558,7 @@ static void bm_mesh_edges_sharp_tag(
if (check_angle) {
const float *no_a = fnos ? fnos[BM_elem_index_get(l_a->f)] : l_a->f->no;
const float *no_b = fnos ? fnos[BM_elem_index_get(l_b->f)] : l_b->f->no;
- is_angle_smooth = (dot_v3v3(no_a, no_b) >= split_angle);
+ is_angle_smooth = (dot_v3v3(no_a, no_b) >= split_angle_cos);
}
/* We only tag edges that are *really* smooth:
@@ -570,20 +568,28 @@ static void bm_mesh_edges_sharp_tag(
* and both its faces have compatible (non-flipped) normals,
* i.e. both loops on the same edge do not share the same vertex.
*/
- if (is_angle_smooth &&
- BM_elem_flag_test(e, BM_ELEM_SMOOTH) &&
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) &&
BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) &&
BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH) &&
l_a->v != l_b->v)
{
- const float *no;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
-
- /* linked vertices might be fully smooth, copy their normals to loop ones. */
- no = vnos ? vnos[BM_elem_index_get(l_a->v)] : l_a->v->no;
- copy_v3_v3(r_lnos[BM_elem_index_get(l_a)], no);
- no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
- copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
+ if (is_angle_smooth) {
+ const float *no;
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+
+ /* linked vertices might be fully smooth, copy their normals to loop ones. */
+ if (r_lnos) {
+ no = vnos ? vnos[BM_elem_index_get(l_a->v)] : l_a->v->no;
+ copy_v3_v3(r_lnos[BM_elem_index_get(l_a)], no);
+ no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
+ copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
+ }
+ }
+ else if (do_sharp_edges_tag) {
+ /* Note that we do not care about the other sharp-edge cases (sharp poly, non-manifold edge, etc.),
+ * only tag edge as sharp when it is due to angle threashold. */
+ BM_elem_flag_disable(e, BM_ELEM_SMOOTH);
+ }
}
}
}
@@ -591,9 +597,11 @@ static void bm_mesh_edges_sharp_tag(
bm->elem_index_dirty &= ~BM_EDGE;
}
-/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
- * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
-static bool bm_mesh_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
+/**
+ * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once.
+ */
+bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
{
BMLoop *lfan_pivot_next = l_curr;
BMEdge *e_next = l_curr->e;
@@ -659,7 +667,7 @@ static void bm_mesh_loops_calc_normals(
r_lnors_spacearr = &_lnors_spacearr;
}
if (r_lnors_spacearr) {
- BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop);
+ BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
}
@@ -694,7 +702,7 @@ static void bm_mesh_loops_calc_normals(
* However, this would complicate the code, add more memory usage, and BM_vert_step_fan_loop()
* is quite cheap in term of CPU cycles, so really think it's not worth it. */
if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !bm_mesh_loop_check_cyclic_smooth_fan(l_curr)))
+ (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !BM_loop_check_cyclic_smooth_fan(l_curr)))
{
}
else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
@@ -728,7 +736,7 @@ static void bm_mesh_loops_calc_normals(
BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL);
/* We know there is only one loop in this space, no need to create a linklist in this case... */
- BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, false);
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true);
if (has_clnors) {
short (*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
@@ -847,7 +855,7 @@ static void bm_mesh_loops_calc_normals(
if (r_lnors_spacearr) {
/* Assign current lnor space to current 'vertex' loop. */
- BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, true);
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false);
if (e_next != e_org) {
/* We store here all edges-normalized vectors processed. */
BLI_stack_push(edge_vectors, vec_next);
@@ -1008,7 +1016,7 @@ void BM_loops_calc_normal_vcos(
if (use_split_normals) {
/* Tag smooth edges and set lnos from vnos when they might be completely smooth...
* When using custom loop normals, disable the angle feature! */
- bm_mesh_edges_sharp_tag(bm, vnos, fnos, has_clnors ? (float)M_PI : split_angle, r_lnos);
+ bm_mesh_edges_sharp_tag(bm, vnos, fnos, r_lnos, has_clnors ? (float)M_PI : split_angle, false);
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
@@ -1019,6 +1027,20 @@ void BM_loops_calc_normal_vcos(
}
}
+/** Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer, to keep same shading as with autosmooth!
+ */
+void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
+{
+ if (split_angle >= (float)M_PI) {
+ /* Nothing to do! */
+ return;
+ }
+
+ bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true);
+}
+
static void UNUSED_FUNCTION(bm_mdisps_space_set)(
Object *ob, BMesh *bm, int from, int to, eObjectMode object_mode)
{
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 01f11f6f942..10f024423aa 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -52,6 +52,11 @@ void BM_loops_calc_normal_vcos(
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
struct MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset);
+bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
+
+
+void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
+
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 1cd51528e06..961cc458784 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -482,8 +482,8 @@ BMEdge *BM_vert_collapse_faces(
BLI_array_append(faces, f);
}
- if (BLI_array_count(faces) >= 2) {
- BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces), true);
+ if (BLI_array_len(faces) >= 2) {
+ BMFace *f2 = BM_faces_join(bm, faces, BLI_array_len(faces), true);
if (f2) {
BMLoop *l_a, *l_b;
@@ -499,7 +499,7 @@ BMEdge *BM_vert_collapse_faces(
}
}
- BLI_assert(BLI_array_count(faces) < 8);
+ BLI_assert(BLI_array_len(faces) < 8);
BLI_array_free(faces);
}
@@ -608,7 +608,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
} while (l != e->l);
/* flag existing faces so we can differentiate oldfaces from new faces */
- for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ for (i = 0; i < BLI_array_len(oldfaces); i++) {
BM_ELEM_API_FLAG_ENABLE(oldfaces[i], _FLAG_OVERLAP);
oldfaces[i] = BM_face_copy(bm, bm, oldfaces[i], true, true);
BM_ELEM_API_FLAG_DISABLE(oldfaces[i], _FLAG_OVERLAP);
@@ -639,7 +639,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
int i, j;
/* interpolate new/changed loop data from copied old faces */
- for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ for (i = 0; i < BLI_array_len(oldfaces); i++) {
float f_center_old[3];
BM_face_calc_center_mean(oldfaces[i], f_center_old);
@@ -671,7 +671,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
}
/* destroy the old faces */
- for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ for (i = 0; i < BLI_array_len(oldfaces); i++) {
BM_face_verts_kill(bm, oldfaces[i]);
}
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 41775bdf2d0..85dfd3f58e2 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -665,7 +665,7 @@ bool BM_face_split_edgenet(
BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT);
} while ((l_iter = l_iter->next) != l_first);
- if (BLI_array_count(face_arr)) {
+ if (BLI_array_len(face_arr)) {
bmesh_face_swap_data(f, face_arr[0]);
BM_face_kill(bm, face_arr[0]);
face_arr[0] = f;
@@ -674,13 +674,13 @@ bool BM_face_split_edgenet(
BM_ELEM_API_FLAG_DISABLE(f, FACE_NET);
}
- for (i = 0; i < BLI_array_count(face_arr); i++) {
+ for (i = 0; i < BLI_array_len(face_arr); i++) {
BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET);
}
if (r_face_arr) {
*r_face_arr = face_arr;
- *r_face_arr_len = BLI_array_count(face_arr);
+ *r_face_arr_len = BLI_array_len(face_arr);
}
else {
if (face_arr) {
@@ -860,7 +860,7 @@ static void bvhtree_test_edges_isect_2d_ray_cb(
/**
* Store values for:
* - #bm_face_split_edgenet_find_connection
- * - #test_edges_isect_2d
+ * - #test_edges_isect_2d_vert
* ... which don't change each call.
*/
struct EdgeGroup_FindConnection_Args {
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 32f726df01d..3a76f4ca271 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -1526,9 +1526,9 @@ float BM_loop_calc_face_angle(const BMLoop *l)
*
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
*
- * \param l The loop to calculate the normal at
- * \param epsilon: Value to avoid numeric errors (1e-5f works well).
- * \param r_normal Resulting normal
+ * \param l: The loop to calculate the normal at.
+ * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
+ * \param r_normal: Resulting normal.
*/
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
{
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 5a2f07be70a..816d2e8d009 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -179,7 +179,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
}
BMW_end(&regwalker);
- for (i = 0; i < BLI_array_count(faces); i++) {
+ for (i = 0; i < BLI_array_len(faces); i++) {
f_iter = faces[i];
BMO_face_flag_disable(bm, f_iter, FACE_TAG);
BMO_face_flag_enable(bm, f_iter, FACE_ORIG);
@@ -198,7 +198,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
/* track how many faces we should end up with */
int totface_target = bm->totface;
- for (i = 0; i < BLI_array_count(regions); i++) {
+ for (i = 0; i < BLI_array_len(regions); i++) {
BMFace *f_new;
int tot = 0;
@@ -259,7 +259,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
cleanup:
/* free/cleanup */
- for (i = 0; i < BLI_array_count(regions); i++) {
+ for (i = 0; i < BLI_array_len(regions); i++) {
if (regions[i]) MEM_freeN(regions[i]);
}
diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c
index 744ef866128..931ac684b07 100644
--- a/source/blender/bmesh/operators/bmo_edgenet.c
+++ b/source/blender/bmesh/operators/bmo_edgenet.c
@@ -179,22 +179,22 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
if (!count) {
edges1 = edges;
- BLI_array_count_set(edges1, BLI_array_count(edges));
+ BLI_array_len_set(edges1, BLI_array_len(edges));
}
else {
edges2 = edges;
- BLI_array_count_set(edges2, BLI_array_count(edges));
+ BLI_array_len_set(edges2, BLI_array_len(edges));
}
BLI_array_clear(edges);
count++;
}
- if (edges1 && BLI_array_count(edges1) > 2 &&
- BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1]))
+ if (edges1 && BLI_array_len(edges1) > 2 &&
+ BM_edge_share_vert_check(edges1[0], edges1[BLI_array_len(edges1) - 1]))
{
- if (edges2 && BLI_array_count(edges2) > 2 &&
- BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1]))
+ if (edges2 && BLI_array_len(edges2) > 2 &&
+ BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1]))
{
BLI_array_free(edges1);
BLI_array_free(edges2);
@@ -206,8 +206,8 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
}
}
- if (edges2 && BLI_array_count(edges2) > 2 &&
- BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1]))
+ if (edges2 && BLI_array_len(edges2) > 2 &&
+ BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1]))
{
edges2 = NULL;
}
@@ -218,23 +218,23 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
float dvec1[3];
float dvec2[3];
- if (BLI_array_count(edges1) == 1) {
+ if (BLI_array_len(edges1) == 1) {
v1 = edges1[0]->v1;
v2 = edges1[0]->v2;
}
else {
v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1;
- i = BLI_array_count(edges1) - 1;
+ i = BLI_array_len(edges1) - 1;
v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
}
- if (BLI_array_count(edges2) == 1) {
+ if (BLI_array_len(edges2) == 1) {
v3 = edges2[0]->v1;
v4 = edges2[0]->v2;
}
else {
v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1;
- i = BLI_array_count(edges2) - 1;
+ i = BLI_array_len(edges2) - 1;
v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1;
}
@@ -265,9 +265,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
else if (edges1) {
BMVert *v1, *v2;
- if (BLI_array_count(edges1) > 1) {
+ if (BLI_array_len(edges1) > 1) {
v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1;
- i = BLI_array_count(edges1) - 1;
+ i = BLI_array_len(edges1) - 1;
v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE);
BMO_edge_flag_enable(bm, e, ELE_NEW);
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 7d3419b5910..8f998797a16 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -1157,7 +1157,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
loops[a] = l;
}
- vlen = BLI_array_count(loops);
+ vlen = BLI_array_len(loops);
/* find the boundary of one of the split edges */
for (a = 1; a < vlen; a++) {
@@ -1236,9 +1236,9 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
* - concave corner of an ngon.
* - 2 edges being used in 2+ ngons.
*/
-// BM_face_splits_check_legal(bm, face, loops_split, BLI_array_count(loops_split));
+// BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split));
- for (j = 0; j < BLI_array_count(loops_split); j++) {
+ for (j = 0; j < BLI_array_len(loops_split); j++) {
if (loops_split[j][0]) {
BMFace *f_new;
BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index beee9065ece..457e74ce1aa 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -3209,7 +3209,7 @@ static void build_center_ngon(BMesh *bm, BevVert *bv, int mat_nr)
BLI_array_append(ve, NULL);
}
} while ((v = v->next) != vm->boundstart);
- bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true);
+ bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true);
BLI_array_free(vv);
BLI_array_free(vf);
@@ -3960,7 +3960,7 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
BLI_array_append(sucs, bme2);
}
}
- nsucs = BLI_array_count(sucs);
+ nsucs = BLI_array_len(sucs);
bestj = j = i;
for (sucindex = 0; sucindex < nsucs; sucindex++) {
@@ -4500,15 +4500,15 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
}
}
if (do_rebuild) {
- n = BLI_array_count(vv);
+ n = BLI_array_len(vv);
f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true);
- for (k = 0; k < BLI_array_count(vv_fix); k++) {
+ for (k = 0; k < BLI_array_len(vv_fix); k++) {
bev_merge_uvs(bm, vv_fix[k]);
}
/* copy attributes from old edges */
- BLI_assert(n == BLI_array_count(ee));
+ BLI_assert(n == BLI_array_len(ee));
bme_prev = ee[n - 1];
for (k = 0; k < n; k++) {
bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]);
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index cc772535e37..1df0705c855 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -34,7 +34,7 @@ void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
}
}
-bool AnimationExporter::exportAnimations(const struct EvaluationContext *eval_ctx, Scene *sce)
+bool AnimationExporter::exportAnimations(Scene *sce)
{
bool has_animations = hasAnimations(sce);
if (has_animations) {
@@ -50,40 +50,265 @@ bool AnimationExporter::exportAnimations(const struct EvaluationContext *eval_ct
return has_animations;
}
-// called for each exported object
+bool AnimationExporter::is_flat_line(std::vector<float> &values, int channel_count)
+{
+ for (int i = 0; i < values.size(); i += channel_count) {
+ for (int j = 0; j < channel_count; j++) {
+ if (!bc_in_range(values[j], values[i+j], 0.000001))
+ return false;
+ }
+ }
+ return true;
+}
+/*
+ * This function creates a complete LINEAR Collada <Animation> Entry with all needed
+ * <source>, <sampler>, and <channel> entries.
+ * This is is used for creating sampled Transformation Animations for either:
+ *
+ * 1-axis animation:
+ * times contains the time points in seconds from within the timeline
+ * values contains the data (list of single floats)
+ * channel_count = 1
+ * axis_name = ['X' | 'Y' | 'Z']
+ * is_rot indicates if the animation is a rotation
+ *
+ * 3-axis animation:
+ * times contains the time points in seconds from within the timeline
+ * values contains the data (list of floats where each 3 entries are one vector)
+ * channel_count = 3
+ * axis_name = "" (actually not used)
+ * is_rot = false (see xxx below)
+ *
+ * xxx: I tried to create a 3 axis rotation animation
+ * like for translation or scale. But i could not
+ * figure out how to setup the channel for this case.
+ * So for now rotations are exported as 3 separate 1-axis collada animations
+ * See export_sampled_animation() further down.
+ */
+void AnimationExporter::create_sampled_animation(int channel_count,
+ std::vector<float> &times,
+ std::vector<float> &values,
+ std::string ob_name,
+ std::string label,
+ std::string axis_name,
+ bool is_rot)
+{
+ char anim_id[200];
+
+ if (is_flat_line(values, channel_count))
+ return;
+
+ BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), label.c_str(), axis_name.c_str());
+
+ openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
+
+ /* create input source */
+ std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, times, false, anim_id, "");
+
+ /* create output source */
+ std::string output_id;
+ if (channel_count == 1)
+ output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, &values[0], values.size(), is_rot, anim_id, axis_name.c_str());
+ else if (channel_count == 3)
+ output_id = create_xyz_source(&values[0], times.size(), anim_id);
+ else if (channel_count == 16)
+ output_id = create_4x4_source(times, values, anim_id);
+
+ std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+ COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
+ std::string empty;
+ sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
+
+ /* TODO create in/out tangents source (LINEAR) */
+ std::string interpolation_id = fake_interpolation_source(times.size(), anim_id, "");
+
+ /* Create Sampler */
+ sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+ addSampler(sampler);
+
+ /* Create channel */
+ std::string target = translate_id(ob_name) + "/" + label + axis_name + ((is_rot) ? ".ANGLE" : "");
+ addChannel(COLLADABU::URI(empty, sampler_id), target);
+
+ closeAnimation();
+
+}
+
+/*
+ * Export all animation FCurves of an Object.
+ *
+ * Note: This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent infromation
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ *
+ * If it is necessary to conserve the Animation precisely then
+ * use export_sampled_animation_set() instead.
+ */
+void AnimationExporter::export_keyframed_animation_set(Object *ob)
+{
+ FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
+ if (!fcu) {
+ return; /* object has no animation */
+ }
+
+ if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
+
+ std::vector<float> ctimes;
+ find_keyframes(ob, ctimes);
+ if (ctimes.size() > 0)
+ export_sampled_matrix_animation(ob, ctimes);
+ }
+ else {
+ char *transformName;
+ while (fcu) {
+ //for armature animations as objects
+ if (ob->type == OB_ARMATURE)
+ transformName = fcu->rna_path;
+ else
+ transformName = extract_transform_name(fcu->rna_path);
+
+ if (
+ STREQ(transformName, "location") ||
+ STREQ(transformName, "scale") ||
+ (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
+ STREQ(transformName, "rotation_quaternion"))
+ {
+ create_keyframed_animation(ob, fcu, transformName, false);
+ }
+ fcu = fcu->next;
+ }
+ }
+}
+
+/*
+ * Export the sampled animation of an Object.
+ *
+ * Note: This steps over all animation frames (step size is given in export_settings.sample_size)
+ * and then evaluates the transformation,
+ * and exports "baked samples" This works always, however currently the interpolation type is set
+ * to LINEAR for now. (maybe later this can be changed to BEZIER)
+ *
+ * Note: If it is necessary to keep the FCurves intact, then use export_keyframed_animation_set() instead.
+ * However be aware that exporting keyframed animation may modify the animation slightly.
+ * Also keyframed animation exports tend to break when negative scales are involved.
+ */
+void AnimationExporter::export_sampled_animation_set(Object *ob)
+{
+ std::vector<float>ctimes;
+ find_sampleframes(ob, ctimes);
+ if (ctimes.size() > 0) {
+ if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX)
+ export_sampled_matrix_animation(ob, ctimes);
+ else
+ export_sampled_transrotloc_animation(ob, ctimes);
+ }
+}
+
+void AnimationExporter::export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes)
+{
+ UnitConverter converter;
+
+ std::vector<float> values;
+
+ for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime) {
+ float fmat[4][4];
+
+ bc_update_scene(eval_ctx, scene, *ctime);
+ BKE_object_matrix_local_get(ob, fmat);
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(fmat, 6);
+
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ values.push_back(fmat[i][j]);
+ }
+
+ std::string ob_name = id_name(ob);
+
+ create_sampled_animation(16, ctimes, values, ob_name, "transform", "", false);
+}
+
+void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes)
+{
+ static int LOC = 0;
+ static int EULX = 1;
+ static int EULY = 2;
+ static int EULZ = 3;
+ static int SCALE = 4;
+
+ std::vector<float> baked_curves[5];
+
+ for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) {
+ float fmat[4][4];
+ float floc[3];
+ float fquat[4];
+ float fsize[3];
+ float feul[3];
+
+ bc_update_scene(eval_ctx, scene, *ctime);
+ BKE_object_matrix_local_get(ob, fmat);
+ mat4_decompose(floc, fquat, fsize, fmat);
+ quat_to_eul(feul, fquat);
+
+ baked_curves[LOC].push_back(floc[0]);
+ baked_curves[LOC].push_back(floc[1]);
+ baked_curves[LOC].push_back(floc[2]);
+
+ baked_curves[EULX].push_back(feul[0]);
+ baked_curves[EULY].push_back(feul[1]);
+ baked_curves[EULZ].push_back(feul[2]);
+
+ baked_curves[SCALE].push_back(fsize[0]);
+ baked_curves[SCALE].push_back(fsize[1]);
+ baked_curves[SCALE].push_back(fsize[2]);
+
+ }
+
+ std::string ob_name = id_name(ob);
+
+ create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale", "", false);
+ create_sampled_animation(3, ctimes, baked_curves[LOC], ob_name, "location", "", false);
+
+ /* Not sure how to export rotation as a 3channel animation,
+ * so separate into 3 single animations for now:
+ */
+
+ create_sampled_animation(1, ctimes, baked_curves[EULX], ob_name, "rotation", "X", true);
+ create_sampled_animation(1, ctimes, baked_curves[EULY], ob_name, "rotation", "Y", true);
+ create_sampled_animation(1, ctimes, baked_curves[EULZ], ob_name, "rotation", "Z", true);
+
+ fprintf(stdout, "Animation Export: Baked %d frames for %s (sampling rate: %d)\n",
+ (int)baked_curves[0].size(),
+ ob->id.name,
+ this->export_settings->sampling_rate);
+}
+
+/* called for each exported object */
void AnimationExporter::operator()(Object *ob)
{
- FCurve *fcu;
char *transformName;
+
/* bool isMatAnim = false; */ /* UNUSED */
//Export transform animations
if (ob->adt && ob->adt->action) {
- fcu = (FCurve *)ob->adt->action->curves.first;
- //transform matrix export for bones are temporarily disabled here.
if (ob->type == OB_ARMATURE) {
+ /* Export skeletal animation (if any)*/
bArmature *arm = (bArmature *)ob->data;
for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
write_bone_animation_matrix(ob, bone);
}
- while (fcu) {
- //for armature animations as objects
- if (ob->type == OB_ARMATURE)
- transformName = fcu->rna_path;
- else
- transformName = extract_transform_name(fcu->rna_path);
-
- if ((STREQ(transformName, "location") || STREQ(transformName, "scale")) ||
- (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
- (STREQ(transformName, "rotation_quaternion")))
- {
- dae_animation(ob, fcu, transformName, false);
- }
- fcu = fcu->next;
+ /* Armatures can have object animation and skeletal animation*/
+ if (this->export_settings->sampling_rate < 1) {
+ export_keyframed_animation_set(ob);
+ }
+ else {
+ export_sampled_animation_set(ob);
}
-
}
export_object_constraint_animation(ob);
@@ -93,14 +318,14 @@ void AnimationExporter::operator()(Object *ob)
//Export Lamp parameter animations
if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
- fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
+ FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
(STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
{
- dae_animation(ob, fcu, transformName, true);
+ create_keyframed_animation(ob, fcu, transformName, true);
}
fcu = fcu->next;
}
@@ -108,7 +333,7 @@ void AnimationExporter::operator()(Object *ob)
//Export Camera parameter animations
if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
- fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
+ FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
@@ -117,7 +342,7 @@ void AnimationExporter::operator()(Object *ob)
(STREQ(transformName, "clip_end")) ||
(STREQ(transformName, "clip_start")))
{
- dae_animation(ob, fcu, transformName, true);
+ create_keyframed_animation(ob, fcu, transformName, true);
}
fcu = fcu->next;
}
@@ -129,7 +354,7 @@ void AnimationExporter::operator()(Object *ob)
if (!ma) continue;
if (ma->adt && ma->adt->action) {
/* isMatAnim = true; */
- fcu = (FCurve *)ma->adt->action->curves.first;
+ FCurve *fcu = (FCurve *)ma->adt->action->curves.first;
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
@@ -137,7 +362,7 @@ void AnimationExporter::operator()(Object *ob)
(STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
(STREQ(transformName, "ior")))
{
- dae_animation(ob, fcu, transformName, true, ma);
+ create_keyframed_animation(ob, fcu, transformName, true, ma);
}
fcu = fcu->next;
}
@@ -168,7 +393,7 @@ void AnimationExporter::export_morph_animation(Object *ob)
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
- dae_animation(ob, fcu, transformName, true);
+ create_keyframed_animation(ob, fcu, transformName, true);
fcu = fcu->next;
}
@@ -201,7 +426,7 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl
obtar = ct->tar;
if (obtar)
- find_frames(obtar, frames);
+ find_keyframes(obtar, frames);
}
if (cti->flush_constraint_targets)
@@ -266,8 +491,8 @@ std::string AnimationExporter::getAnimationPathId(const FCurve *fcu)
return translate_id(rna_path);
}
-//convert f-curves to animation curves and write
-void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
+/* convert f-curves to animation curves and write */
+void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
{
const char *axis_name = NULL;
char anim_id[200];
@@ -275,6 +500,8 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
bool has_tangents = false;
bool quatRotation = false;
+ Object *obj = NULL;
+
if (STREQ(transformName, "rotation_quaternion") ) {
fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
quatRotation = true;
@@ -292,15 +519,26 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
axis_name = axis_names[fcu->array_index];
}
- //axis names for transforms
- else if (STREQ(transformName, "location") ||
- STREQ(transformName, "scale") ||
- STREQ(transformName, "rotation_euler") ||
- STREQ(transformName, "rotation_quaternion"))
+ /*
+ * Note: Handle transformation animations separately (to apply matrix inverse to fcurves)
+ * We will use the object to evaluate the animation on all keyframes and calculate the
+ * resulting object matrix. We need this to incorporate the
+ * effects of the parent inverse matrix (when it contains a rotation component)
+ *
+ * TODO: try to combine exported fcurves into 3 channel animations like done
+ * in export_sampled_animation(). For now each channel is exported as separate <Animation>.
+ */
+
+ else if (
+ STREQ(transformName, "scale") ||
+ STREQ(transformName, "location") ||
+ STREQ(transformName, "rotation_euler"))
{
const char *axis_names[] = {"X", "Y", "Z"};
- if (fcu->array_index < 3)
+ if (fcu->array_index < 3) {
axis_name = axis_names[fcu->array_index];
+ obj = ob;
+ }
}
else {
/* no axis name. single parameter */
@@ -309,7 +547,7 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
std::string ob_name = std::string("null");
- //Create anim Id
+ /* Create anim Id */
if (ob->type == OB_ARMATURE) {
ob_name = getObjectBoneName(ob, fcu);
BLI_snprintf(
@@ -358,7 +596,7 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
}
else {
- output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
+ output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name, obj);
}
// create interpolations source
@@ -370,10 +608,10 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
if (has_tangents) {
// create in_tangent source
- intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
+ intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj);
// create out_tangent source
- outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
+ outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name, obj);
}
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
@@ -476,8 +714,11 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B
if (!pchan)
return;
- //every inserted keyframe of bones.
- find_frames(ob_arm, fra);
+
+ if (this->export_settings->sampling_rate < 1)
+ find_keyframes(ob_arm, fra);
+ else
+ find_sampleframes(ob_arm, fra);
if (flag & ARM_RESTPOS) {
arm->flag &= ~ARM_RESTPOS;
@@ -531,7 +772,7 @@ void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_
addSampler(sampler);
- std::string target = get_joint_id(bone, ob_arm) + "/transform";
+ std::string target = get_joint_id(ob_arm, bone) + "/transform";
addChannel(COLLADABU::URI(empty, sampler_id), target);
closeAnimation();
@@ -756,14 +997,60 @@ void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSeman
}
}
+// old function to keep compatibility for calls where offset and object are not needed
std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
{
- std::string source_id = anim_id + get_semantic_suffix(semantic);
+ return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL);
+}
- //bool is_angle = STREQ(fcu->rna_path, "rotation");
- bool is_angle = false;
+void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime)
+{
+ BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
+ ListBase *conlist = get_active_constraints(this->eval_ctx, ob);
+ bConstraint *con;
+ for (con = (bConstraint *)conlist->first; con; con = con->next) {
+ ListBase targets = { NULL, NULL };
+
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (cti && cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+ Object *obtar;
+ cti->get_constraint_targets(con, &targets);
+ for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ obtar = ct->tar;
- if (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path,"spot_size")) is_angle = true;
+ if (obtar) {
+ BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(this->eval_ctx, scene, obtar, ctime);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ BKE_object_where_is_calc_time(this->eval_ctx, scene, ob, ctime);
+}
+
+/*
+ * ob is needed to aply parent inverse information to fcurve.
+ * TODO: Here we have to step over all keyframes for each object and for each fcurve.
+ * Instead of processing each fcurve one by one,
+ * step over the animation from keyframe to keyframe,
+ * then create adjusted fcurves (and entries) for all affected objects.
+ * Then we would need to step through the scene only once.
+ */
+std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob)
+{
+ std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+ bool is_angle = (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path, "spot_size"));
+ bool is_euler = strstr(fcu->rna_path, "rotation_euler");
+ bool is_translation = strstr(fcu->rna_path, "location");
+ bool is_scale = strstr(fcu->rna_path, "scale");
+ bool is_tangent = false;
+ int offset_index = 0;
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
@@ -774,27 +1061,76 @@ std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemanti
case COLLADASW::InputSemantic::INPUT:
case COLLADASW::InputSemantic::OUTPUT:
source.setAccessorStride(1);
+ offset_index = 0;
break;
case COLLADASW::InputSemantic::IN_TANGENT:
case COLLADASW::InputSemantic::OUT_TANGENT:
source.setAccessorStride(2);
+ offset_index = 1;
+ is_tangent = true;
break;
default:
break;
}
-
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_angle, axis_name, false);
source.prepareToAppendValues();
- for (unsigned int i = 0; i < fcu->totvert; i++) {
+ for (unsigned int frame_index = 0; frame_index < fcu->totvert; frame_index++) {
+ float fixed_val = 0;
+ if (ob) {
+ float fmat[4][4];
+ float frame = fcu->bezt[frame_index].vec[1][0];
+ float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+
+ evaluate_anim_with_constraints(ob, ctime); // set object transforms to fcurve's i'th keyframe
+
+ BKE_object_matrix_local_get(ob, fmat);
+ float floc[3];
+ float fquat[4];
+ float fsize[3];
+ mat4_decompose(floc, fquat, fsize, fmat);
+
+ if (is_euler) {
+ float eul[3];
+ quat_to_eul(eul, fquat);
+ fixed_val = RAD2DEGF(eul[fcu->array_index]);
+ }
+ else if (is_translation) {
+ fixed_val = floc[fcu->array_index];
+ }
+ else if (is_scale) {
+ fixed_val = fsize[fcu->array_index];
+ }
+ }
+
float values[3]; // be careful!
+ float offset = 0;
int length = 0;
- get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
- for (int j = 0; j < length; j++)
- source.appendValues(values[j]);
+ get_source_values(&fcu->bezt[frame_index], semantic, is_angle, values, &length);
+ if (is_tangent) {
+ float bases[3];
+ int len = 0;
+ get_source_values(&fcu->bezt[frame_index], COLLADASW::InputSemantic::OUTPUT, is_angle, bases, &len);
+ offset = values[offset_index] - bases[0];
+ }
+
+ for (int j = 0; j < length; j++) {
+ float val;
+ if (j == offset_index) {
+ if (ob) {
+ val = fixed_val + offset;
+ }
+ else {
+ val = values[j] + offset;
+ }
+ } else {
+ val = values[j];
+ }
+ source.appendValues(val);
+ }
}
source.finish();
@@ -838,9 +1174,9 @@ std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLA
return source_id;
}
-
-
-//Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
+/*
+ * only to get OUTPUT source values ( if rotation and hence the axis is also specified )
+ */
std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -870,7 +1206,10 @@ std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic
return source_id;
}
-// only used for sources with INPUT semantic
+
+/*
+ * only used for sources with INPUT semantic
+ */
std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -901,9 +1240,47 @@ std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemanti
return source_id;
}
+std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std::vector<float> &values , const std::string &anim_id)
+{
+ COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
+ std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+ COLLADASW::Float4x4Source source(mSW);
+ source.setId(source_id);
+ source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+ source.setAccessorCount(ctimes.size());
+ source.setAccessorStride(16);
+
+ COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+ add_source_parameters(param, semantic, false, NULL, true);
+
+ source.prepareToAppendValues();
+
+ std::vector<float>::iterator it;
+
+ for (it = values.begin(); it != values.end(); it+=16) {
+ float mat[4][4];
+
+ bc_copy_m4_farray(mat, &*it);
+
+ UnitConverter converter;
+ double outmat[4][4];
+ converter.mat4_to_dae_double(outmat, mat);
+
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(outmat, 6);
+
+ source.appendValues(outmat);
+ }
+
+ source.finish();
+ return source_id;
+}
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id)
{
+ bool is_bone_animation = ob->type == OB_ARMATURE && bone;
+
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -921,7 +1298,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
bPoseChannel *parchan = NULL;
bPoseChannel *pchan = NULL;
- if (ob->type == OB_ARMATURE && bone) {
+ if (is_bone_animation) {
bPose *pose = ob->pose;
pchan = BKE_pose_channel_find_name(pose, bone->name);
if (!pchan)
@@ -936,13 +1313,12 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
int j = 0;
for (it = frames.begin(); it != frames.end(); it++) {
float mat[4][4], ipar[4][4];
+ float frame = *it;
+
+ float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+ bc_update_scene(eval_ctx, scene, ctime);
+ if (is_bone_animation) {
- float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
- CFRA = BKE_scene_frame_get_from_ctime(scene, *it);
- //BKE_scene_graph_update_for_newframe(G.main->eval_ctx, depsgraph, G.main,scene);
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
-
- if (bone) {
if (pchan->flag & POSE_CHAIN) {
enable_fcurves(ob->adt->action, NULL);
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
@@ -960,9 +1336,10 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
else
copy_m4_m4(mat, pchan->pose_mat);
- // OPEN_SIM_COMPATIBILITY
- // AFAIK animation to second life is via BVH, but no
- // reason to not have the collada-animation be correct
+ /* OPEN_SIM_COMPATIBILITY
+ * AFAIK animation to second life is via BVH, but no
+ * reason to not have the collada-animation be correct
+ */
if (export_settings->open_sim) {
float temp[4][4];
copy_m4_m4(temp, bone->arm_mat);
@@ -981,7 +1358,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
}
else {
- calc_ob_mat_at_time(ob, ctime, mat);
+ copy_m4_m4(mat, ob->obmat);
}
UnitConverter converter;
@@ -1009,7 +1386,9 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
}
-// only used for sources with OUTPUT semantic ( locations and scale)
+/*
+ * only used for sources with OUTPUT semantic ( locations and scale)
+ */
std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
{
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
@@ -1193,8 +1572,10 @@ std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type,
return std::string("");
}
-// Assign sid of the animated parameter or transform
-// for rotation, axis name is always appended and the value of append_axis is ignored
+/*
+ * Assign sid of the animated parameter or transform for rotation,
+ * axis name is always appended and the value of append_axis is ignored
+ */
std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
std::string tm_name;
@@ -1278,29 +1659,10 @@ char *AnimationExporter::extract_transform_name(char *rna_path)
return dot ? (dot + 1) : rna_path;
}
-//find keyframes of all the objects animations
-void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
-{
- if (ob->adt && ob->adt->action) {
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-
- for (; fcu; fcu = fcu->next) {
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- float f = fcu->bezt[i].vec[1][0];
- if (std::find(fra.begin(), fra.end(), f) == fra.end())
- fra.push_back(f);
- }
- }
-
- // keep the keys in ascending order
- std::sort(fra.begin(), fra.end());
- }
-}
-
-
-
-// enable fcurves driving a specific bone, disable all the rest
-// if bone_name = NULL enable all fcurves
+/*
+ * enable fcurves driving a specific bone, disable all the rest
+ * if bone_name = NULL enable all fcurves
+ */
void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
{
FCurve *fcu;
@@ -1365,14 +1727,53 @@ bool AnimationExporter::hasAnimations(Scene *sce)
void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
{
if (rotmode > 0)
- find_frames(ob, fra, prefix, "rotation_euler");
+ find_keyframes(ob, fra, prefix, "rotation_euler");
else if (rotmode == ROT_MODE_QUAT)
- find_frames(ob, fra, prefix, "rotation_quaternion");
+ find_keyframes(ob, fra, prefix, "rotation_quaternion");
/*else if (rotmode == ROT_MODE_AXISANGLE)
;*/
}
-void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
+/* Take care to always have the first frame and the last frame in the animation
+ * regardless of the sampling_rate setting
+ */
+void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra)
+{
+ int frame = scene->r.sfra;
+ do {
+ float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+ fra.push_back(ctime);
+ if (frame == scene->r.efra)
+ break;
+ frame += this->export_settings->sampling_rate;
+ if (frame > scene->r.efra)
+ frame = scene->r.efra; // make sure the last frame is always exported
+
+ } while (true);
+}
+
+/*
+ * find keyframes of all the objects animations
+ */
+void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra)
+{
+ if (ob->adt && ob->adt->action) {
+ FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
+
+ for (; fcu; fcu = fcu->next) {
+ for (unsigned int i = 0; i < fcu->totvert; i++) {
+ float f = fcu->bezt[i].vec[1][0];
+ if (std::find(fra.begin(), fra.end(), f) == fra.end())
+ fra.push_back(f);
+ }
+ }
+
+ // keep the keys in ascending order
+ std::sort(fra.begin(), fra.end());
+ }
+}
+
+void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
{
if (ob->adt && ob->adt->action) {
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
@@ -1430,10 +1831,10 @@ void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bo
find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
break;
case 1:
- find_frames(ob_arm, fra, prefix, "scale");
+ find_keyframes(ob_arm, fra, prefix, "scale");
break;
case 2:
- find_frames(ob_arm, fra, prefix, "location");
+ find_keyframes(ob_arm, fra, prefix, "location");
break;
default:
return;
@@ -1527,46 +1928,21 @@ void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, i
bool AnimationExporter::validateConstraints(bConstraint *con)
{
- bool valid = true;
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
/* these we can skip completely (invalid constraints...) */
- if (cti == NULL) valid = false;
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false;
- /* these constraints can't be evaluated anyway */
- if (cti->evaluate_constraint == NULL) valid = false;
- /* influence == 0 should be ignored */
- if (con->enforce == 0.0f) valid = false;
-
- return valid;
-}
+ if (cti == NULL)
+ return false;
+ if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
+ return false;
-void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4])
-{
- ListBase *conlist = get_active_constraints(this->eval_ctx, ob);
- bConstraint *con;
- for (con = (bConstraint *)conlist->first; con; con = con->next) {
- ListBase targets = {NULL, NULL};
-
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- Object *obtar;
- cti->get_constraint_targets(con, &targets);
- for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
- obtar = ct->tar;
+ /* these constraints can't be evaluated anyway */
+ if (cti->evaluate_constraint == NULL)
+ return false;
- if (obtar) {
- BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
- BKE_object_where_is_calc_time(eval_ctx, scene, obtar, ctime);
- }
- }
+ /* influence == 0 should be ignored */
+ if (con->enforce == 0.0f)
+ return false;
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- BKE_object_where_is_calc_time(eval_ctx, scene, ob, ctime);
- copy_m4_m4(mat, ob->obmat);
+ /* validation passed */
+ return true;
}
-
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
index 5af5d884455..d2216c04ee5 100644
--- a/source/blender/collada/AnimationExporter.h
+++ b/source/blender/collada/AnimationExporter.h
@@ -85,25 +85,26 @@ class AnimationExporter: COLLADASW::LibraryAnimations
{
private:
Scene *scene;
- const struct EvaluationContext *eval_ctx;
+ EvaluationContext *eval_ctx;
COLLADASW::StreamWriter *sw;
public:
- AnimationExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
- COLLADASW::LibraryAnimations(sw), export_settings(export_settings)
- { this->sw = sw; }
-
-
- bool exportAnimations(const struct EvaluationContext *eval_ctx, Scene *sce);
+ AnimationExporter(EvaluationContext *eval_ctx, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
+ eval_ctx(eval_ctx),
+ COLLADASW::LibraryAnimations(sw),
+ export_settings(export_settings)
+ {
+ this->sw = sw;
+ }
+ bool exportAnimations(Scene *sce);
// called for each exported object
void operator() (Object *ob);
protected:
const ExportSettings *export_settings;
- void dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL);
void export_object_constraint_animation(Object *ob);
@@ -144,7 +145,18 @@ protected:
float* get_eul_source_for_quat(Object *ob );
+ bool is_flat_line(std::vector<float> &values, int channel_count);
+ void export_keyframed_animation_set(Object *ob);
+ void create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL);
+ void export_sampled_animation_set(Object *ob);
+ void export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes);
+ void export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes);
+ void create_sampled_animation(int channel_count, std::vector<float> &times, std::vector<float> &values, std::string, std::string label, std::string axis_name, bool is_rot);
+
+ void evaluate_anim_with_constraints(Object *ob, float ctime);
+
std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name);
+ std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob);
std::string create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id);
@@ -153,7 +165,7 @@ protected:
std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name);
std::string create_xyz_source(float *v, int tot, const std::string& anim_id);
-
+ std::string create_4x4_source(std::vector<float> &times, std::vector<float> &values, const std::string& anim_id);
std::string create_4x4_source(std::vector<float> &frames, Object * ob_arm, Bone *bone, const std::string& anim_id);
std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
@@ -165,8 +177,10 @@ protected:
std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
- void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
- void find_frames(Object *ob, std::vector<float> &fra);
+ void find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
+ void find_keyframes(Object *ob, std::vector<float> &fra);
+ void find_sampleframes(Object *ob, std::vector<float> &fra);
+
void make_anim_frames_from_targets(Object *ob, std::vector<float> &frames );
@@ -187,6 +201,5 @@ protected:
bool validateConstraints(bConstraint *con);
- void calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4]);
};
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index e63b70edcf5..ee3fddbf5b7 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -70,14 +70,15 @@ FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path)
fcu->array_index = array_index;
return fcu;
}
-
-void AnimationImporter::create_bezt(FCurve *fcu, float frame, float output)
+
+void AnimationImporter::add_bezt(FCurve *fcu, float frame, float value, eBezTriple_Interpolation ipo)
{
+ //float fps = (float)FPS;
BezTriple bez;
memset(&bez, 0, sizeof(BezTriple));
bez.vec[1][0] = frame;
- bez.vec[1][1] = output;
- bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+ bez.vec[1][1] = value;
+ bez.ipo = ipo; /* use default interpolation mode here... */
bez.f1 = bez.f2 = bez.f3 = SELECT;
bez.h1 = bez.h2 = HD_AUTO;
insert_bezt_fcurve(fcu, &bez, 0);
@@ -401,7 +402,7 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
eul_to_quat(quat, eul);
for (int k = 0; k < 4; k++)
- create_bezt(quatcu[k], frame, quat[k]);
+ create_bezt(quatcu[k], frame, quat[k], U.ipo_new);
}
}
@@ -764,7 +765,6 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a
axis = i - 7;
}
-
if (is_joint)
BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str);
else
@@ -780,8 +780,8 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a
std::vector<float>::iterator it;
- float qref[4];
- unit_qt(qref);
+ //float qref[4];
+ //unit_qt(qref);
// sample values at each frame
for (it = frames.begin(); it != frames.end(); it++) {
@@ -817,18 +817,7 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a
}
float rot[4], loc[3], scale[3];
- transpose_m4(mat);
-
- bc_rotate_from_reference_quat(rot, qref, mat);
- copy_qt_qt(qref, rot);
-
-#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);
+ mat4_decompose(loc, rot, scale, mat);
// add keys
for (int i = 0; i < totcu; i++) {
@@ -1572,7 +1561,8 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
copy_m4_m4(mat, matfra);
}
- float val[4], rot[4], loc[3], scale[3];
+ float val[4] = {};
+ float rot[4], loc[3], scale[3];
switch (tm_type) {
case COLLADAFW::Transformation::ROTATE:
@@ -1844,23 +1834,18 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float
}
COLLADABU::Math::Matrix4 matrix;
- int i = 0, j = 0;
+ int mi = 0, mj = 0;
for (std::vector<FCurve *>::iterator it = curves.begin(); it != curves.end(); it++) {
- matrix.setElement(i, j, evaluate_fcurve(*it, fra));
- j++;
- if (j == 4) {
- i++;
- j = 0;
+ matrix.setElement(mi, mj, evaluate_fcurve(*it, fra));
+ mj++;
+ if (mj == 4) {
+ mi++;
+ mj = 0;
}
fcurve_is_used(*it);
}
-
- COLLADAFW::Matrix tm(matrix);
- dae_matrix_to_mat4(&tm, mat);
-
- std::vector<FCurve *>::iterator it;
-
+ unit_converter->dae_matrix_to_mat4_(mat, matrix);
return true;
}
}
@@ -2023,19 +2008,6 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv
action_groups_add_channel(act, grp, fcu);
}
-void AnimationImporter::add_bezt(FCurve *fcu, float fra, float value)
-{
- //float fps = (float)FPS;
- BezTriple bez;
- memset(&bez, 0, sizeof(BezTriple));
- bez.vec[1][0] = fra;
- bez.vec[1][1] = value;
- bez.ipo = BEZT_IPO_LIN; /* use default interpolation mode here... */
- bez.f1 = bez.f2 = bez.f3 = SELECT;
- bez.h1 = bez.h2 = HD_AUTO;
- insert_bezt_fcurve(fcu, &bez, 0);
- calchandles_fcurve(fcu);
-}
void AnimationImporter::set_import_from_version(std::string import_from_version)
{
diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h
index 15dee8ff5f4..7dc4131dd69 100644
--- a/source/blender/collada/AnimationImporter.h
+++ b/source/blender/collada/AnimationImporter.h
@@ -78,7 +78,7 @@ private:
FCurve *create_fcurve(int array_index, const char *rna_path);
- void create_bezt(FCurve *fcu, float frame, float output);
+ void add_bezt(FCurve *fcu, float frame, float value, eBezTriple_Interpolation ipo=BEZT_IPO_LIN);
// create one or several fcurves depending on the number of parameters being animated
void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
@@ -214,8 +214,6 @@ public:
void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu);
- void add_bezt(FCurve *fcu, float fra, float value);
-
void extra_data_importer(std::string elementName);
};
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 844be2dd60b..fbceb6e077f 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -89,7 +89,7 @@ void ArmatureExporter::add_armature_bones(const EvaluationContext *eval_ctx, Obj
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
{
if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
- ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
+ ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
else {
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
write_bone_URLs(ins, ob_arm, child);
@@ -162,9 +162,9 @@ void ArmatureExporter::add_bone_node(const EvaluationContext *eval_ctx, Bone *bo
std::list<Object *>& child_objects)
{
if (!(this->export_settings->deform_bones_only && bone->flag & BONE_NO_DEFORM)) {
- std::string node_id = get_joint_id(bone, ob_arm);
+ std::string node_id = get_joint_id(ob_arm, bone);
std::string node_name = std::string(bone->name);
- std::string node_sid = get_joint_sid(bone, ob_arm);
+ std::string node_sid = get_joint_sid(bone);
COLLADASW::Node node(mSW);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 8832e0fd577..b2794b3bd23 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -284,12 +284,11 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
BoneExtended *dominant_child = NULL;
int maxlen = 0;
- Bone *child;
if (parentbone == NULL)
return;
- child = (Bone *)parentbone->childbase.first;
+ Bone *child = (Bone *)parentbone->childbase.first;
if (child && (import_settings->find_chains || child->next==NULL)) {
for (; child; child = child->next) {
BoneExtended *be = extended_bones[child->name];
@@ -339,8 +338,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
}
}
}
- for (Bone *child = (Bone *)parentbone->childbase.first; child; child = child->next) {
- ArmatureImporter::connect_bone_chains(armature, child, UNLIMITED_CHAIN_MAX);
+ for (Bone *ch = (Bone *)parentbone->childbase.first; ch; ch = ch->next) {
+ ArmatureImporter::connect_bone_chains(armature, ch, UNLIMITED_CHAIN_MAX);
}
}
else if (maxlen>1 && maxlen > this->import_settings->min_chain_length) {
@@ -350,8 +349,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
else {
/* can't connect this Bone. Proceed with children ... */
if (pbe) pbe->set_leaf_bone(true);
- for (Bone *child = (Bone *)parentbone->childbase.first; child; child = child->next) {
- ArmatureImporter::connect_bone_chains(armature, child, UNLIMITED_CHAIN_MAX);
+ for (Bone *ch = (Bone *)parentbone->childbase.first; ch; ch = ch->next) {
+ ArmatureImporter::connect_bone_chains(armature, ch, UNLIMITED_CHAIN_MAX);
}
}
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index f413651167c..f32cb624f78 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -71,7 +71,7 @@ bool ControllerExporter::is_skinned_mesh(Object *ob)
void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
{
if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
- ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
+ ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
else {
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
write_bone_URLs(ins, ob_arm, child);
@@ -280,7 +280,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
}
if (oob_counter > 0) {
- fprintf(stderr, "Ignored %d Vertex weights which use index to non existing VGroup %lu.\n",
+ fprintf(stderr, "Ignored %d Vertex weights which use index to non existing VGroup %zu.\n",
oob_counter, joint_index_by_def_index.size());
}
}
@@ -456,7 +456,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb
for (def = (bDeformGroup *)defbase->first; def; def = def->next) {
Bone *bone = get_bone_from_defgroup(ob_arm, def);
if (bone)
- source.appendValues(get_joint_sid(bone, ob_arm));
+ source.appendValues(get_joint_sid(bone));
}
source.finish();
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index 1741312af5f..04af73f2406 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -152,7 +152,9 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
return data->layers[layer_index].name;
}
-DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) {
+DocumentExporter::DocumentExporter(EvaluationContext *eval_ctx, const ExportSettings *export_settings) :
+ eval_ctx(eval_ctx),
+ export_settings(export_settings) {
}
static COLLADABU::NativeString make_temp_filepath(const char *name, const char *extension)
@@ -179,7 +181,8 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char *
// COLLADA allows this through multiple <channel>s in <animation>.
// For this to work, we need to know objects that use a certain action.
-int DocumentExporter::exportCurrentScene(const EvaluationContext *eval_ctx, Scene *sce)
+
+int DocumentExporter::exportCurrentScene(Scene *sce)
{
PointerRNA sceneptr, unit_settings;
PropertyRNA *system; /* unused , *scale; */
@@ -300,29 +303,11 @@ int DocumentExporter::exportCurrentScene(const EvaluationContext *eval_ctx, Scen
SceneExporter se(writer, &arm_exporter, this->export_settings);
- // <library_animations>
- AnimationExporter ae(writer, this->export_settings);
-
-#if 0
- bool has_animations = ae.exportAnimations(eval_ctx, sce);
- /* The following code seems to be an obsolete workaround
- Comment out until it proofs correct that we no longer need it.
- */
- if (has_animations && this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
- // channels adressing <matrix> objects is not (yet) supported
- // So we force usage of <location>, <translation> and <scale>
- fprintf(stdout,
- "For animated Ojects we must use decomposed <matrix> elements,\n" \
- "Forcing usage of TransLocRot transformation type.");
- se.setExportTransformationType(BC_TRANSFORMATION_TYPE_TRANSROTLOC);
- }
- else {
- se.setExportTransformationType(this->export_settings->export_transformation_type);
+ if (this->export_settings->include_animations) {
+ // <library_animations>
+ AnimationExporter ae(eval_ctx, writer, this->export_settings);
+ ae.exportAnimations(sce);
}
-#else
- ae.exportAnimations(eval_ctx, sce);
- se.setExportTransformationType(this->export_settings->export_transformation_type);
-#endif
se.exportScene(eval_ctx, sce);
// <scene>
diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h
index 895787c7bbc..68e1523fbee 100644
--- a/source/blender/collada/DocumentExporter.h
+++ b/source/blender/collada/DocumentExporter.h
@@ -27,10 +27,11 @@
#ifndef __DOCUMENTEXPORTER_H__
#define __DOCUMENTEXPORTER_H__
-#include "ExportSettings.h"
+#include "collada.h"
extern "C" {
#include "DNA_customdata_types.h"
+
}
struct Scene;
@@ -38,11 +39,13 @@ struct Scene;
class DocumentExporter
{
public:
- DocumentExporter(const ExportSettings *export_settings);
- int exportCurrentScene(const struct EvaluationContext *eval_ctx, Scene *sce);
+ DocumentExporter(EvaluationContext *eval_ctx, const ExportSettings *export_settings);
+ int exportCurrentScene(Scene *sce);
+
void exportScenes(const char *filename);
private:
const ExportSettings *export_settings;
+ EvaluationContext *eval_ctx;
};
#endif
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index dfd662aa66c..7999b3c4727 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -195,8 +195,8 @@ void DocumentImporter::finish()
std::vector<Object *> *objects_to_scale = new std::vector<Object *>();
/** TODO Break up and put into 2-pass parsing of DAE */
- std::vector<const COLLADAFW::VisualScene *>::iterator it;
- for (it = vscenes.begin(); it != vscenes.end(); it++) {
+ std::vector<const COLLADAFW::VisualScene *>::iterator sit;
+ for (sit = vscenes.begin(); sit != vscenes.end(); sit++) {
PointerRNA sceneptr, unit_settings;
PropertyRNA *system, *scale;
@@ -227,7 +227,7 @@ void DocumentImporter::finish()
}
// Write nodes to scene
- const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
+ const COLLADAFW::NodePointerArray& roots = (*sit)->getRootNodes();
for (unsigned int i = 0; i < roots.getCount(); i++) {
std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false);
objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end());
@@ -252,8 +252,8 @@ void DocumentImporter::finish()
armature_importer.fix_animation();
#endif
- for (std::vector<const COLLADAFW::VisualScene *>::iterator it = vscenes.begin(); it != vscenes.end(); it++) {
- const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
+ for (std::vector<const COLLADAFW::VisualScene *>::iterator vsit = vscenes.begin(); vsit != vscenes.end(); vsit++) {
+ const COLLADAFW::NodePointerArray& roots = (*vsit)->getRootNodes();
for (unsigned int i = 0; i < roots.getCount(); i++) {
translate_anim_recursive(roots[i], NULL, NULL);
@@ -261,7 +261,6 @@ void DocumentImporter::finish()
}
if (libnode_ob.size()) {
- Scene *sce = CTX_data_scene(mContext);
fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
// free all library_nodes
@@ -472,9 +471,9 @@ void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
{
if (et && et->isProfile("blender")) {
std::string name;
- short* type = 0;
- et->setData("type", type);
- BKE_constraint_add_for_object(ob, "Test_con", *type);
+ short type = 0;
+ et->setData("type", &type);
+ BKE_constraint_add_for_object(ob, "Test_con", type);
}
}
@@ -585,8 +584,8 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
++lamp_done;
}
while (controller_done < controller.getCount()) {
- COLLADAFW::InstanceGeometry *geom = (COLLADAFW::InstanceGeometry *)controller[controller_done];
- ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map);
+ COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)controller[controller_done];
+ ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map, material_texture_mapping_map);
if (ob == NULL) {
report_unknown_reference(*node, "instance_controller");
}
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 5e7f92047d3..5e2b00be82a 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(sce, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
{
int a;
for (a = 0; a < ob->totcol; a++) {
@@ -79,7 +79,7 @@ bool EffectsExporter::hasEffects(Scene *sce)
return true;
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
return false;
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 33a7527f383..b6a7c1f1b4e 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -27,11 +27,24 @@
#ifndef __EXPORTSETTINGS_H__
#define __EXPORTSETTINGS_H__
-#include "collada.h"
-#include "collada.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_linklist.h"
+
+typedef enum BC_export_mesh_type {
+ BC_MESH_TYPE_VIEW,
+ BC_MESH_TYPE_RENDER
+} BC_export_mesh_type;
+
+typedef enum BC_export_transformation_type {
+ BC_TRANSFORMATION_TYPE_MATRIX,
+ BC_TRANSFORMATION_TYPE_TRANSROTLOC
+} BC_export_transformation_type;
-struct ExportSettings {
-public:
+
+typedef struct ExportSettings {
bool apply_modifiers;
BC_export_mesh_type export_mesh_type;
@@ -40,6 +53,8 @@ public:
bool include_armatures;
bool include_shapekeys;
bool deform_bones_only;
+ bool include_animations;
+ int sampling_rate;
bool active_uv_only;
bool include_material_textures;
@@ -57,6 +72,10 @@ public:
char *filepath;
LinkNode *export_set;
-};
+} ExportSettings;
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index a2ab3ce520b..3cdc013c137 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -158,8 +158,8 @@ bool ImagesExporter::hasImages(Scene *sce)
for (node = this->export_settings->export_set; node; node = node->next) {
Object *ob = (Object *)node->link;
- int a;
- for (a = 0; a < ob->totcol; a++) {
+
+ for (int a = 0; a < ob->totcol; a++) {
Material *ma = give_current_material(ob, a + 1);
// no material, but check all of the slots
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 4a2d4e8046a..fb4277b048f 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -27,10 +27,7 @@
#ifndef __IMPORTSETTINGS_H__
#define __IMPORTSETTINGS_H__
-#include "collada.h"
-
-struct ImportSettings {
-public:
+typedef struct ImportSettings {
bool import_units;
bool find_chains;
bool auto_connect;
@@ -38,6 +35,6 @@ public:
int min_chain_length;
char *filepath;
bool keep_bind_info;
-};
+} ImportSettings;
#endif
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index f8cd487c355..ec1b14a3855 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -554,7 +554,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
{
CustomData edata;
MEdge *medge;
- int i, totedge;
+ int totedge;
if (len == 0)
return;
@@ -574,7 +574,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
/* set default flags */
medge = &mesh->medge[mesh->totedge];
- for (i = 0; i < len; i++, medge++)
+ for (int i = 0; i < len; i++, medge++)
medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
mesh->totedge = totedge;
@@ -608,12 +608,12 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
unsigned int edge_count = mp->getFaceCount();
unsigned int *indices = mp->getPositionIndices().getData();
- for (int i = 0; i < edge_count; i++, med++) {
+ for (int j = 0; j < edge_count; j++, med++) {
med->bweight = 0;
med->crease = 0;
med->flag |= ME_LOOSEEDGE;
- med->v1 = indices[2 * i];
- med->v2 = indices[2 * i + 1];
+ med->v1 = indices[2 * j];
+ med->v2 = indices[2 * j + 1];
}
}
}
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index c375c09d869..f24c104892d 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -39,11 +39,6 @@ SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm,
{
}
-void SceneExporter::setExportTransformationType(BC_export_transformation_type transformation_type)
-{
- this->transformation_type = transformation_type;
-}
-
void SceneExporter::exportScene(const EvaluationContext *eval_ctx, Scene *sce)
{
// <library_visual_scenes> <visual_scene>
@@ -139,7 +134,7 @@ void SceneExporter::writeNodes(const EvaluationContext *eval_ctx, Object *ob, Sc
// for skinned mesh we write obmat in <bind_shape_matrix>
TransformWriter::add_node_transform_identity(colladaNode);
else {
- TransformWriter::add_node_transform_ob(colladaNode, ob, this->transformation_type);
+ TransformWriter::add_node_transform_ob(colladaNode, ob, this->export_settings->export_transformation_type);
}
// <instance_geometry>
@@ -180,11 +175,11 @@ void SceneExporter::writeNodes(const EvaluationContext *eval_ctx, Object *ob, Sc
if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) {
Group *group = ob->dup_group;
/* printf("group detected '%s'\n", group->id.name + 2); */
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
printf("\t%s\n", object->id.name);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h
index ded48983bd9..3e3c15b836f 100644
--- a/source/blender/collada/SceneExporter.h
+++ b/source/blender/collada/SceneExporter.h
@@ -96,12 +96,9 @@ class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter,
{
public:
SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings);
- void exportScene(const struct EvaluationContext *eval_ctx, Scene *sce);
- void setExportTransformationType(BC_export_transformation_type transformation_type);
+ void exportScene(const EvaluationContext *eval_ctx, Scene *sce);
private:
- BC_export_transformation_type transformation_type;
- // required for writeNodes() for bone-parented objects
friend class ArmatureExporter;
void exportHierarchy(const struct EvaluationContext *eval_ctx, Scene *sce);
void writeNodes(const struct EvaluationContext *eval_ctx, Object *ob, Scene *sce);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index 6c5fb0b33f3..64e3a4c36ce 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -32,103 +32,41 @@
#include "DocumentImporter.h"
#include "ExportSettings.h"
#include "ImportSettings.h"
+#include "collada.h"
extern "C"
{
#include "BKE_scene.h"
#include "BKE_context.h"
+#include "DEG_depsgraph.h"
/* make dummy file */
#include "BLI_fileops.h"
#include "BLI_linklist.h"
-int collada_import(bContext *C,
- const char *filepath,
- int import_units,
- int find_chains,
- int auto_connect,
- int fix_orientation,
- int min_chain_length,
- int keep_bind_info)
+int collada_import(bContext *C, ImportSettings *import_settings)
{
-
- ImportSettings import_settings;
- import_settings.filepath = (char *)filepath;
- import_settings.import_units = import_units != 0;
- import_settings.auto_connect = auto_connect != 0;
- import_settings.find_chains = find_chains != 0;
- import_settings.fix_orientation = fix_orientation != 0;
- import_settings.min_chain_length = min_chain_length;
- import_settings.keep_bind_info = keep_bind_info !=0;
-
- DocumentImporter imp(C, &import_settings);
- if (imp.import()) return 1;
-
- return 0;
+ DocumentImporter imp(C, import_settings);
+ return (imp.import())? 1:0;
}
-int collada_export(const EvaluationContext *eval_ctx,
+int collada_export(EvaluationContext *eval_ctx,
Scene *sce,
- ViewLayer *view_layer,
- const char *filepath,
-
- int apply_modifiers,
- BC_export_mesh_type export_mesh_type,
-
- int selected,
- int include_children,
- int include_armatures,
- int include_shapekeys,
- int deform_bones_only,
-
- int active_uv_only,
- int include_material_textures,
- int use_texture_copies,
-
- int triangulate,
- int use_object_instantiation,
- int use_blender_profile,
- int sort_by_name,
- BC_export_transformation_type export_transformation_type,
- int open_sim,
- int limit_precision,
- int keep_bind_info)
+ ExportSettings *export_settings)
{
- ExportSettings export_settings;
-
- export_settings.filepath = (char *)filepath;
-
- export_settings.apply_modifiers = apply_modifiers != 0;
- export_settings.export_mesh_type = export_mesh_type;
- export_settings.selected = selected != 0;
- export_settings.include_children = include_children != 0;
- export_settings.include_armatures = include_armatures != 0;
- export_settings.include_shapekeys = include_shapekeys != 0;
- export_settings.deform_bones_only = deform_bones_only != 0;
-
- export_settings.active_uv_only = active_uv_only != 0;
- export_settings.include_material_textures= include_material_textures != 0;
- export_settings.use_texture_copies = use_texture_copies != 0;
-
- export_settings.triangulate = triangulate != 0;
- export_settings.use_object_instantiation = use_object_instantiation != 0;
- export_settings.use_blender_profile = use_blender_profile != 0;
- export_settings.sort_by_name = sort_by_name != 0;
- export_settings.export_transformation_type = export_transformation_type;
- export_settings.open_sim = open_sim != 0;
- export_settings.limit_precision = limit_precision != 0;
- export_settings.keep_bind_info = keep_bind_info !=0;
+ ViewLayer *view_layer = eval_ctx->view_layer;
int includeFilter = OB_REL_NONE;
- if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
- if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE;
+ if (export_settings->include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
+ if (export_settings->include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE;
+
+ eObjectSet objectSet = (export_settings->selected) ? OB_SET_SELECTED : OB_SET_ALL;
+ export_settings->export_set = BKE_object_relational_superset(view_layer, objectSet, (eObRelationTypes)includeFilter);
- eObjectSet objectSet = (export_settings.selected) ? OB_SET_SELECTED : OB_SET_ALL;
- export_settings.export_set = BKE_object_relational_superset(view_layer, objectSet, (eObRelationTypes)includeFilter);
- int export_count = BLI_linklist_count(export_settings.export_set);
+ int export_count = BLI_linklist_count(export_settings->export_set);
if (export_count == 0) {
- if (export_settings.selected) {
+ if (export_settings->selected) {
fprintf(stderr, "Collada: Found no objects to export.\nPlease ensure that all objects which shall be exported are also visible in the 3D Viewport.\n");
}
else {
@@ -136,14 +74,14 @@ int collada_export(const EvaluationContext *eval_ctx,
}
}
else {
- if (export_settings.sort_by_name)
- bc_bubble_sort_by_Object_name(export_settings.export_set);
+ if (export_settings->sort_by_name)
+ bc_bubble_sort_by_Object_name(export_settings->export_set);
}
- DocumentExporter exporter(&export_settings);
- int status = exporter.exportCurrentScene(eval_ctx, sce);
+ DocumentExporter exporter(eval_ctx, export_settings);
+ int status = exporter.exportCurrentScene(sce);
- BLI_linklist_free(export_settings.export_set, NULL);
+ BLI_linklist_free(export_settings->export_set, NULL);
return (status) ? -1:export_count;
}
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index eb3964f9cb7..f95fca03b65 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -28,6 +28,10 @@
#define __COLLADA_H__
#include <stdlib.h>
+
+#include "ImportSettings.h"
+#include "ExportSettings.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -36,16 +40,6 @@ extern "C" {
#include "BLI_path_util.h"
#include "RNA_types.h"
-typedef enum BC_export_mesh_type {
- BC_MESH_TYPE_VIEW,
- BC_MESH_TYPE_RENDER
-} BC_export_mesh_type;
-
-typedef enum BC_export_transformation_type {
- BC_TRANSFORMATION_TYPE_MATRIX,
- BC_TRANSFORMATION_TYPE_TRANSROTLOC
-} BC_export_transformation_type;
-
struct bContext;
struct Scene;
struct ViewLayer;
@@ -55,41 +49,12 @@ struct EvaluationContext;
* both return 1 on success, 0 on error
*/
int collada_import(struct bContext *C,
- const char *filepath,
- int import_units,
- int find_chains,
- int auto_connect,
- int fix_orientation,
- int min_chain_length,
+ ImportSettings *import_settings);
- int keep_bind_info);
-int collada_export(const struct EvaluationContext *eval_ctx,
+int collada_export(struct EvaluationContext *eval_ctx,
struct Scene *sce,
- struct ViewLayer *view_layer,
- const char *filepath,
- int apply_modifiers,
- BC_export_mesh_type export_mesh_type,
-
- int selected,
- int include_children,
- int include_armatures,
- int include_shapekeys,
- int deform_bones_only,
-
- int active_uv_only,
- int include_material_textures,
- int use_texture_copies,
-
- int triangulate,
- int use_object_instantiation,
- int use_blender_profile,
- int sort_by_name,
- BC_export_transformation_type export_transformation_type,
-
- int open_sim,
- int limit_precision,
- int keep_bind_info);
+ ExportSettings *export_settings);
#ifdef __cplusplus
}
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index 6ebde6bd773..cf4dcb5eb42 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -327,12 +327,12 @@ std::string get_light_id(Object *ob)
return translate_id(id_name(ob)) + "-light";
}
-std::string get_joint_id(Bone *bone, Object *ob_arm)
+std::string get_joint_id(Object *ob, Bone *bone)
{
- return translate_id(id_name(ob_arm) + "_" + bone->name);
+ return translate_id(id_name(ob) + "_" + bone->name);
}
-std::string get_joint_sid(Bone *bone, Object *ob_arm)
+std::string get_joint_sid(Bone *bone)
{
return translate_id(bone->name);
}
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 1c7aa160f57..299e13326ce 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -97,8 +97,8 @@ extern std::string get_geometry_id(Object *ob, bool use_instantiation);
extern std::string get_light_id(Object *ob);
-extern std::string get_joint_id(Bone *bone, Object *ob_arm);
-extern std::string get_joint_sid(Bone *bone, Object *ob_arm);
+extern std::string get_joint_id(Object *ob, Bone *bone);
+extern std::string get_joint_sid(Bone *bone);
extern std::string get_camera_id(Object *ob);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index 117e2ef7f76..cc18cea662a 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -32,6 +32,8 @@
#include "COLLADAFWMeshPrimitive.h"
#include "COLLADAFWMeshVertexData.h"
+#include <set>
+
extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_customdata_types.h"
@@ -51,6 +53,7 @@ extern "C" {
#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_main.h"
#include "ED_armature.h"
@@ -135,6 +138,30 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
return true;
}
+Scene *bc_get_scene(bContext *C)
+{
+ return CTX_data_scene(C);
+}
+
+Main *bc_get_main()
+{
+ return G.main;
+}
+
+EvaluationContext *bc_get_evaluation_context()
+{
+ Main *bmain = G.main;
+ return bmain->eval_ctx;
+}
+
+
+void bc_update_scene(EvaluationContext *eval_ctx, Scene *scene, float ctime)
+{
+ BKE_scene_frame_set(scene, ctime);
+ Main *bmain = bc_get_main();
+ BKE_scene_graph_update_for_newframe(eval_ctx, eval_ctx->depsgraph, bmain, scene, eval_ctx->view_layer);
+}
+
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);
@@ -878,3 +905,181 @@ void bc_sanitize_mat(double mat[4][4], int precision)
mat[i][j] = double_round(mat[i][j], precision);
}
+void bc_copy_m4_farray(float r[4][4], float *a)
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ r[i][j] = *a++;
+}
+
+void bc_copy_farray_m4(float *r, float a[4][4])
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ *r++ = a[i][j];
+
+}
+
+/*
+ * Returns name of Active UV Layer or empty String if no active UV Layer defined
+ */
+std::string bc_get_active_uvlayer_name(Mesh *me)
+{
+ int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ if (num_layers) {
+ char *layer_name = bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE);
+ if (layer_name) {
+ return std::string(layer_name);
+ }
+ }
+ return "";
+}
+
+/*
+* Returns name of Active UV Layer or empty String if no active UV Layer defined.
+* Assuming the Object is of type MESH
+*/
+std::string bc_get_active_uvlayer_name(Object *ob)
+{
+ Mesh *me = (Mesh *)ob->data;
+ return bc_get_active_uvlayer_name(me);
+}
+
+/*
+ * Returns UV Layer name or empty string if layer index is out of range
+ */
+std::string bc_get_uvlayer_name(Mesh *me, int layer)
+{
+ int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ if (num_layers && layer < num_layers) {
+ char *layer_name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, layer);
+ if (layer_name) {
+ return std::string(layer_name);
+ }
+ }
+ return "";
+}
+
+#if 0
+/**********************************************************************
+*
+* Return the list of Mesh objects with assigned UVtextures and Images
+* Note: We need to create artificaial materials for each of them
+*
+***********************************************************************/
+std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers)
+{
+ std::set <Object *> UVObjects;
+ Base *base = (Base *)sce->base.first;
+
+ while (base) {
+ Object *ob = base->object;
+ bool has_uvimage = false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+
+ for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
+ if (all_uv_layers || active_uv_layer == i)
+ {
+ if (me->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
+ MPoly *mpoly = me->mpoly;
+ for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
+
+ Image *ima = txface->tpage;
+ if (ima != NULL) {
+ has_uvimage = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (has_uvimage) {
+ UVObjects.insert(ob);
+ }
+ }
+ base = base->next;
+ }
+ return UVObjects;
+}
+
+/**********************************************************************
+*
+* Return the list of UV Texture images from all exported Mesh Items
+* Note: We need to create one artificial material for each Image.
+*
+***********************************************************************/
+std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers)
+{
+ std::set <Image *> UVImages;
+ Base *base = (Base *)sce->base.first;
+
+ while (base) {
+ Object *ob = base->object;
+ bool has_uvimage = false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+
+ for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
+ if (all_uv_layers || active_uv_layer == i)
+ {
+ if (me->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
+ MPoly *mpoly = me->mpoly;
+ for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
+
+ Image *ima = txface->tpage;
+ if (ima != NULL) {
+ if (UVImages.find(ima) == UVImages.end())
+ UVImages.insert(ima);
+ }
+ }
+ }
+ }
+ }
+ }
+ base = base->next;
+ }
+ return UVImages;
+}
+
+/**********************************************************************
+*
+* Return the list of UV Texture images for the given Object
+* Note: We need to create one artificial material for each Image.
+*
+***********************************************************************/
+std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers)
+{
+ std::set <Image *> UVImages;
+
+ bool has_uvimage = false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+
+ for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
+ if (all_uv_layers || active_uv_layer == i)
+ {
+ if (me->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
+ MPoly *mpoly = me->mpoly;
+ for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
+
+ Image *ima = txface->tpage;
+ if (ima != NULL) {
+ if (UVImages.find(ima) == UVImages.end())
+ UVImages.insert(ima);
+ }
+ }
+ }
+ }
+ }
+ }
+ return UVImages;
+}
+#endif
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index e3a16105861..52767557397 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -64,6 +64,11 @@ struct EvaluationContext;
typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex *> > TexIndexTextureArrayMap;
+extern Scene *bc_get_scene(bContext *C);
+extern Main *bc_get_main();
+extern EvaluationContext *bc_get_evaluation_context();
+extern void bc_update_scene(EvaluationContext *eval_ctx, Scene *scene, float ctime);
+
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);
@@ -100,6 +105,13 @@ extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
extern int bc_set_layer(int bitfield, int layer);
+
+inline bool bc_in_range(float a, float b, float range) {
+ return fabsf(a - b) < range;
+}
+void bc_copy_m4_farray(float r[4][4], float *a);
+void bc_copy_farray_m4(float *r, float a[4][4]);
+
extern void bc_sanitize_mat(float mat[4][4], int precision);
extern void bc_sanitize_mat(double mat[4][4], int precision);
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 3e1dd83112a..a141495e5ae 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
../imbuf
../makesdna
../makesrna
diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cpp b/source/blender/compositor/operations/COM_MapRangeOperation.cpp
index 7a89ba91b4c..7a38d066122 100644
--- a/source/blender/compositor/operations/COM_MapRangeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapRangeOperation.cpp
@@ -65,6 +65,11 @@ void MapRangeOperation::executePixelSampled(float output[4], float x, float y, P
dest_min = inputs[3];
dest_max = inputs[4];
+ if (fabsf(source_max - source_min) < 1e-6f) {
+ output[0] = 0.0f;
+ return;
+ }
+
if (value >= -BLENDER_ZMAX && value <= BLENDER_ZMAX) {
value = (value - source_min) / (source_max - source_min);
value = dest_min + value * (dest_max - dest_min);
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index c42d06bd0a2..c2f69343456 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -42,6 +42,7 @@ set(INC_SYS
set(SRC
intern/builder/deg_builder.cc
intern/builder/deg_builder_cycle.cc
+ intern/builder/deg_builder_map.cc
intern/builder/deg_builder_nodes.cc
intern/builder/deg_builder_nodes_layer_collection.cc
intern/builder/deg_builder_nodes_rig.cc
@@ -81,6 +82,7 @@ set(SRC
intern/builder/deg_builder.h
intern/builder/deg_builder_cycle.h
+ intern/builder/deg_builder_map.h
intern/builder/deg_builder_nodes.h
intern/builder/deg_builder_pchanmap.h
intern/builder/deg_builder_relations.h
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 8110899048d..5cd1b48e80e 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -224,6 +224,17 @@ void DEG_evaluation_context_init_from_scene(
const eObjectMode object_mode,
eEvaluationMode mode);
+void DEG_evaluation_context_init_from_view_layer_for_render(
+ struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+
+void DEG_evaluation_context_init_from_depsgraph(
+ struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
+ eEvaluationMode mode);
+
/* Free evaluation context. */
void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
@@ -269,6 +280,32 @@ typedef void (*DEG_EditorUpdateSceneCb)(
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func);
+/* Evaluation Debug ------------------------------ */
+
+void DEG_debug_print_eval(const char* function_name,
+ const char* object_name,
+ const void* object_address);
+
+void DEG_debug_print_eval_subdata(const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ const char *subdata_comment,
+ const char *subdata_name,
+ const void *subdata_address);
+
+void DEG_debug_print_eval_subdata_index(const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ const char *subdata_comment,
+ const char *subdata_name,
+ const void *subdata_address,
+ const int subdata_index);
+
+void DEG_debug_print_eval_time(const char* function_name,
+ const char* object_name,
+ const void* object_address,
+ float time);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index fffdccf3efc..3a8d6e70aca 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -124,7 +124,7 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
* 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_) \
+#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, mode_, flag_) \
{ \
DEGObjectIterData data_ = { \
.graph = (graph_), \
@@ -138,20 +138,20 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
&data_, Object *, instance_)
#define DEG_OBJECT_ITER_END \
- ITER_END \
+ 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 | \
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(graph_, instance_, mode_) \
+ DEG_OBJECT_ITER_BEGIN(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 \
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END \
DEG_OBJECT_ITER_END
/* ************************ DEG traversal ********************* */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index e30b9b44490..026aa309b02 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -46,6 +46,8 @@
namespace DEG {
+namespace {
+
typedef enum eCyclicCheckVisitedState {
/* Not is not visited at all during traversal. */
NODE_NOT_VISITED = 0,
@@ -55,6 +57,30 @@ typedef enum eCyclicCheckVisitedState {
NODE_IN_STACK = 2,
} eCyclicCheckVisitedState;
+struct StackEntry {
+ OperationDepsNode *node;
+ StackEntry *from;
+ DepsRelation *via_relation;
+};
+
+struct CyclesSolverState {
+ CyclesSolverState(Depsgraph *graph)
+ : graph(graph),
+ traversal_stack(BLI_stack_new(sizeof(StackEntry),
+ "DEG detect cycles stack")),
+ num_cycles(0) {
+ }
+ ~CyclesSolverState() {
+ BLI_stack_free(traversal_stack);
+ if (num_cycles != 0) {
+ printf("Detected %d dependency cycles\n", num_cycles);
+ }
+ }
+ Depsgraph *graph;
+ BLI_Stack *traversal_stack;
+ int num_cycles;
+};
+
BLI_INLINE void set_node_visited_state(DepsNode *node,
eCyclicCheckVisitedState state)
{
@@ -76,18 +102,20 @@ BLI_INLINE int get_node_num_visited_children(DepsNode *node)
return node->done >> 2;
}
-void deg_graph_detect_cycles(Depsgraph *graph)
+void schedule_node_to_stack(CyclesSolverState *state, OperationDepsNode *node)
{
- struct StackEntry {
- OperationDepsNode *node;
- StackEntry *from;
- DepsRelation *via_relation;
- };
-
- BLI_Stack *traversal_stack = BLI_stack_new(sizeof(StackEntry),
- "DEG detect cycles stack");
+ StackEntry entry;
+ entry.node = node;
+ entry.from = NULL;
+ entry.via_relation = NULL;
+ BLI_stack_push(state->traversal_stack, &entry);
+ set_node_visited_state(node, NODE_IN_STACK);
+}
- foreach (OperationDepsNode *node, graph->operations) {
+/* Schedule leaf nodes (node without input links) for traversal. */
+void schedule_leaf_nodes(CyclesSolverState *state)
+{
+ foreach (OperationDepsNode *node, state->graph->operations) {
bool has_inlinks = false;
foreach (DepsRelation *rel, node->inlinks) {
if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
@@ -96,18 +124,32 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
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);
- set_node_visited_state(node, NODE_IN_STACK);
+ schedule_node_to_stack(state, node);
}
else {
set_node_visited_state(node, NODE_NOT_VISITED);
}
}
+}
+
+/* Schedule node which was not checked yet for being belong to
+ * any of dependency cycle.
+ */
+bool schedule_non_checked_node(CyclesSolverState *state)
+{
+ foreach (OperationDepsNode *node, state->graph->operations) {
+ if (get_node_visited_state(node) == NODE_NOT_VISITED) {
+ schedule_node_to_stack(state, node);
+ return true;
+ }
+ }
+ return false;
+}
+/* Solve cycles with all nodes which are scheduled for traversal. */
+void solve_cycles(CyclesSolverState *state)
+{
+ BLI_Stack *traversal_stack = state->traversal_stack;
while (!BLI_stack_is_empty(traversal_stack)) {
StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
OperationDepsNode *node = entry->node;
@@ -136,6 +178,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
/* TODO(sergey): So called russian roulette cycle solver. */
rel->flag |= DEPSREL_FLAG_CYCLIC;
+ ++state->num_cycles;
}
else if (to_state == NODE_NOT_VISITED) {
StackEntry new_entry;
@@ -155,8 +198,24 @@ void deg_graph_detect_cycles(Depsgraph *graph)
BLI_stack_discard(traversal_stack);
}
}
+}
+
+} // namespace
- BLI_stack_free(traversal_stack);
+void deg_graph_detect_cycles(Depsgraph *graph)
+{
+ CyclesSolverState state(graph);
+ /* First we solve cycles which are reachable from leaf nodes. */
+ schedule_leaf_nodes(&state);
+ solve_cycles(&state);
+ /* We are not done yet. It is possible to have closed loop cycle,
+ * for example A -> B -> C -> A. These nodes were not scheduled
+ * yet (since they all have inlinks), and were not traversed since
+ * nobody else points to them.
+ */
+ while (schedule_non_checked_node(&state)) {
+ solve_cycles(&state);
+ }
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.cc b/source/blender/depsgraph/intern/builder/deg_builder_map.cc
new file mode 100644
index 00000000000..67cb04d1b98
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_map.cc
@@ -0,0 +1,64 @@
+/*
+ * ***** 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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_map.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder_map.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+namespace DEG {
+
+BuilderMap::BuilderMap() {
+ set = BLI_gset_ptr_new("deg builder gset");
+}
+
+
+BuilderMap::~BuilderMap() {
+ BLI_gset_free(set, NULL);
+}
+
+bool BuilderMap::checkIsBuilt(ID *id) {
+ return BLI_gset_haskey(set, id);
+}
+
+void BuilderMap::tagBuild(ID *id) {
+ BLI_gset_insert(set, id);
+}
+
+bool BuilderMap::checkIsBuiltAndTag(ID *id) {
+ void **key_p;
+ if (!BLI_gset_ensure_p_ex(set, id, &key_p)) {
+ *key_p = id;
+ return false;
+ }
+ return true;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.h b/source/blender/depsgraph/intern/builder/deg_builder_map.h
new file mode 100644
index 00000000000..5ad22a9aa77
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_map.h
@@ -0,0 +1,69 @@
+/*
+ * ***** 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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_map.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+struct GSet;
+struct ID;
+
+namespace DEG {
+
+class BuilderMap {
+public:
+ BuilderMap();
+ ~BuilderMap();
+
+ /* Check whether given ID is already handled by builder (or if it's being
+ * handled).
+ */
+ bool checkIsBuilt(ID *id);
+
+ /* Tag given ID as handled/built. */
+ void tagBuild(ID *id);
+
+ /* Combination of previous two functions, returns truth if ID was already
+ * handled, or tags is handled otherwise and return false.
+ */
+ bool checkIsBuiltAndTag(ID *id);
+
+ template<typename T> bool checkIsBuilt(T *datablock) {
+ return checkIsBuilt(&datablock->id);
+ }
+ template<typename T> void tagBuild(T *datablock) {
+ tagBuild(&datablock->id);
+ }
+ template<typename T> bool checkIsBuiltAndTag(T *datablock) {
+ return checkIsBuiltAndTag(&datablock->id);
+ }
+
+ GSet *set;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index b65c16591dc..e7a9b4b5a69 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -179,10 +179,10 @@ DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
}
}
-IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id, bool do_tag)
+IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
{
if (!DEG_depsgraph_use_copy_on_write()) {
- return graph_->add_id_node(id, do_tag);
+ return graph_->add_id_node(id);
}
IDDepsNode *id_node = NULL;
ID *id_cow = (ID *)BLI_ghash_lookup(cow_id_hash_, id);
@@ -192,7 +192,7 @@ IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id, bool do_tag)
*/
BLI_ghash_remove(cow_id_hash_, id, NULL, NULL);
}
- id_node = graph_->add_id_node(id, do_tag, id_cow);
+ id_node = graph_->add_id_node(id, id_cow);
/* Currently all ID nodes are supposed to have copy-on-write logic.
*
* NOTE: Zero number of components indicates that ID node was just created.
@@ -285,6 +285,22 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
name_tag);
}
+OperationDepsNode *DepsgraphNodeBuilder::ensure_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const DepsEvalOperationCb& op,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+{
+ OperationDepsNode *operation =
+ find_operation_node(id, comp_type, opcode, name, name_tag);
+ if (operation != NULL) {
+ return operation;
+ }
+ return add_operation_node(id, comp_type, op, opcode, name, name_tag);
+}
+
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
eDepsNode_Type comp_type,
const char *comp_name,
@@ -333,7 +349,7 @@ ID *DepsgraphNodeBuilder::ensure_cow_id(ID *id_orig)
/* ID is already remapped to copy-on-write. */
return id_orig;
}
- IDDepsNode *id_node = add_id_node(id_orig, false);
+ IDDepsNode *id_node = add_id_node(id_orig);
return id_node->id_cow;
}
@@ -351,23 +367,6 @@ ID *DepsgraphNodeBuilder::expand_cow_id(ID *id_orig)
/* **** Build functions for entity nodes **** */
void DepsgraphNodeBuilder::begin_build() {
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * created or not. This flag is being set in add_id_node(), so functions
- * shouldn't bother with setting it, they only might query this flag when
- * needed.
- */
- BKE_main_id_tag_all(bmain_, LIB_TAG_DOIT, false);
- /* XXX nested node trees are not included in tag-clearing above,
- * so we need to do this manually.
- */
- FOREACH_NODETREE(bmain_, nodetree, id)
- {
- if (id != (ID *)nodetree) {
- nodetree->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- FOREACH_NODETREE_END;
-
if (DEG_depsgraph_use_copy_on_write()) {
/* Store existing copy-on-write versions of datablock, so we can re-use
* them for new ID nodes.
@@ -424,11 +423,9 @@ void DepsgraphNodeBuilder::end_build()
void DepsgraphNodeBuilder::build_group(Group *group)
{
- ID *group_id = &group->id;
- if (group_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(group)) {
return;
}
- group_id->tag |= LIB_TAG_DOIT;
/* Build group objects. */
LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY);
@@ -439,9 +436,9 @@ void DepsgraphNodeBuilder::build_group(Group *group)
* 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);
+ add_id_node(&group->id);
Group *group_cow = get_cow_datablock(group);
- add_operation_node(group_id,
+ add_operation_node(&group->id,
DEG_NODE_TYPE_LAYER_COLLECTIONS,
function_bind(BKE_group_eval_view_layers,
_1,
@@ -453,8 +450,9 @@ void DepsgraphNodeBuilder::build_object(Base *base,
Object *object,
eDepsNode_LinkedState_Type linked_state)
{
+ const bool has_object = built_map_.checkIsBuiltAndTag(object);
/* Skip rest of components if the ID node was already there. */
- if (object->id.tag & LIB_TAG_DOIT) {
+ if (has_object) {
IDDepsNode *id_node = find_id_node(&object->id);
/* We need to build some extra stuff if object becomes linked
* directly.
@@ -465,7 +463,6 @@ void DepsgraphNodeBuilder::build_object(Base *base,
id_node->linked_state = max(id_node->linked_state, linked_state);
return;
}
- object->id.tag |= LIB_TAG_DOIT;
/* Create ID node for object and begin init. */
IDDepsNode *id_node = add_id_node(&object->id);
id_node->linked_state = linked_state;
@@ -581,7 +578,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
default:
{
ID *obdata = (ID *)object->data;
- if ((obdata->tag & LIB_TAG_DOIT) == 0) {
+ if (built_map_.checkIsBuilt(obdata) == 0) {
build_animdata(obdata);
}
break;
@@ -712,50 +709,69 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
* \param id: ID-Block that driver is attached to
* \param fcu: Driver-FCurve
*/
-OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
+void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve)
{
ID *id_cow = get_cow_id(id);
/* Create data node for this driver */
- /* TODO(sergey): Avoid creating same operation multiple times,
- * in the future we need to avoid lookup of the operation as well
- * and use some tagging magic instead.
- */
- OperationDepsNode *driver_op = find_operation_node(
- id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_DRIVER,
- fcu->rna_path ? fcu->rna_path : "",
- fcu->array_index);
-
- if (driver_op == NULL) {
- /* TODO(sergey): Shall we use COW of fcu itself here? */
- driver_op = add_operation_node(id,
- DEG_NODE_TYPE_PARAMETERS,
- function_bind(BKE_animsys_eval_driver,
- _1,
- id_cow,
- fcu),
- DEG_OPCODE_DRIVER,
- fcu->rna_path ? fcu->rna_path : "",
- fcu->array_index);
+ /* TODO(sergey): Shall we use COW of fcu itself here? */
+ ensure_operation_node(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ function_bind(BKE_animsys_eval_driver, _1, id_cow, fcurve),
+ DEG_OPCODE_DRIVER,
+ fcurve->rna_path ? fcurve->rna_path : "",
+ fcurve->array_index);
+ build_driver_variables(id, fcurve);
+}
+
+void DepsgraphNodeBuilder::build_driver_variables(ID * id, FCurve *fcurve)
+{
+ build_driver_id_property(id, fcurve->rna_path);
+ LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) {
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ build_driver_id_property(dtar->id, dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END
}
+}
- /* return driver node created */
- return driver_op;
+void DepsgraphNodeBuilder::build_driver_id_property(ID *id,
+ const char *rna_path)
+{
+ if (id == NULL || rna_path == NULL) {
+ return;
+ }
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ RNA_id_pointer_create(id, &id_ptr);
+ if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) {
+ return;
+ }
+ if (prop == NULL) {
+ return;
+ }
+ if (!RNA_property_is_idprop(prop)) {
+ return;
+ }
+ const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
+ ensure_operation_node(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_ID_PROPERTY,
+ prop_identifier);
}
/* Recursively build graph for world */
void DepsgraphNodeBuilder::build_world(World *world)
{
- ID *world_id = &world->id;
- if (world_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
/* Animation. */
- build_animdata(world_id);
+ build_animdata(&world->id);
/* world itself */
- add_operation_node(world_id,
+ add_operation_node(&world->id,
DEG_NODE_TYPE_SHADING,
function_bind(BKE_world_eval,
_1,
@@ -916,19 +932,17 @@ void DepsgraphNodeBuilder::build_particles(Object *object)
}
void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *part) {
- ID *part_id = &part->id;
- if (part_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(part)) {
return;
}
- part_id->tag |= LIB_TAG_DOIT;
/* Animation data. */
- build_animdata(part_id);
+ build_animdata(&part->id);
/* Parameters change. */
- add_operation_node(part_id,
+ add_operation_node(&part->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PARTICLE_SETTINGS_EVAL);
- add_operation_node(part_id,
+ add_operation_node(&part->id,
DEG_NODE_TYPE_PARAMETERS,
function_bind(BKE_particle_system_settings_recalc_clear,
_1,
@@ -1035,10 +1049,9 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
}
ID *obdata = (ID *)object->data;
- if (obdata->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
- obdata->tag |= LIB_TAG_DOIT;
/* Make sure we've got an ID node before requesting CoW pointer. */
(void) add_id_node((ID *)obdata);
ID *obdata_cow = get_cow_id(obdata);
@@ -1172,18 +1185,14 @@ void DepsgraphNodeBuilder::build_camera(Object *object)
NULL,
DEG_OPCODE_PARAMETERS_EVAL,
"Camera Parameters");
-
/* Object data. */
- /* TODO: Link scene-camera links in somehow. */
- Camera *cam = (Camera *)object->data;
- ID *camera_id = &cam->id;
- if (camera_id->tag & LIB_TAG_DOIT) {
+ /* TODO: Link scene-camera links in somehow... */
+ Camera *camera = (Camera *)object->data;
+ if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
-
- build_animdata(&cam->id);
-
- add_operation_node(camera_id,
+ build_animdata(&camera->id);
+ add_operation_node(&camera->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PARAMETERS_EVAL);
@@ -1198,28 +1207,20 @@ void DepsgraphNodeBuilder::build_lamp(Object *object)
NULL,
DEG_OPCODE_PARAMETERS_EVAL,
"Lamp Parameters");
-
/* Object data. */
- Lamp *la = (Lamp *)object->data;
- ID *lamp_id = &la->id;
- if (lamp_id->tag & LIB_TAG_DOIT) {
+ Lamp *lamp = (Lamp *)object->data;
+ if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
-
- build_animdata(&la->id);
-
- add_operation_node(lamp_id,
+ build_animdata(&lamp->id);
+ add_operation_node(&lamp->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PARAMETERS_EVAL);
-
/* lamp's nodetree */
- if (la->nodetree) {
- build_nodetree(la->nodetree);
- }
-
+ build_nodetree(lamp->nodetree);
/* textures */
- build_texture_stack(la->mtex);
+ build_texture_stack(lamp->mtex);
}
void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
@@ -1227,21 +1228,23 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
if (ntree == NULL) {
return;
}
+ if (built_map_.checkIsBuiltAndTag(ntree)) {
+ return;
+ }
/* nodetree itself */
- ID *ntree_id = &ntree->id;
- add_id_node(ntree_id);
+ add_id_node(&ntree->id);
bNodeTree *ntree_cow = get_cow_datablock(ntree);
/* Animation, */
- build_animdata(ntree_id);
+ build_animdata(&ntree->id);
/* Shading update. */
- add_operation_node(ntree_id,
+ add_operation_node(&ntree->id,
DEG_NODE_TYPE_SHADING,
NULL,
DEG_OPCODE_MATERIAL_UPDATE);
/* NOTE: We really pass original and CoW node trees here, this is how the
* callback works. Ideally we need to find a better way for that.
*/
- add_operation_node(ntree_id,
+ add_operation_node(&ntree->id,
DEG_NODE_TYPE_SHADING_PARAMETERS,
function_bind(BKE_nodetree_shading_params_eval,
_1,
@@ -1277,9 +1280,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
}
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
- if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(group_ntree);
- }
+ build_nodetree(group_ntree);
}
else {
BLI_assert(!"Unknown ID type used for node");
@@ -1292,23 +1293,21 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
/* Recursively build graph for material */
void DepsgraphNodeBuilder::build_material(Material *material)
{
- ID *material_id = &material->id;
- if (material_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
- material_id->tag |= LIB_TAG_DOIT;
/* Material itself. */
- add_id_node(material_id);
+ add_id_node(&material->id);
Material *material_cow = get_cow_datablock(material);
/* Shading update. */
- add_operation_node(material_id,
+ add_operation_node(&material->id,
DEG_NODE_TYPE_SHADING,
function_bind(BKE_material_eval,
_1,
material_cow),
DEG_OPCODE_MATERIAL_UPDATE);
/* Material animation. */
- build_animdata(material_id);
+ build_animdata(&material->id);
/* Textures. */
build_texture_stack(material->mtex);
/* Material's nodetree. */
@@ -1328,33 +1327,29 @@ void DepsgraphNodeBuilder::build_texture_stack(MTex **texture_stack)
}
/* Recursively build graph for texture */
-void DepsgraphNodeBuilder::build_texture(Tex *tex)
+void DepsgraphNodeBuilder::build_texture(Tex *texture)
{
- ID *tex_id = &tex->id;
- if (tex_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(texture)) {
return;
}
- tex_id->tag |= LIB_TAG_DOIT;
/* Texture itself. */
- build_animdata(tex_id);
+ build_animdata(&texture->id);
/* Texture's nodetree. */
- build_nodetree(tex->nodetree);
+ build_nodetree(texture->nodetree);
/* Special cases for different IDs which texture uses. */
- if (tex->type == TEX_IMAGE) {
- if (tex->ima != NULL) {
- build_image(tex->ima);
+ if (texture->type == TEX_IMAGE) {
+ if (texture->ima != NULL) {
+ build_image(texture->ima);
}
}
}
void DepsgraphNodeBuilder::build_image(Image *image) {
- ID *image_id = &image->id;
- if (image_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(image)) {
return;
}
- image_id->tag |= LIB_TAG_DOIT;
/* Placeholder so we can add relations and tag ID node for update. */
- add_operation_node(image_id,
+ add_operation_node(&image->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PLACEHOLDER,
@@ -1433,13 +1428,11 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
void DepsgraphNodeBuilder::build_lightprobe(Object *object)
{
LightProbe *probe = (LightProbe *)object->data;
- ID *probe_id = &probe->id;
- if (probe_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
- probe_id->tag |= LIB_TAG_DOIT;
/* Placeholder so we can add relations and tag ID node for update. */
- add_operation_node(probe_id,
+ add_operation_node(&probe->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PLACEHOLDER,
@@ -1450,7 +1443,7 @@ void DepsgraphNodeBuilder::build_lightprobe(Object *object)
DEG_OPCODE_PLACEHOLDER,
"LightProbe Eval");
- build_animdata(probe_id);
+ build_animdata(&probe->id);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index cc8ad08ea3b..49cccb60843 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -30,6 +30,7 @@
#pragma once
+#include "intern/builder/deg_builder_map.h"
#include "intern/depsgraph_types.h"
#include "DEG_depsgraph.h" /* used for DEG_depsgraph_use_copy_on_write() */
@@ -112,7 +113,7 @@ struct DepsgraphNodeBuilder {
void begin_build();
void end_build();
- IDDepsNode *add_id_node(ID *id, bool do_tag = true);
+ IDDepsNode *add_id_node(ID *id);
IDDepsNode *find_id_node(ID *id);
TimeSourceDepsNode *add_time_source();
@@ -139,6 +140,13 @@ struct DepsgraphNodeBuilder {
const char *name = "",
int name_tag = -1);
+ OperationDepsNode *ensure_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const DepsEvalOperationCb& op,
+ eDepsOperation_Code opcode,
+ const char *name = "",
+ int name_tag = -1);
+
bool has_operation_node(ID *id,
eDepsNode_Type comp_type,
const char *comp_name,
@@ -178,7 +186,9 @@ struct DepsgraphNodeBuilder {
void build_particle_settings(ParticleSettings *part);
void build_cloth(Object *object);
void build_animdata(ID *id);
- OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_driver(ID *id, FCurve *fcurve);
+ void build_driver_variables(ID *id, FCurve *fcurve);
+ void build_driver_id_property(ID *id, const char *rna_path);
void build_ik_pose(Object *object,
bPoseChannel *pchan,
bConstraint *con);
@@ -231,6 +241,7 @@ protected:
Scene *scene_;
GHash *cow_id_hash_;
+ BuilderMap built_map_;
};
} // namespace DEG
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 c3116db6146..aabcbd1c6d4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -135,7 +135,6 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
void DepsgraphNodeBuilder::build_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
- const short armature_tag = armature->id.tag;
Scene *scene_cow;
Object *object_cow;
bArmature *armature_cow;
@@ -163,9 +162,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
* mechanism in-between here to ensure that we can use same rig
* multiple times in same scene.
*/
- if ((armature_tag & LIB_TAG_DOIT) == 0) {
+ if (!built_map_.checkIsBuilt(armature)) {
build_animdata(&armature->id);
-
/* Make sure pose is up-to-date with armature updates. */
add_operation_node(&armature->id,
DEG_NODE_TYPE_PARAMETERS,
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 7a0fc790780..859ad36d06d 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
@@ -86,13 +86,13 @@ void DepsgraphNodeBuilder::build_view_layer(
*/
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *object = base->object;
- add_id_node(&object->id, false);
+ add_id_node(&object->id);
}
/* Create ID node for nested ID of nodetree as well, otherwise remapping
* will not work correct either.
*/
if (scene->nodetree != NULL) {
- add_id_node(&scene->nodetree->id, false);
+ add_id_node(&scene->nodetree->id);
}
/* Make sure we've got ID node, so we can get pointer to CoW datablock.
*/
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index cff6c926278..ddb0f809a53 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -283,7 +283,7 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
graph_->add_new_relation(timesrc, node_to, description, check_unique);
}
else {
- DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
+ DEG_DEBUG_PRINTF(BUILD, "add_time_relation(%p = %s, %p = %s, %s) Failed\n",
timesrc, (timesrc) ? timesrc->identifier().c_str() : "<None>",
node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
description);
@@ -300,7 +300,7 @@ void DepsgraphRelationBuilder::add_operation_relation(
graph_->add_new_relation(node_from, node_to, description, check_unique);
}
else {
- DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
+ DEG_DEBUG_PRINTF(BUILD, "add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
node_from, (node_from) ? node_from->identifier().c_str() : "<None>",
node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
description);
@@ -403,26 +403,11 @@ Depsgraph *DepsgraphRelationBuilder::getGraph()
void DepsgraphRelationBuilder::begin_build()
{
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * created or not.
- */
- BKE_main_id_tag_all(bmain_, LIB_TAG_DOIT, false);
- /* XXX nested node trees are notr included in tag-clearing above,
- * so we need to do this manually.
- */
- FOREACH_NODETREE(bmain_, nodetree, id)
- {
- if (id != (ID *)nodetree) {
- nodetree->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- FOREACH_NODETREE_END
}
void DepsgraphRelationBuilder::build_group(Object *object, Group *group)
{
- ID *group_id = &group->id;
- bool group_done = (group_id->tag & LIB_TAG_DOIT) != 0;
+ const bool group_done = built_map_.checkIsBuiltAndTag(group);
OperationKey object_local_transform_key(object != NULL ? &object->id : NULL,
DEG_NODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_LOCAL);
@@ -430,7 +415,6 @@ void DepsgraphRelationBuilder::build_group(Object *object, Group *group)
LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
build_object(NULL, base->object);
}
- group_id->tag |= LIB_TAG_DOIT;
}
if (object != NULL) {
LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
@@ -442,13 +426,12 @@ void DepsgraphRelationBuilder::build_group(Object *object, Group *group)
void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
{
- if (object->id.tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(object)) {
if (base != NULL) {
build_object_flags(base, object);
}
return;
}
- object->id.tag |= LIB_TAG_DOIT;
/* Object Transforms */
eDepsOperation_Code base_op = (object->parent) ? DEG_OPCODE_TRANSFORM_PARENT
: DEG_OPCODE_TRANSFORM_LOCAL;
@@ -1195,6 +1178,26 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
}
}
}
+ if (RNA_pointer_is_null(&target_key.ptr)) {
+ /* TODO(sergey): This would only mean that driver is broken.
+ * so we can't create relation anyway. However, we need to avoid
+ * adding drivers which are known to be buggy to a dependency
+ * graph, in order to save computational power.
+ */
+ }
+ else {
+ if (target_key.prop != NULL &&
+ RNA_property_is_idprop(target_key.prop))
+ {
+ OperationKey parameters_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PARAMETERS_EVAL);
+ add_relation(target_key,
+ parameters_key,
+ "Driver Target -> Properties");
+ }
+ add_relation(driver_key, target_key, "Driver -> Target");
+ }
}
}
@@ -1284,24 +1287,18 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
void DepsgraphRelationBuilder::build_world(World *world)
{
- ID *world_id = &world->id;
- if (world_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
- world_id->tag |= LIB_TAG_DOIT;
-
- build_animdata(world_id);
-
+ build_animdata(&world->id);
/* TODO: other settings? */
-
/* textures */
build_texture_stack(world->mtex);
-
/* world's nodetree */
if (world->nodetree != NULL) {
build_nodetree(world->nodetree);
ComponentKey ntree_key(&world->nodetree->id, DEG_NODE_TYPE_SHADING);
- ComponentKey world_key(world_id, DEG_NODE_TYPE_SHADING);
+ ComponentKey world_key(&world->id, DEG_NODE_TYPE_SHADING);
add_relation(ntree_key, world_key, "NTree->World Shading Update");
}
}
@@ -1541,19 +1538,16 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
{
- ID *part_id = &part->id;
- if (part_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(part)) {
return;
}
- part_id->tag |= LIB_TAG_DOIT;
-
/* Animation data relations. */
build_animdata(&part->id);
- OperationKey eval_key(part_id,
+ OperationKey eval_key(&part->id,
DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PARTICLE_SETTINGS_EVAL);
- OperationKey recalc_clear_key(part_id,
+ OperationKey recalc_clear_key(&part->id,
DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PARTICLE_SETTINGS_RECALC_CLEAR);
add_relation(eval_key, recalc_clear_key, "Particle Settings Clear Recalc");
@@ -1668,16 +1662,16 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
/* Modifiers */
if (object->modifiers.first != NULL) {
+ ModifierUpdateDepsgraphContext ctx = {};
+ ctx.scene = scene_;
+ ctx.object = object;
+
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);
- mti->updateDepsgraph(
- md,
- bmain_,
- scene_,
- object,
- reinterpret_cast< ::DepsNodeHandle* >(&handle));
+ ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle);
+ mti->updateDepsgraph(md, &ctx);
}
if (BKE_object_modifier_use_time(object, md)) {
TimeSourceKey time_src_key;
@@ -1722,10 +1716,9 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval");
}
- if (obdata->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
- obdata->tag |= LIB_TAG_DOIT;
/* Link object data evaluation node to exit operation. */
OperationKey obdata_geom_eval_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
@@ -1821,22 +1814,20 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
// TODO: Link scene-camera links in somehow...
void DepsgraphRelationBuilder::build_camera(Object *object)
{
- Camera *cam = (Camera *)object->data;
- ID *camera_id = &cam->id;
- if (camera_id->tag & LIB_TAG_DOIT) {
+ Camera *camera = (Camera *)object->data;
+ if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
- camera_id->tag |= LIB_TAG_DOIT;
ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
- ComponentKey camera_parameters_key(camera_id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS);
add_relation(camera_parameters_key, object_parameters_key,
"Camera -> Object");
/* DOF */
- if (cam->dof_ob != NULL) {
- ComponentKey dof_ob_key(&cam->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
+ if (camera->dof_ob != NULL) {
+ ComponentKey dof_ob_key(&camera->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(dof_ob_key, object_parameters_key, "Camera DOF");
}
}
@@ -1844,27 +1835,25 @@ void DepsgraphRelationBuilder::build_camera(Object *object)
/* Lamps */
void DepsgraphRelationBuilder::build_lamp(Object *object)
{
- Lamp *la = (Lamp *)object->data;
- ID *lamp_id = &la->id;
- if (lamp_id->tag & LIB_TAG_DOIT) {
+ Lamp *lamp = (Lamp *)object->data;
+ if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
- lamp_id->tag |= LIB_TAG_DOIT;
ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
- ComponentKey lamp_parameters_key(lamp_id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
add_relation(lamp_parameters_key, object_parameters_key,
"Lamp -> Object");
/* lamp's nodetree */
- if (la->nodetree != NULL) {
- build_nodetree(la->nodetree);
- ComponentKey nodetree_key(&la->nodetree->id, DEG_NODE_TYPE_SHADING);
+ if (lamp->nodetree != NULL) {
+ build_nodetree(lamp->nodetree);
+ ComponentKey nodetree_key(&lamp->nodetree->id, DEG_NODE_TYPE_SHADING);
add_relation(nodetree_key, lamp_parameters_key, "NTree->Lamp Parameters");
}
/* textures */
- build_texture_stack(la->mtex);
+ build_texture_stack(lamp->mtex);
if (DEG_depsgraph_use_copy_on_write()) {
/* Make sure copy on write of lamp data is always properly updated for
@@ -1873,7 +1862,7 @@ void DepsgraphRelationBuilder::build_lamp(Object *object)
OperationKey ob_copy_on_write_key(&object->id,
DEG_NODE_TYPE_COPY_ON_WRITE,
DEG_OPCODE_COPY_ON_WRITE);
- OperationKey lamp_copy_on_write_key(lamp_id,
+ OperationKey lamp_copy_on_write_key(&lamp->id,
DEG_NODE_TYPE_COPY_ON_WRITE,
DEG_OPCODE_COPY_ON_WRITE);
add_relation(lamp_copy_on_write_key, ob_copy_on_write_key, "Eval Order");
@@ -1885,9 +1874,11 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (ntree == NULL) {
return;
}
- ID *ntree_id = &ntree->id;
- build_animdata(ntree_id);
- ComponentKey shading_key(ntree_id, DEG_NODE_TYPE_SHADING);
+ if (built_map_.checkIsBuiltAndTag(ntree)) {
+ return;
+ }
+ build_animdata(&ntree->id);
+ ComponentKey shading_key(&ntree->id, DEG_NODE_TYPE_SHADING);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
@@ -1917,10 +1908,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
- if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(group_ntree);
- group_ntree->id.tag |= LIB_TAG_DOIT;
- }
+ build_nodetree(group_ntree);
ComponentKey group_shading_key(&group_ntree->id,
DEG_NODE_TYPE_SHADING);
add_relation(group_shading_key, shading_key, "Group Node");
@@ -1930,37 +1918,32 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
}
- OperationKey shading_update_key(ntree_id,
+ OperationKey shading_update_key(&ntree->id,
DEG_NODE_TYPE_SHADING,
DEG_OPCODE_MATERIAL_UPDATE);
- OperationKey shading_parameters_key(ntree_id,
+ OperationKey shading_parameters_key(&ntree->id,
DEG_NODE_TYPE_SHADING_PARAMETERS,
DEG_OPCODE_MATERIAL_UPDATE);
add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
-void DepsgraphRelationBuilder::build_material(Material *ma)
+void DepsgraphRelationBuilder::build_material(Material *material)
{
- ID *ma_id = &ma->id;
- if (ma_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
- ma_id->tag |= LIB_TAG_DOIT;
-
/* animation */
- build_animdata(ma_id);
-
+ build_animdata(&material->id);
/* textures */
- build_texture_stack(ma->mtex);
-
+ build_texture_stack(material->mtex);
/* material's nodetree */
- if (ma->nodetree != NULL) {
- build_nodetree(ma->nodetree);
- OperationKey ntree_key(&ma->nodetree->id,
+ if (material->nodetree != NULL) {
+ build_nodetree(material->nodetree);
+ OperationKey ntree_key(&material->nodetree->id,
DEG_NODE_TYPE_SHADING,
DEG_OPCODE_MATERIAL_UPDATE);
- OperationKey material_key(&ma->id,
+ OperationKey material_key(&material->id,
DEG_NODE_TYPE_SHADING,
DEG_OPCODE_MATERIAL_UPDATE);
add_relation(ntree_key, material_key, "Material's NTree");
@@ -1968,28 +1951,22 @@ void DepsgraphRelationBuilder::build_material(Material *ma)
}
/* Recursively build graph for texture */
-void DepsgraphRelationBuilder::build_texture(Tex *tex)
+void DepsgraphRelationBuilder::build_texture(Tex *texture)
{
- ID *tex_id = &tex->id;
- if (tex_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(texture)) {
return;
}
- tex_id->tag |= LIB_TAG_DOIT;
-
/* texture itself */
- build_animdata(tex_id);
-
+ build_animdata(&texture->id);
/* texture's nodetree */
- build_nodetree(tex->nodetree);
+ build_nodetree(texture->nodetree);
}
/* Texture-stack attached to some shading datablock */
void DepsgraphRelationBuilder::build_texture_stack(MTex **texture_stack)
{
- int i;
-
/* for now assume that all texture-stacks have same number of max items */
- for (i = 0; i < MAX_MTEX; i++) {
+ for (int i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
build_texture(mtex->tex);
@@ -2041,14 +2018,12 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
void DepsgraphRelationBuilder::build_lightprobe(Object *object)
{
LightProbe *probe = (LightProbe *)object->data;
- ID *probe_id = &probe->id;
- if (probe_id->tag & LIB_TAG_DOIT) {
+ if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
- probe_id->tag |= LIB_TAG_DOIT;
build_animdata(&probe->id);
- OperationKey probe_key(probe_id,
+ OperationKey probe_key(&probe->id,
DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PLACEHOLDER,
"LightProbe Eval");
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index ea7e23eca79..1720f19eb22 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -43,6 +43,7 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "intern/builder/deg_builder_map.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -339,6 +340,8 @@ private:
/* State which demotes currently built entities. */
Scene *scene_;
+
+ BuilderMap built_map_;
};
struct DepsNodeHandle
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 f3c3772e512..c8fbc5e2e9a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -175,15 +175,12 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
}
}
- DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
+ DEG_DEBUG_PRINTF(BUILD, "\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
bPoseChannel *parchan = pchan;
/* exclude tip from chain? */
if (!(data->flag & CONSTRAINT_IK_TIP)) {
- OperationKey tip_transforms_key(&object->id, DEG_NODE_TYPE_BONE,
- parchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(solver_key, tip_transforms_key, "IK Solver Result");
parchan = pchan->parent;
}
@@ -221,7 +218,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
root_map->add_bone(parchan->name, rootchan->name);
/* continue up chain, until we reach target number of items... */
- DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name);
+ DEG_DEBUG_PRINTF(BUILD, " %d = %s\n", segcount, parchan->name);
segcount++;
if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 7731b76c6b9..12760cad73c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -117,7 +117,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
}
}
}
- DEG_DEBUG_PRINTF("Removed %d relations\n", num_removed_relations);
+ DEG_DEBUG_PRINTF(BUILD, "Removed %d relations\n", num_removed_relations);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 3b5ea2bfc3f..a2e6993e442 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -35,6 +35,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_console.h"
+#include "BLI_hash.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
@@ -140,7 +142,7 @@ static bool pointer_to_component_node_criteria(
*type = DEG_NODE_TYPE_PARAMETERS;
*subdata = "";
*operation_code = DEG_OPCODE_PARAMETERS_EVAL;
- *operation_name = pchan->name;;
+ *operation_name = pchan->name;
}
else {
/* Bone - generally, we just want the bone component. */
@@ -161,16 +163,20 @@ static bool pointer_to_component_node_criteria(
Object *object = (Object *)ptr->id.data;
bConstraint *con = (bConstraint *)ptr->data;
/* Check whether is object or bone constraint. */
+ /* NOTE: Currently none of the area can address transform of an object
+ * at a given constraint, but for rigging one might use constraint
+ * influence to be used to drive some corrective shape keys or so.
+ */
if (BLI_findindex(&object->constraints, con) != -1) {
- /* Constraint is defining object transform. */
*type = DEG_NODE_TYPE_TRANSFORM;
+ *operation_code = DEG_OPCODE_TRANSFORM_LOCAL;
return true;
}
else if (object->pose != NULL) {
LISTBASE_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) {
if (BLI_findindex(&pchan->constraints, con) != -1) {
- /* bone transforms */
*type = DEG_NODE_TYPE_BONE;
+ *operation_code = DEG_OPCODE_BONE_LOCAL;
*subdata = pchan->name;
return true;
}
@@ -226,10 +232,18 @@ static bool pointer_to_component_node_criteria(
}
if (prop != NULL) {
/* All unknown data effectively falls under "parameter evaluation". */
- *type = DEG_NODE_TYPE_PARAMETERS;
- *operation_code = DEG_OPCODE_PARAMETERS_EVAL;
- *operation_name = "";
- *operation_name_tag = -1;
+ if (RNA_property_is_idprop(prop)) {
+ *type = DEG_NODE_TYPE_PARAMETERS;
+ *operation_code = DEG_OPCODE_ID_PROPERTY;
+ *operation_name = RNA_property_identifier((PropertyRNA *)prop);
+ *operation_name_tag = -1;
+ }
+ else {
+ *type = DEG_NODE_TYPE_PARAMETERS;
+ *operation_code = DEG_OPCODE_PARAMETERS_EVAL;
+ *operation_name = "";
+ *operation_name_tag = -1;
+ }
return true;
}
return false;
@@ -290,7 +304,7 @@ IDDepsNode *Depsgraph::find_id_node(const ID *id) const
return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
}
-IDDepsNode *Depsgraph::add_id_node(ID *id, bool do_tag, ID *id_cow_hint)
+IDDepsNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
{
BLI_assert((id->tag & LIB_TAG_COPY_ON_WRITE) == 0);
IDDepsNode *id_node = find_id_node(id);
@@ -298,9 +312,6 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, bool do_tag, ID *id_cow_hint)
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) {
- id->tag |= LIB_TAG_DOIT;
- }
/* Register node in ID hash.
*
* NOTE: We address ID nodes by the original ID pointer they are
@@ -309,9 +320,6 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, bool do_tag, ID *id_cow_hint)
BLI_ghash_insert(id_hash, id, id_node);
id_nodes.push_back(id_node);
}
- else if (do_tag) {
- id->tag |= LIB_TAG_DOIT;
- }
return id_node;
}
@@ -520,6 +528,31 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
}
}
+bool deg_terminal_do_color(void)
+{
+ return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0;
+}
+
+string deg_color_for_pointer(const void *pointer)
+{
+ if (!deg_terminal_do_color()) {
+ return "";
+ }
+ int r, g, b;
+ BLI_hash_pointer_to_color(pointer, &r, &g, &b);
+ char buffer[64];
+ BLI_snprintf(buffer, sizeof(buffer), TRUECOLOR_ANSI_COLOR_FORMAT, r, g, b);
+ return string(buffer);
+}
+
+string deg_color_end(void)
+{
+ if (!deg_terminal_do_color()) {
+ return "";
+ }
+ return string(TRUECOLOR_ANSI_COLOR_FINISH);
+}
+
} // namespace DEG
/* **************** */
@@ -547,3 +580,85 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG::deg_editor_update_id_cb = id_func;
DEG::deg_editor_update_scene_cb = scene_func;
}
+
+/* Evaluation and debug */
+
+void DEG_debug_print_eval(const char *function_name,
+ const char *object_name,
+ const void *object_address)
+{
+ if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ return;
+ }
+ printf("%s on %s %s(%p)%s\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str());
+}
+
+void DEG_debug_print_eval_subdata(const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ const char *subdata_comment,
+ const char *subdata_name,
+ const void *subdata_address)
+{
+ if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ return;
+ }
+ printf("%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ subdata_comment,
+ subdata_name,
+ DEG::deg_color_for_pointer(subdata_address).c_str(),
+ subdata_address,
+ DEG::deg_color_end().c_str());
+}
+
+void DEG_debug_print_eval_subdata_index(const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ const char *subdata_comment,
+ const char *subdata_name,
+ const void *subdata_address,
+ const int subdata_index)
+{
+ if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ return;
+ }
+ printf("%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ subdata_comment,
+ subdata_name,
+ subdata_index,
+ DEG::deg_color_for_pointer(subdata_address).c_str(),
+ subdata_address,
+ DEG::deg_color_end().c_str());
+}
+
+void DEG_debug_print_eval_time(const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ float time)
+{
+ if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ return;
+ }
+ printf("%s on %s %s(%p)%s at time %f\n",
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ time);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index f18b93c9807..985991e91e3 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -119,7 +119,7 @@ struct Depsgraph {
TimeSourceDepsNode *find_time_source() const;
IDDepsNode *find_id_node(const ID *id) const;
- IDDepsNode *add_id_node(ID *id, bool do_tag = true, ID *id_cow_hint = NULL);
+ IDDepsNode *add_id_node(ID *id, ID *id_cow_hint = NULL);
void clear_id_nodes();
/* Add new relationship between two nodes. */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 377f2d3b4c5..c7f53b51374 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -32,16 +32,12 @@
#include "MEM_guardedalloc.h"
-// #define DEBUG_TIME
-
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
-#ifdef DEBUG_TIME
-# include "PIL_time.h"
-# include "PIL_time_utildefines.h"
-#endif
+#include "PIL_time.h"
+#include "PIL_time_utildefines.h"
extern "C" {
#include "DNA_cachefile_types.h"
@@ -202,9 +198,10 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph,
Scene *scene,
ViewLayer *view_layer)
{
-#ifdef DEBUG_TIME
- TIMEIT_START(DEG_graph_build_from_view_layer);
-#endif
+ double start_time;
+ if (G.debug & G_DEBUG_DEPSGRAPH_BUILD) {
+ start_time = PIL_check_seconds_timer();
+ }
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
@@ -257,16 +254,17 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph,
}
#endif
-#ifdef DEBUG_TIME
- TIMEIT_END(DEG_graph_build_from_view_layer);
-#endif
-
/* Relations are up to date. */
deg_graph->need_update = false;
if (need_on_visible_update) {
DEG_graph_on_visible_update(bmain, graph);
}
+
+ if (G.debug & G_DEBUG_DEPSGRAPH_BUILD) {
+ printf("Depsgraph built in %f seconds.\n",
+ PIL_check_seconds_timer() - start_time);
+ }
}
/* Tag graph relations for update. */
@@ -293,7 +291,7 @@ void DEG_graph_relations_update(Depsgraph *graph,
/* Tag all relations for update. */
void DEG_relations_tag_update(Main *bmain)
{
- DEG_DEBUG_PRINTF("%s: Tagging relations for update.\n", __func__);
+ DEG_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Depsgraph *depsgraph =
@@ -341,45 +339,40 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle,
const char *name)
{
ListBase *effectors = pdInitEffectors(NULL, scene, object, NULL, effector_weights, false);
-
- if (effectors) {
- for (EffectorCache *eff = (EffectorCache*)effectors->first; eff; eff = eff->next) {
- if (eff->ob != object && eff->pd->forcefield != skip_forcefield) {
- DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_TRANSFORM, name);
-
- if (eff->psys) {
- DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
-
- /* TODO: remove this when/if EVAL_PARTICLES is sufficient
- * for up to date particles.
- */
- DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name);
- }
-
- if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- DEG_add_object_relation(handle,
- eff->pd->f_source,
- DEG_OB_COMP_TRANSFORM,
- "Smoke Force Domain");
- DEG_add_object_relation(handle,
- eff->pd->f_source,
- DEG_OB_COMP_GEOMETRY,
- "Smoke Force Domain");
- }
-
- if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- DEG_add_collision_relations(handle,
- scene,
- object,
- NULL,
- eModifierType_Collision,
- NULL,
- true,
- "Force Absorption");
- }
+ if (effectors == NULL) {
+ return;
+ }
+ for (EffectorCache *eff = (EffectorCache*)effectors->first; eff; eff = eff->next) {
+ if (eff->ob != object && eff->pd->forcefield != skip_forcefield) {
+ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_TRANSFORM, name);
+ if (eff->psys) {
+ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient
+ * for up to date particles.
+ */
+ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name);
+ }
+ if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
+ DEG_add_object_relation(handle,
+ eff->pd->f_source,
+ DEG_OB_COMP_TRANSFORM,
+ "Smoke Force Domain");
+ DEG_add_object_relation(handle,
+ eff->pd->f_source,
+ DEG_OB_COMP_GEOMETRY,
+ "Smoke Force Domain");
+ }
+ if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
+ DEG_add_collision_relations(handle,
+ scene,
+ object,
+ NULL,
+ eModifierType_Collision,
+ NULL,
+ true,
+ "Force Absorption");
}
}
}
-
pdEndEffectors(&effectors);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 4fb5a8ff580..d76eba29628 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,16 +32,19 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
extern "C" {
#include "BKE_scene.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "intern/eval/deg_eval.h"
#include "intern/eval/deg_eval_flush.h"
@@ -92,6 +95,38 @@ void DEG_evaluation_context_init_from_scene(
eval_ctx->object_mode = object_mode;
}
+void DEG_evaluation_context_init_from_view_layer_for_render(
+ EvaluationContext *eval_ctx,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ ViewLayer *view_layer)
+{
+ /* ViewLayer may come from a copy of scene.viewlayers, we need to find the original though. */
+ ViewLayer *view_layer_original = (ViewLayer *)BLI_findstring(&scene->view_layers, view_layer->name, offsetof(ViewLayer, name));
+ BLI_assert(view_layer_original != NULL);
+
+ DEG_evaluation_context_init(eval_ctx, DAG_EVAL_RENDER);
+ eval_ctx->ctime = BKE_scene_frame_get(scene);
+ eval_ctx->object_mode = OB_MODE_OBJECT;
+ eval_ctx->depsgraph = depsgraph;
+ eval_ctx->view_layer = view_layer_original;
+ eval_ctx->engine_type = NULL;
+}
+
+void DEG_evaluation_context_init_from_depsgraph(
+ EvaluationContext *eval_ctx,
+ Depsgraph *depsgraph,
+ eEvaluationMode mode)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ DEG_evaluation_context_init(eval_ctx, mode);
+ eval_ctx->ctime = (float)scene->r.cfra + scene->r.subframe;
+ eval_ctx->object_mode = OB_MODE_OBJECT;
+ eval_ctx->depsgraph = depsgraph;
+ eval_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ eval_ctx->engine_type = NULL;
+}
+
/* Free evaluation context. */
void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
{
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index df5e51a3910..9961723ed17 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -112,12 +112,11 @@ void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx,
void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
bool updated);
-#define DEG_DEBUG_PRINTF(...) \
- do { \
- if (G.debug & G_DEBUG_DEPSGRAPH) { \
- fprintf(stderr, __VA_ARGS__); \
- fflush(stderr); \
- } \
+#define DEG_DEBUG_PRINTF(type, ...) \
+ do { \
+ if (G.debug & G_DEBUG_DEPSGRAPH_ ## type) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
} while (0)
#define DEG_ERROR_PRINTF(...) \
@@ -126,4 +125,8 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
fflush(stderr); \
} while (0)
+bool deg_terminal_do_color(void);
+string deg_color_for_pointer(const void *pointer);
+string deg_color_end(void);
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index b0b3cbe0f8c..ea53b18f55b 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -508,7 +508,9 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag)
/* Ideally should not happen, but old depsgraph allowed this. */
return;
}
- DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
+ if (G.debug & G_DEBUG_DEPSGRAPH_TAG) {
+ printf("%s: id=%s flag=%d\n", __func__, id->name, flag);
+ }
DEG::deg_id_tag_update(bmain, id, flag);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 886601225c7..1ae1b52b8d2 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -81,6 +81,7 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
/* Generic Operations. */
STRINGIFY_OPCODE(OPERATION);
+ STRINGIFY_OPCODE(ID_PROPERTY);
STRINGIFY_OPCODE(PARAMETERS_EVAL);
STRINGIFY_OPCODE(PLACEHOLDER);
/* Animation, Drivers, etc. */
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index 3f4df21b8d6..f8699186866 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -162,6 +162,7 @@ typedef enum eDepsOperation_Code {
DEG_OPCODE_OPERATION = 0,
/* Generic parameters evaluation. */
+ DEG_OPCODE_ID_PROPERTY,
DEG_OPCODE_PARAMETERS_EVAL,
// XXX: Placeholder while porting depsgraph code
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c3aa84943d3..a8fa73654a4 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -234,6 +234,7 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
if (BLI_gset_len(graph->entry_tags) == 0) {
return;
}
+ const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
/* Set time for the current graph evaluation context. */
TimeSourceDepsNode *time_src = graph->find_time_source();
eval_ctx->depsgraph = (::Depsgraph *)graph;
@@ -243,7 +244,7 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
DepsgraphEvalState state;
state.eval_ctx = eval_ctx;
state.graph = graph;
- state.do_stats = (G.debug_value != 0);
+ state.do_stats = do_time_debug;
/* Set up task scheduler and pull for threaded evaluation. */
TaskScheduler *task_scheduler;
bool need_free_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 8bdc68d9351..5be95543801 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
@@ -87,7 +87,7 @@ extern "C" {
namespace DEG {
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
namespace {
@@ -614,6 +614,8 @@ void update_copy_on_write_scene(const Depsgraph *depsgraph,
BLI_strncpy(scene_cow->view_render.engine_id,
scene_orig->view_render.engine_id,
sizeof(scene_cow->view_render.engine_id));
+ BKE_toolsettings_free(scene_cow->toolsettings);
+ scene_cow->toolsettings = BKE_toolsettings_copy(scene_orig->toolsettings, 0);
/* TODO(sergey): What else do we need here? */
}
@@ -868,6 +870,22 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
gpumaterial_ptr = &world->gpumaterial;
break;
}
+ case ID_NT:
+ {
+ /* Node trees should try to preserve their socket pointers
+ * as much as possible. This is due to UBOs code in GPU,
+ * which references sockets from trees.
+ *
+ * These flags CURRENTLY don't need full datablock update,
+ * everything is done by node tree update function which
+ * only copies socket values.
+ */
+ const int ignore_flag = (ID_RECALC_DRAW | ID_RECALC_ANIMATION);
+ if ((id_cow->recalc & ~ignore_flag) == 0) {
+ return id_cow;
+ }
+ break;
+ }
case ID_OB:
{
Object *object = (Object *)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 b4e1c2f4e1a..8be8a4b31ba 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -248,7 +248,7 @@ void flush_editors_id_update(Main *bmain,
id_cow->recalc |= factory->id_recalc_tag();
}
GHASH_FOREACH_END();
- DEG_DEBUG_PRINTF("Accumulated recalc bits for %s: %u\n",
+ DEG_DEBUG_PRINTF(EVAL, "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)) {
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 51b3db695c2..733e4b0b524 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -64,7 +64,12 @@ set(SRC
intern/draw_common.c
intern/draw_instance_data.c
intern/draw_manager.c
+ intern/draw_manager_data.c
+ intern/draw_manager_exec.c
+ intern/draw_manager_framebuffer.c
+ intern/draw_manager_shader.c
intern/draw_manager_text.c
+ intern/draw_manager_texture.c
intern/draw_manager_profiling.c
intern/draw_view.c
modes/edit_armature_mode.c
@@ -108,6 +113,7 @@ set(SRC
intern/draw_cache_impl.h
intern/draw_common.h
intern/draw_instance_data.h
+ intern/draw_manager.h
intern/draw_manager_text.h
intern/draw_manager_profiling.h
intern/draw_view.h
@@ -126,6 +132,9 @@ if(WITH_CLAY_ENGINE)
endif()
data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC)
+data_to_c_simple(engines/clay/shaders/clay_fxaa.glsl SRC)
+data_to_c_simple(engines/clay/shaders/clay_copy.glsl SRC)
+data_to_c_simple(engines/clay/shaders/clay_prepass_frag.glsl SRC)
data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC)
data_to_c_simple(engines/clay/shaders/clay_particle_vert.glsl SRC)
data_to_c_simple(engines/clay/shaders/clay_particle_strand_frag.glsl SRC)
@@ -197,6 +206,7 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC)
+data_to_c_simple(modes/shaders/common_view_lib.glsl SRC)
data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_vert.glsl SRC)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 9baad113c42..cc4c0ed10e8 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -46,6 +46,7 @@ struct ViewContext;
struct ViewportEngineData;
struct View3D;
struct rcti;
+struct GPUMaterial;
struct GPUOffScreen;
struct GPUViewport;
struct RenderEngine;
@@ -88,6 +89,11 @@ typedef struct DRWUpdateContext {
void DRW_notify_view_update(const DRWUpdateContext *update_ctx);
void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id);
+
+typedef enum eDRWSelectStage { DRW_SELECT_PASS_PRE = 1, DRW_SELECT_PASS_POST, } eDRWSelectStage;
+typedef bool (*DRW_SelectPassFn)(
+ eDRWSelectStage stage, void *user_data);
+
void DRW_draw_view(const struct bContext *C);
void DRW_draw_render_loop_ex(
@@ -108,7 +114,8 @@ void DRW_draw_render_loop_offscreen(
void DRW_draw_select_loop(
struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d, const eObjectMode object_mode,
- bool use_obedit_skip, bool use_nearest, const struct rcti *rect);
+ bool use_obedit_skip, bool use_nearest, const struct rcti *rect,
+ DRW_SelectPassFn select_pass_fn, void *select_pass_user_data);
void DRW_draw_depth_loop(
struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d, const eObjectMode object_mode);
@@ -125,4 +132,11 @@ void EDIT_ARMATURE_collection_settings_create(struct IDProperty *properties);
void PAINT_WEIGHT_collection_settings_create(struct IDProperty *properties);
void PAINT_VERTEX_collection_settings_create(struct IDProperty *properties);
+void DRW_opengl_context_create(void);
+void DRW_opengl_context_destroy(void);
+void DRW_opengl_context_enable(void);
+void DRW_opengl_context_disable(void);
+
+void DRW_deferred_shader_remove(struct GPUMaterial *mat);
+
#endif /* __DRW_ENGINE_H__ */
diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c
index 4b554f776a6..382551b16e4 100644
--- a/source/blender/draw/engines/clay/clay_engine.c
+++ b/source/blender/draw/engines/clay/clay_engine.c
@@ -20,7 +20,7 @@
*/
#include "BLI_utildefines.h"
-#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "BLI_rand.h"
#include "DNA_particle_types.h"
@@ -51,17 +51,24 @@
#define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */
-#define SHADER_DEFINES \
+#define SHADER_DEFINES_NO_AO \
"#define MAX_MATERIAL " STRINGIFY(MAX_CLAY_MAT) "\n" \
"#define USE_ROTATION\n" \
- "#define USE_AO\n" \
"#define USE_HSV\n"
+#define SHADER_DEFINES \
+ SHADER_DEFINES_NO_AO \
+ "#define USE_AO\n"
+
extern char datatoc_clay_frag_glsl[];
+extern char datatoc_clay_prepass_frag_glsl[];
+extern char datatoc_clay_copy_glsl[];
extern char datatoc_clay_vert_glsl[];
+extern char datatoc_clay_fxaa_glsl[];
extern char datatoc_clay_particle_vert_glsl[];
extern char datatoc_clay_particle_strand_frag_glsl[];
extern char datatoc_ssao_alchemy_glsl[];
+extern char datatoc_common_fxaa_lib_glsl[];
/* *********** LISTS *********** */
@@ -111,6 +118,8 @@ typedef struct CLAY_Storage {
int hair_ubo_current_id;
DRWShadingGroup *shgrps[MAX_CLAY_MAT];
DRWShadingGroup *shgrps_flat[MAX_CLAY_MAT];
+ DRWShadingGroup *shgrps_pre[MAX_CLAY_MAT];
+ DRWShadingGroup *shgrps_pre_flat[MAX_CLAY_MAT];
DRWShadingGroup *hair_shgrps[MAX_CLAY_MAT];
} CLAY_Storage;
@@ -120,24 +129,33 @@ typedef struct CLAY_StorageList {
} CLAY_StorageList;
typedef struct CLAY_FramebufferList {
- /* default */
- struct GPUFrameBuffer *default_fb;
- /* engine specific */
- struct GPUFrameBuffer *dupli_depth;
+ struct GPUFrameBuffer *antialias_fb;
+ struct GPUFrameBuffer *prepass_fb;
} CLAY_FramebufferList;
typedef struct CLAY_PassList {
- struct DRWPass *depth_pass;
- struct DRWPass *depth_pass_cull;
- struct DRWPass *clay_pass;
- struct DRWPass *clay_pass_flat;
+ struct DRWPass *clay_ps;
+ struct DRWPass *clay_cull_ps;
+ struct DRWPass *clay_flat_ps;
+ struct DRWPass *clay_flat_cull_ps;
+ struct DRWPass *clay_pre_ps;
+ struct DRWPass *clay_pre_cull_ps;
+ struct DRWPass *clay_flat_pre_ps;
+ struct DRWPass *clay_flat_pre_cull_ps;
+ struct DRWPass *clay_deferred_ps;
+ struct DRWPass *fxaa_ps;
+ struct DRWPass *copy_ps;
struct DRWPass *hair_pass;
} CLAY_PassList;
+typedef struct CLAY_TextureList {
+ struct GPUTexture *color_copy; /* only used if fxaa */
+} CLAY_TextureList;
+
typedef struct CLAY_Data {
void *engine_type;
CLAY_FramebufferList *fbl;
- DRWViewportEmptyList *txl;
+ CLAY_TextureList *txl;
CLAY_PassList *psl;
CLAY_StorageList *stl;
} CLAY_Data;
@@ -154,27 +172,22 @@ typedef struct CLAY_ViewLayerData {
/* *********** STATIC *********** */
static struct {
- /* Depth Pre Pass */
- struct GPUShader *depth_sh;
/* Shading Pass */
struct GPUShader *clay_sh;
struct GPUShader *clay_flat_sh;
+ struct GPUShader *clay_prepass_flat_sh;
+ struct GPUShader *clay_prepass_sh;
+ struct GPUShader *clay_deferred_shading_sh;
+ struct GPUShader *fxaa_sh;
+ struct GPUShader *copy_sh;
struct GPUShader *hair_sh;
-
/* Matcap textures */
struct GPUTexture *matcap_array;
float matcap_colors[24][4];
-
- /* Ssao */
- float winmat[4][4];
- float viewvecs[3][4];
- float ssao_params[4];
-
/* Just a serie of int from 0 to MAX_CLAY_MAT-1 */
int ubo_mat_idxs[MAX_CLAY_MAT];
-
- /* engine specific */
- struct GPUTexture *depth_dup;
+ /* To avoid useless texture and ubo binds. */
+ bool first_shgrp;
} e_data = {NULL}; /* Engine data */
typedef struct CLAY_PrivateData {
@@ -184,7 +197,15 @@ typedef struct CLAY_PrivateData {
DRWShadingGroup *depth_shgrp_cull;
DRWShadingGroup *depth_shgrp_cull_select;
DRWShadingGroup *depth_shgrp_cull_active;
- bool enable_ao;
+ /* Deferred shading */
+ struct GPUTexture *depth_tx; /* ref only, not alloced */
+ struct GPUTexture *normal_tx; /* ref only, not alloced */
+ struct GPUTexture *id_tx; /* ref only, not alloced */
+ bool enable_deferred_path;
+ /* Ssao */
+ float winmat[4][4];
+ float viewvecs[3][4];
+ float ssao_params[4];
} CLAY_PrivateData; /* Transient data */
/* Functions */
@@ -330,6 +351,7 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
static void clay_engine_init(void *vedata)
{
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
+ CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl;
CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get();
@@ -366,31 +388,44 @@ static void clay_engine_init(void *vedata)
e_data.matcap_array = load_matcaps(prv, 24);
}
- /* Depth prepass */
- if (!e_data.depth_sh) {
- e_data.depth_sh = DRW_shader_create_3D_depth_only();
- }
-
/* Shading pass */
if (!e_data.clay_sh) {
- DynStr *ds = BLI_dynstr_new();
- char *matcap_with_ao;
-
- BLI_dynstr_append(ds, datatoc_clay_frag_glsl);
- BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl);
-
- matcap_with_ao = BLI_dynstr_get_cstring(ds);
+ char *matcap_with_ao = BLI_string_joinN(
+ datatoc_clay_frag_glsl,
+ datatoc_ssao_alchemy_glsl);
e_data.clay_sh = DRW_shader_create(
- datatoc_clay_vert_glsl, NULL, matcap_with_ao,
- SHADER_DEFINES);
+ datatoc_clay_vert_glsl, NULL, datatoc_clay_frag_glsl,
+ SHADER_DEFINES_NO_AO);
e_data.clay_flat_sh = DRW_shader_create(
- datatoc_clay_vert_glsl, NULL, matcap_with_ao,
+ datatoc_clay_vert_glsl, NULL, datatoc_clay_frag_glsl,
+ SHADER_DEFINES_NO_AO
+ "#define USE_FLAT_NORMAL\n");
+
+ e_data.clay_prepass_sh = DRW_shader_create(
+ datatoc_clay_vert_glsl, NULL, datatoc_clay_prepass_frag_glsl,
+ SHADER_DEFINES);
+ e_data.clay_prepass_flat_sh = DRW_shader_create(
+ datatoc_clay_vert_glsl, NULL, datatoc_clay_prepass_frag_glsl,
SHADER_DEFINES
"#define USE_FLAT_NORMAL\n");
- BLI_dynstr_free(ds);
+ e_data.clay_deferred_shading_sh = DRW_shader_create_fullscreen(
+ matcap_with_ao,
+ SHADER_DEFINES
+ "#define DEFERRED_SHADING\n");
+
MEM_freeN(matcap_with_ao);
+
+ char *fxaa_str = BLI_string_joinN(
+ datatoc_common_fxaa_lib_glsl,
+ datatoc_clay_fxaa_glsl);
+
+ e_data.fxaa_sh = DRW_shader_create_fullscreen(fxaa_str, NULL);
+
+ MEM_freeN(fxaa_str);
+
+ e_data.copy_sh = DRW_shader_create_fullscreen(datatoc_clay_copy_glsl, NULL);
}
if (!e_data.hair_sh) {
@@ -403,6 +438,12 @@ static void clay_engine_init(void *vedata)
stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage");
}
+ if (!stl->g_data) {
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), "CLAY_PrivateStorage");
+ }
+
+ CLAY_PrivateData *g_data = stl->g_data;
+
if (!sldata->mat_ubo) {
sldata->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL);
}
@@ -424,8 +465,15 @@ static void clay_engine_init(void *vedata)
if (DRW_state_is_fbo()) {
const float *viewport_size = DRW_viewport_size_get();
- DRWFboTexture tex = {&e_data.depth_dup, DRW_TEX_DEPTH_24_STENCIL_8, DRW_TEX_TEMP};
- DRW_framebuffer_init(&fbl->dupli_depth, &draw_engine_clay_type,
+ DRWFboTexture texs[2] = {{&g_data->normal_tx, DRW_TEX_RG_8, DRW_TEX_TEMP},
+ {&g_data->id_tx, DRW_TEX_R_16I, DRW_TEX_TEMP}};
+ DRW_framebuffer_init(&fbl->prepass_fb, &draw_engine_clay_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ texs, 2);
+
+ /* For FXAA */
+ DRWFboTexture tex = {&txl->color_copy, DRW_TEX_RGBA_8, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->antialias_fb, &draw_engine_clay_type,
(int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
}
@@ -453,14 +501,14 @@ static void clay_engine_init(void *vedata)
DRW_state_dfdy_factors_get(dfdyfacs);
- e_data.ssao_params[0] = ssao_samples;
- e_data.ssao_params[1] = size[0] / 64.0;
- e_data.ssao_params[2] = size[1] / 64.0;
- e_data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
+ g_data->ssao_params[0] = ssao_samples;
+ g_data->ssao_params[1] = size[0] / 64.0;
+ g_data->ssao_params[2] = size[1] / 64.0;
+ g_data->ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
/* invert the view matrix */
- DRW_viewport_matrix_get(e_data.winmat, DRW_MAT_WIN);
- invert_m4_m4(invproj, e_data.winmat);
+ DRW_viewport_matrix_get(g_data->winmat, DRW_MAT_WIN);
+ invert_m4_m4(invproj, g_data->winmat);
/* convert the view vectors to view space */
for (i = 0; i < 3; i++) {
@@ -472,19 +520,19 @@ static void clay_engine_init(void *vedata)
mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
viewvecs[i][3] = 1.0;
- copy_v4_v4(e_data.viewvecs[i], viewvecs[i]);
+ copy_v4_v4(g_data->viewvecs[i], viewvecs[i]);
}
/* we need to store the differences */
- e_data.viewvecs[1][0] -= e_data.viewvecs[0][0];
- e_data.viewvecs[1][1] = e_data.viewvecs[2][1] - e_data.viewvecs[0][1];
+ g_data->viewvecs[1][0] -= g_data->viewvecs[0][0];
+ g_data->viewvecs[1][1] = g_data->viewvecs[2][1] - g_data->viewvecs[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]);
- e_data.viewvecs[1][2] = vec_far[2] - e_data.viewvecs[0][2];
+ g_data->viewvecs[1][2] = vec_far[2] - g_data->viewvecs[0][2];
}
/* AO Samples Tex */
@@ -503,37 +551,56 @@ static void clay_engine_init(void *vedata)
}
}
-static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *UNUSED(vedata), DRWPass *pass, int *material_id, bool use_flat)
+static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, GPUShader *sh, int id)
{
CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get();
- DRWShadingGroup *grp = DRW_shgroup_create(use_flat ? e_data.clay_flat_sh : e_data.clay_sh, pass);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1);
+ if (e_data.first_shgrp) {
+ DRW_shgroup_uniform_texture_persistent(grp, "matcaps", e_data.matcap_array);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", sldata->mat_ubo);
+ DRW_shgroup_uniform_block_persistent(grp, "matcaps_block", sldata->matcaps_ubo);
+ }
+ return grp;
+}
- DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_buffer(grp, "depthtex", &e_data.depth_dup);
- DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array);
- DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)e_data.winmat);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)e_data.viewvecs, 3);
- DRW_shgroup_uniform_vec4(grp, "ssao_params", e_data.ssao_params, 1);
+static DRWShadingGroup *CLAY_shgroup_deferred_prepass_create(DRWPass *pass, GPUShader *sh, int id)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1);
- DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1);
+ return grp;
+}
+static DRWShadingGroup *CLAY_shgroup_deferred_shading_create(DRWPass *pass, CLAY_PrivateData *g_data)
+{
+ CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get();
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.clay_deferred_shading_sh, pass);
+ DRW_shgroup_uniform_buffer(grp, "depthtex", &g_data->depth_tx);
+ DRW_shgroup_uniform_buffer(grp, "normaltex", &g_data->normal_tx);
+ DRW_shgroup_uniform_buffer(grp, "idtex", &g_data->id_tx);
+ DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array);
DRW_shgroup_uniform_texture(grp, "ssao_jitter", sldata->jitter_tx);
DRW_shgroup_uniform_block(grp, "samples_block", sldata->sampling_ubo);
DRW_shgroup_uniform_block(grp, "material_block", sldata->mat_ubo);
DRW_shgroup_uniform_block(grp, "matcaps_block", sldata->matcaps_ubo);
-
+ /* TODO put in ubo */
+ DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)g_data->winmat);
+ DRW_shgroup_uniform_vec2(grp, "invscreenres", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)g_data->viewvecs, 3);
+ DRW_shgroup_uniform_vec4(grp, "ssao_params", g_data->ssao_params, 1);
return grp;
}
-static DRWShadingGroup *CLAY_hair_shgroup_create(CLAY_Data *UNUSED(vedata), DRWPass *pass, int *material_id)
+static DRWShadingGroup *CLAY_hair_shgroup_create(DRWPass *pass, int id)
{
CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get();
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass);
DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array);
- DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1);
DRW_shgroup_uniform_block(grp, "material_block", sldata->mat_ubo);
DRW_shgroup_uniform_block(grp, "matcaps_block", sldata->matcaps_ubo);
+ DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1);
return grp;
}
@@ -568,25 +635,17 @@ static int search_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Mat
static int push_mat_to_ubo(CLAY_Storage *storage, const CLAY_UBO_Material *mat_ubo_test)
{
- int id = storage->ubo_current_id;
- CLAY_UBO_Material *ubo = &storage->mat_storage.materials[id];
-
- *ubo = *mat_ubo_test;
-
- storage->ubo_current_id++;
-
+ int id = storage->ubo_current_id++;
+ id = min_ii(MAX_CLAY_MAT, id);
+ storage->mat_storage.materials[id] = *mat_ubo_test;
return id;
}
static int push_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *hair_mat_ubo_test)
{
- int id = storage->hair_ubo_current_id;
- CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[id];
-
- *ubo = *hair_mat_ubo_test;
-
- storage->hair_ubo_current_id++;
-
+ int id = storage->hair_ubo_current_id++;
+ id = min_ii(MAX_CLAY_MAT, id);
+ storage->hair_mat_storage.materials[id] = *hair_mat_ubo_test;
return id;
}
@@ -616,11 +675,11 @@ 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, bool *r_needs_ao)
+static void ubo_mat_from_object(CLAY_Storage *storage, Object *ob, bool *r_needs_ao, int *r_id)
{
IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
- /* Default Settings */
+ int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation");
float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue");
float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation");
@@ -629,41 +688,45 @@ static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_ne
float ssao_factor_cavity = BKE_collection_engine_property_value_get_float(props, "ssao_factor_cavity");
float ssao_factor_edge = BKE_collection_engine_property_value_get_float(props, "ssao_factor_edge");
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");
+
+ CLAY_UBO_Material r_ubo = {{0.0f}};
if (((ssao_factor_cavity > 0.0) || (ssao_factor_edge > 0.0)) &&
(ssao_distance > 0.0))
{
*r_needs_ao = true;
+
+ r_ubo.ssao_params_var[0] = ssao_distance;
+ r_ubo.ssao_params_var[1] = ssao_factor_cavity;
+ r_ubo.ssao_params_var[2] = ssao_factor_edge;
+ r_ubo.ssao_params_var[3] = ssao_attenuation;
+ }
+ else {
+ *r_needs_ao = false;
}
- memset(r_ubo, 0x0, sizeof(*r_ubo));
+ r_ubo.matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
+ r_ubo.matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f);
- r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
- r_ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f);
+ r_ubo.matcap_hsv[0] = matcap_hue + 0.5f;
+ r_ubo.matcap_hsv[1] = matcap_sat * 2.0f;
+ r_ubo.matcap_hsv[2] = matcap_val * 2.0f;
- r_ubo->matcap_hsv[0] = matcap_hue + 0.5f;
- r_ubo->matcap_hsv[1] = matcap_sat * 2.0f;
- r_ubo->matcap_hsv[2] = matcap_val * 2.0f;
+ r_ubo.matcap_id = matcap_to_index(matcap_icon);
- r_ubo->ssao_params_var[0] = ssao_distance;
- r_ubo->ssao_params_var[1] = ssao_factor_cavity;
- r_ubo->ssao_params_var[2] = ssao_factor_edge;
- r_ubo->ssao_params_var[3] = ssao_attenuation;
- r_ubo->matcap_id = matcap_to_index(matcap_icon);
+ *r_id = mat_in_ubo(storage, &r_ubo);
}
-static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo)
+static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo)
{
IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
- /* Default Settings */
+ int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation");
float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue");
float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation");
float matcap_val = BKE_collection_engine_property_value_get_float(props, "matcap_value");
float hair_randomness = BKE_collection_engine_property_value_get_float(props, "hair_brightness_randomness");
- int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
memset(r_ubo, 0x0, sizeof(*r_ubo));
@@ -676,25 +739,56 @@ static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo)
r_ubo->matcap_id = matcap_to_index(matcap_icon);
}
-static DRWShadingGroup *CLAY_object_shgrp_get(
- CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl, bool use_flat)
+static DRWShadingGroup *CLAY_object_shgrp_get(CLAY_Data *vedata, Object *ob, bool use_flat, bool cull)
{
- DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps;
- CLAY_UBO_Material mat_ubo_test;
+ bool prepass; int id;
+ CLAY_PassList *psl = vedata->psl;
+ CLAY_Storage *storage = vedata->stl->storage;
+ DRWShadingGroup **shgrps;
+ DRWPass *pass; GPUShader *sh;
+
+ ubo_mat_from_object(storage, ob, &prepass, &id);
+
+ if (prepass) {
+ if (use_flat) {
+ shgrps = storage->shgrps_pre_flat;
+ pass = (cull) ? psl->clay_flat_pre_cull_ps : psl->clay_flat_pre_ps;
+ sh = e_data.clay_prepass_flat_sh;
+ }
+ else {
+ shgrps = storage->shgrps_pre;
+ pass = (cull) ? psl->clay_pre_cull_ps : psl->clay_pre_ps;
+ sh = e_data.clay_prepass_sh;
+ }
- ubo_mat_from_object(ob, &mat_ubo_test, &stl->g_data->enable_ao);
+ if (shgrps[id] == NULL) {
+ shgrps[id] = CLAY_shgroup_deferred_prepass_create(pass, sh, id);
+ }
- int id = mat_in_ubo(stl->storage, &mat_ubo_test);
+ vedata->stl->g_data->enable_deferred_path = true;
+ }
+ else {
+ if (use_flat) {
+ shgrps = storage->shgrps_flat;
+ pass = (cull) ? psl->clay_flat_cull_ps : psl->clay_flat_ps;
+ sh = e_data.clay_flat_sh;
+ }
+ else {
+ shgrps = storage->shgrps;
+ pass = (cull) ? psl->clay_cull_ps : psl->clay_ps;
+ sh = e_data.clay_sh;
+ }
- if (shgrps[id] == NULL) {
- shgrps[id] = CLAY_shgroup_create(
- vedata, use_flat ? psl->clay_pass_flat : psl->clay_pass, &e_data.ubo_mat_idxs[id], use_flat);
+ if (shgrps[id] == NULL) {
+ shgrps[id] = CLAY_shgroup_create(pass, sh, id);
+ e_data.first_shgrp = false;
+ }
}
return shgrps[id];
}
-static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
+static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *UNUSED(vedata), Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
{
DRWShadingGroup **hair_shgrps = stl->storage->hair_shgrps;
@@ -704,54 +798,44 @@ static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_
int hair_id = hair_mat_in_ubo(stl->storage, &hair_mat_ubo_test);
if (hair_shgrps[hair_id] == NULL) {
- hair_shgrps[hair_id] = CLAY_hair_shgroup_create(vedata, psl->hair_pass, &e_data.ubo_mat_idxs[hair_id]);
+ hair_shgrps[hair_id] = CLAY_hair_shgroup_create(psl->hair_pass, hair_id);
}
return hair_shgrps[hair_id];
}
-static DRWShadingGroup *CLAY_object_shgrp_default_mode_get(
- CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
-{
- bool use_flat = DRW_object_is_flat_normal(ob);
- return CLAY_object_shgrp_get(vedata, ob, stl, psl, use_flat);
-}
-
static void clay_cache_init(void *vedata)
{
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- }
+ CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl;
/* Disable AO unless a material needs it. */
- stl->g_data->enable_ao = false;
+ stl->g_data->enable_deferred_path = false;
- /* Depth Pass */
- {
- psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
-
- psl->depth_pass_cull = DRW_pass_create(
- "Depth Pass Cull",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK);
- stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull);
- }
+ /* Reset UBO datas, shgrp pointers and material id counters. */
+ memset(stl->storage, 0, sizeof(*stl->storage));
+ e_data.first_shgrp = true;
- /* Clay Pass */
+ /* Solid Passes */
{
- psl->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
- stl->storage->ubo_current_id = 0;
- memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
- }
-
- /* Clay Pass (Flat) */
- {
- psl->clay_pass_flat = DRW_pass_create("Clay Pass Flat", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
- memset(stl->storage->shgrps_flat, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ psl->clay_ps = DRW_pass_create("Clay", state);
+ psl->clay_cull_ps = DRW_pass_create("Clay Culled", state | DRW_STATE_CULL_BACK);
+ psl->clay_flat_ps = DRW_pass_create("Clay Flat", state);
+ psl->clay_flat_cull_ps = DRW_pass_create("Clay Flat Culled", state | DRW_STATE_CULL_BACK);
+
+ DRWState prepass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ DRWState prepass_cull_state = prepass_state | DRW_STATE_CULL_BACK;
+ psl->clay_pre_ps = DRW_pass_create("Clay Deferred Pre", prepass_state);
+ psl->clay_pre_cull_ps = DRW_pass_create("Clay Deferred Pre Culled", prepass_cull_state);
+ psl->clay_flat_pre_ps = DRW_pass_create("Clay Deferred Flat Pre", prepass_state);
+ psl->clay_flat_pre_cull_ps = DRW_pass_create("Clay Deferred Flat Pre Culled", prepass_cull_state);
+
+ psl->clay_deferred_ps = DRW_pass_create("Clay Deferred Shading", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = CLAY_shgroup_deferred_shading_create(psl->clay_deferred_ps, stl->g_data);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
/* Hair Pass */
@@ -759,8 +843,19 @@ static void clay_cache_init(void *vedata)
psl->hair_pass = DRW_pass_create(
"Hair Pass",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE);
- stl->storage->hair_ubo_current_id = 0;
- memset(stl->storage->hair_shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
+ }
+
+ {
+ psl->fxaa_ps = DRW_pass_create("Fxaa", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.fxaa_sh, psl->fxaa_ps);
+ DRW_shgroup_uniform_buffer(grp, "colortex", &dtxl->color);
+ DRW_shgroup_uniform_vec2(grp, "invscreenres", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+
+ psl->copy_ps = DRW_pass_create("Copy", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.copy_sh, psl->copy_ps);
+ DRW_shgroup_uniform_buffer(grp, "colortex", &txl->color_copy);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
}
@@ -795,9 +890,6 @@ static void clay_cache_populate_particles(void *vedata, Object *ob)
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;
if (!DRW_object_is_renderable(ob))
@@ -825,32 +917,15 @@ static void clay_cache_populate(void *vedata, Object *ob)
IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
const bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling");
const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0;
- const bool is_default_mode_shader = is_sculpt_mode;
+ const bool use_flat = is_sculpt_mode && DRW_object_is_flat_normal(ob);
- /* Depth Prepass */
- {
- DRWShadingGroup *depth_shgrp = do_cull ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
- if (is_sculpt_mode) {
- DRW_shgroup_call_sculpt_add(depth_shgrp, ob, ob->obmat);
- }
- else {
- DRW_shgroup_call_object_add(depth_shgrp, geom, ob);
- }
- }
-
- /* Shading */
- if (is_default_mode_shader) {
- clay_shgrp = CLAY_object_shgrp_default_mode_get(vedata, ob, stl, psl);
- }
- else {
- clay_shgrp = CLAY_object_shgrp_get(vedata, ob, stl, psl, false);
- }
+ clay_shgrp = CLAY_object_shgrp_get(vedata, ob, use_flat, do_cull);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(clay_shgrp, ob, ob->obmat);
}
else {
- DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat);
+ DRW_shgroup_call_object_add(clay_shgrp, geom, ob);
}
}
}
@@ -870,37 +945,50 @@ static void clay_draw_scene(void *vedata)
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ stl->g_data->depth_tx = dtxl->depth;
+
+ /* Passes are ordered to have less _potential_ overdraw */
+ DRW_draw_pass(psl->clay_cull_ps);
+ DRW_draw_pass(psl->clay_flat_cull_ps);
+ DRW_draw_pass(psl->clay_ps);
+ DRW_draw_pass(psl->clay_flat_ps);
+ DRW_draw_pass(psl->hair_pass);
- /* Pass 1 : Depth pre-pass */
- 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);
- }
+ if (stl->g_data->enable_deferred_path) {
+ if (DRW_state_is_fbo()) {
+ DRW_framebuffer_texture_detach(dtxl->depth);
+ DRW_framebuffer_texture_attach(fbl->prepass_fb, dtxl->depth, 0, 0);
+ DRW_framebuffer_texture_attach(fbl->prepass_fb, stl->g_data->normal_tx, 0, 0);
+ DRW_framebuffer_texture_attach(fbl->prepass_fb, stl->g_data->id_tx, 1, 0);
+ DRW_framebuffer_bind(fbl->prepass_fb);
+ /* We need to clear the id texture unfortunately. */
+ DRW_framebuffer_clear(true, false, false, (float[4]){0.0f, 0.0f, 0.0f, 0.0f}, 0.0f);
+ }
- /* 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() && stl->g_data->enable_ao) {
- /* attach temp textures */
- DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0);
+ DRW_draw_pass(psl->clay_pre_cull_ps);
+ DRW_draw_pass(psl->clay_flat_pre_cull_ps);
+ DRW_draw_pass(psl->clay_pre_ps);
+ DRW_draw_pass(psl->clay_flat_pre_ps);
- DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true, false);
+ if (DRW_state_is_fbo()) {
+ DRW_framebuffer_texture_detach(dtxl->depth);
+ DRW_framebuffer_bind(dfbl->default_fb);
- /* detach temp textures */
- DRW_framebuffer_texture_detach(e_data.depth_dup);
+ DRW_draw_pass(psl->clay_deferred_ps);
- /* restore default fb */
- DRW_framebuffer_bind(dfbl->default_fb);
+ DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ DRW_framebuffer_bind(dfbl->default_fb);
+ }
}
- /* Pass 3 : Shading */
- DRW_draw_pass(psl->clay_pass);
- DRW_draw_pass(psl->clay_pass_flat);
- DRW_draw_pass(psl->hair_pass);
+ if (true) { /* Always on for now. We might want a parameter for this. */
+ DRW_framebuffer_bind(fbl->antialias_fb);
+ DRW_draw_pass(psl->fxaa_ps);
+
+ DRW_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->copy_ps);
+ }
}
static void clay_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
@@ -935,6 +1023,11 @@ static void clay_engine_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.clay_sh);
DRW_SHADER_FREE_SAFE(e_data.clay_flat_sh);
+ DRW_SHADER_FREE_SAFE(e_data.clay_prepass_flat_sh);
+ DRW_SHADER_FREE_SAFE(e_data.clay_prepass_sh);
+ DRW_SHADER_FREE_SAFE(e_data.clay_deferred_shading_sh);
+ DRW_SHADER_FREE_SAFE(e_data.fxaa_sh);
+ DRW_SHADER_FREE_SAFE(e_data.copy_sh);
DRW_SHADER_FREE_SAFE(e_data.hair_sh);
DRW_TEXTURE_FREE_SAFE(e_data.matcap_array);
}
diff --git a/source/blender/draw/engines/clay/shaders/clay_copy.glsl b/source/blender/draw/engines/clay/shaders/clay_copy.glsl
new file mode 100644
index 00000000000..ec462978e67
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_copy.glsl
@@ -0,0 +1,10 @@
+
+in vec4 uvcoordsvar;
+out vec4 fragColor;
+
+uniform sampler2D colortex;
+
+void main()
+{
+ fragColor = texture(colortex, uvcoordsvar.st);
+}
diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl
index 619843e2a02..f2c6cd5f780 100644
--- a/source/blender/draw/engines/clay/shaders/clay_frag.glsl
+++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl
@@ -1,5 +1,4 @@
-uniform vec2 screenres;
-uniform sampler2D depthtex;
+uniform vec2 invscreenres;
uniform mat4 WinMatrix;
/* Matcap */
@@ -33,7 +32,14 @@ layout(std140) uniform material_block {
Material matcaps_param[MAX_MATERIAL];
};
+#ifdef DEFERRED_SHADING
+uniform sampler2D depthtex;
+uniform sampler2D normaltex;
+uniform isampler2D idtex;
+int mat_id; /* global */
+#else
uniform int mat_id;
+#endif
/* Aliases */
#define ssao_samples_num ssao_params.x
@@ -44,10 +50,12 @@ uniform int mat_id;
#define matcap_index matcaps_param[mat_id].matcap_hsv_id.w
#define matcap_rotation matcaps_param[mat_id].matcap_rot.xy
-#ifdef USE_FLAT_NORMAL
+#ifndef DEFERRED_SHADING
+# ifdef USE_FLAT_NORMAL
flat in vec3 normal;
-#else
+# else
in vec3 normal;
+# endif
#endif
out vec4 fragColor;
@@ -169,24 +177,33 @@ void ssao_factors(
out float cavities, out float edges);
#endif
-void main() {
- vec2 screenco = vec2(gl_FragCoord.xy) / screenres;
- float depth = texture(depthtex, screenco).r;
-
- vec3 position = get_view_space_from_depth(screenco, depth);
+/* From http://aras-p.info/texts/CompactNormalStorage.html
+ * Using Method #4: Spheremap Transform */
+vec3 normal_decode(vec2 enc)
+{
+ vec2 fenc = enc * 4.0 - 2.0;
+ float f = dot(fenc, fenc);
+ float g = sqrt(1.0 - f / 4.0);
+ vec3 n;
+ n.xy = fenc*g;
+ n.z = 1 - f / 2;
+ return n;
+}
+vec3 shade(vec3 N, vec3 position, float depth, vec2 screenco)
+{
#ifdef USE_ROTATION
/* Rotate texture coordinates */
vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x);
- vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5);
+ vec2 texco = abs(vec2(dot(N.xy, matcap_rotation), dot(N.xy, rotY)) * .49 + 0.5);
#else
- vec2 texco = abs(normal.xy * .49 + 0.5);
+ vec2 texco = abs(N.xy * .49 + 0.5);
#endif
vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb;
#ifdef USE_AO
- float cavity, edges;
- ssao_factors(depth, normal, position, screenco, cavity, edges);
+ float cavity = 0.0, edges = 0.0;
+ ssao_factors(depth, N, position, screenco, cavity, edges);
col *= mix(vec3(1.0), matcaps_color[int(matcap_index)].rgb, cavity);
#endif
@@ -200,5 +217,35 @@ void main() {
col *= edges + 1.0;
#endif
+ return col;
+}
+
+void main()
+{
+ vec2 screenco = vec2(gl_FragCoord.xy) * invscreenres;
+
+#ifdef DEFERRED_SHADING
+ mat_id = texture(idtex, screenco).r;
+
+ /* early out (manual stencil test) */
+ if (mat_id == 0)
+ discard;
+
+ float depth = texture(depthtex, screenco).r;
+ vec3 N = normal_decode(texture(normaltex, screenco).rg);
+ /* see the prepass for explanations. */
+ if (mat_id < 0) {
+ N = -N;
+ }
+ mat_id = abs(mat_id) - 1;
+#else
+ float depth = gl_FragCoord.z;
+ vec3 N = normal;
+#endif
+
+ vec3 position = get_view_space_from_depth(screenco, depth);
+
+ vec3 col = shade(N, position, depth, screenco);
+
fragColor = vec4(col, 1.0);
}
diff --git a/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl b/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl
new file mode 100644
index 00000000000..1a34927aaa6
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl
@@ -0,0 +1,18 @@
+
+in vec4 uvcoordsvar;
+out vec4 fragColor;
+
+uniform vec2 invscreenres;
+uniform sampler2D colortex;
+
+void main()
+{
+ fragColor = FxaaPixelShader(
+ uvcoordsvar.st,
+ colortex,
+ invscreenres,
+ 1.0,
+ 0.166,
+ 0.0833
+ );
+}
diff --git a/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl
new file mode 100644
index 00000000000..8eb22a7854c
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl
@@ -0,0 +1,44 @@
+uniform int mat_id;
+
+#ifdef USE_FLAT_NORMAL
+flat in vec3 normal;
+#else
+in vec3 normal;
+#endif
+
+layout(location = 0) out vec2 outNormals;
+layout(location = 1) out int outIndex;
+
+/* From http://aras-p.info/texts/CompactNormalStorage.html
+ * Using Method #4: Spheremap Transform */
+vec2 normal_encode(vec3 n)
+{
+ float p = sqrt(n.z * 8.0 + 8.0);
+ return n.xy / p + 0.5;
+}
+
+/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */
+#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0))
+const mat4 dither_mat = mat4(
+ vec4( P(0.0), P(8.0), P(2.0), P(10.0)),
+ vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
+ vec4( P(3.0), P(11.0), P(1.0), P(9.0)),
+ vec4(P(15.0), P(7.0), P(13.0), P(5.0))
+);
+
+void main() {
+ outIndex = (mat_id + 1); /* 0 is clear color */
+ /**
+ * To fix the normal buffer precision issue for backfaces,
+ * we invert normals and use the sign of the index buffer
+ * to tag them, and re-invert in deferred pass.
+ **/
+ vec3 N = (gl_FrontFacing) ? normal : -normal;
+ outIndex = (gl_FrontFacing) ? outIndex : -outIndex;
+
+ outNormals = normal_encode(N);
+
+ /* Dither the output to fight low quality. */
+ ivec2 tx = ivec2(gl_FragCoord.xy) % 4;
+ outNormals += dither_mat[tx.x][tx.y];
+}
diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
index 48c117c3d8d..94e2d6f3c7b 100644
--- a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
+++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
@@ -10,6 +10,11 @@ void ssao_factors(
in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
out float cavities, out float edges)
{
+ cavities = edges = 0.0;
+ /* early out if there is no need for SSAO */
+ if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0)
+ return;
+
/* take the normalized ray direction here */
vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
@@ -22,7 +27,6 @@ void ssao_factors(
/* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
offset *= 0.5;
- cavities = edges = 0.0;
int num_samples = int(ssao_samples_num);
/* Note. Putting noise usage here to put some ALU after texture fetch. */
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
index 1b015a51f6a..c62f35a70e7 100644
--- a/source/blender/draw/engines/eevee/eevee_bloom.c
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -41,7 +41,7 @@ static struct {
struct GPUShader *bloom_downsample_sh[2];
struct GPUShader *bloom_upsample_sh[2];
struct GPUShader *bloom_resolve_sh[2];
-} e_data = {NULL}; /* Engine data */
+} e_data = {{NULL}}; /* Engine data */
extern char datatoc_effect_bloom_frag_glsl[];
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 449668d8590..0b6ab905e32 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -56,6 +56,7 @@ static void eevee_view_layer_data_free(void *storage)
DRW_UBO_FREE_SAFE(sldata->grid_ubo);
DRW_UBO_FREE_SAFE(sldata->planar_ubo);
DRW_UBO_FREE_SAFE(sldata->common_ubo);
+ DRW_UBO_FREE_SAFE(sldata->clip_ubo);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 751b9a0f7d6..1030fe1ce3a 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -240,13 +240,13 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
static int zero = 0;
+ static unsigned int six = 6;
psl->color_downsample_cube_ps = DRW_pass_create("Downsample Cube", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.downsample_cube_sh, psl->color_downsample_cube_ps,
- quad, NULL);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_cube_sh, psl->color_downsample_cube_ps);
DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src);
DRW_shgroup_uniform_float(grp, "texelSize", &e_data.cube_texel_size, 1);
DRW_shgroup_uniform_int(grp, "Layer", &zero, 1);
- DRW_shgroup_set_instance_count(grp, 6);
+ DRW_shgroup_call_instances_add(grp, quad, NULL, &six);
}
{
@@ -407,7 +407,7 @@ void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_
DRW_stats_group_end();
}
-void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_TextureList *txl = vedata->txl;
EEVEE_FramebufferList *fbl = vedata->fbl;
@@ -450,7 +450,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
/* Record pers matrix for the next frame. */
- DRW_viewport_matrix_get(sldata->common_data.prev_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_get(stl->effects->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 4a7258d6525..6cfecd0a226 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -78,6 +78,9 @@ static void eevee_engine_init(void *ved)
if (sldata->common_ubo == NULL) {
sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
}
+ if (sldata->clip_ubo == NULL) {
+ sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data);
+ }
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, camera);
@@ -87,24 +90,20 @@ static void eevee_engine_init(void *ved)
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);
- DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
- DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
+ DRW_viewport_matrix_override_unset_all();
}
}
static void eevee_cache_init(void *vedata)
{
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
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_lights_cache_init(sldata, vedata);
+ EEVEE_materials_cache_init(sldata, vedata);
EEVEE_motion_blur_cache_init(sldata, vedata);
EEVEE_occlusion_cache_init(sldata, vedata);
EEVEE_screen_raytrace_cache_init(sldata, vedata);
@@ -180,9 +179,10 @@ static void eevee_draw_background(void *vedata)
/* Sort transparents before the loop. */
DRW_pass_sort_shgroup_z(psl->transparent_pass);
- /* Number of iteration: needed for all temporal effect (SSR, TAA)
+ /* Number of iteration: needed for all temporal effect (SSR, volumetrics)
* when using opengl render. */
- int loop_ct = DRW_state_is_image_render() ? 4 : 1;
+ int loop_ct = (DRW_state_is_image_render() &&
+ (stl->effects->enabled_effects & (EFFECT_VOLUMETRIC | EFFECT_SSR)) != 0) ? 4 : 1;
while (loop_ct--) {
unsigned int primes[3] = {2, 3, 7};
@@ -197,10 +197,26 @@ static void eevee_draw_background(void *vedata)
EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1);
EEVEE_materials_init(sldata, stl, fbl);
}
+ /* Copy previous persmat to UBO data */
+ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat);
+
+ 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);
+ DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV);
+ }
/* Refresh Probes */
DRW_stats_group_start("Probes Refresh");
EEVEE_lightprobes_refresh(sldata, vedata);
+ /* Probes refresh can have reset the current sample. */
+ if (stl->effects->taa_current_sample == 1) {
+ DRW_viewport_matrix_override_unset_all();
+ }
EEVEE_lightprobes_refresh_planar(sldata, vedata);
DRW_stats_group_end();
@@ -225,16 +241,6 @@ static void eevee_draw_background(void *vedata)
DRW_framebuffer_clear(true, true, true, clear_col, 1.0f);
}
- 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);
- DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV);
- }
-
/* Depth prepass */
DRW_stats_group_start("Prepass");
DRW_draw_pass(psl->depth_pass);
@@ -285,10 +291,7 @@ static void eevee_draw_background(void *vedata)
DRW_stats_group_end();
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);
- DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
+ DRW_viewport_matrix_override_unset_all();
}
}
@@ -377,7 +380,7 @@ static void eevee_id_update(void *vedata, ID *id)
}
}
-static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderResult *render_result, struct RenderLayer *render_layer)
+static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
EEVEE_render_init(vedata, engine, draw_ctx->depsgraph);
@@ -385,7 +388,7 @@ static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct Ren
DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache);
/* Actually do the rendering. */
- EEVEE_render_draw(vedata, engine, render_result, render_layer);
+ EEVEE_render_draw(vedata, engine, render_layer, rect);
}
static void eevee_engine_free(void)
@@ -502,7 +505,7 @@ DrawEngineType draw_engine_eevee_type = {
RenderEngineType DRW_engine_viewport_eevee_type = {
NULL, NULL,
- EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES,
+ EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES | RE_USE_PREVIEW,
NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL,
&EEVEE_render_update_passes,
&eevee_layer_collection_settings_create,
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index b4de6081457..e751f2dd6b4 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -85,8 +85,6 @@ static struct {
struct Gwn_VertFormat *format_probe_display_cube;
struct Gwn_VertFormat *format_probe_display_planar;
-
- int update_world;
} e_data = {NULL}; /* Engine data */
extern char datatoc_background_vert_glsl[];
@@ -111,6 +109,7 @@ 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_common_view_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern GlobalsUboStorage ts;
@@ -207,8 +206,10 @@ static void lightprobe_shaders_init(void)
"#define NOISE_SIZE 64\n";
char *shader_str = NULL;
+ char *vert_str = NULL;
shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_sampling_lib_glsl,
@@ -223,6 +224,7 @@ static void lightprobe_shaders_init(void)
MEM_freeN(shader_str);
shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_sampling_lib_glsl,
@@ -233,6 +235,7 @@ static void lightprobe_shaders_init(void)
MEM_freeN(shader_str);
shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_sampling_lib_glsl,
@@ -244,15 +247,20 @@ static void lightprobe_shaders_init(void)
shader_str = BLI_string_joinN(
datatoc_octahedron_lib_glsl,
+ datatoc_common_view_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);
+ vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_grid_display_vert_glsl);
+
+ e_data.probe_grid_display_sh = DRW_shader_create(vert_str, NULL, shader_str, filter_defines);
+ MEM_freeN(vert_str);
MEM_freeN(shader_str);
e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(
@@ -260,19 +268,33 @@ static void lightprobe_shaders_init(void)
shader_str = BLI_string_joinN(
datatoc_octahedron_lib_glsl,
+ datatoc_common_view_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);
+ vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_cube_display_vert_glsl);
+ e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL);
+
+ MEM_freeN(vert_str);
MEM_freeN(shader_str);
- e_data.probe_planar_display_sh = DRW_shader_create(
- datatoc_lightprobe_planar_display_vert_glsl, NULL,
- datatoc_lightprobe_planar_display_frag_glsl, NULL);
+ vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_planar_display_vert_glsl);
+
+ shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_planar_display_frag_glsl);
+
+ e_data.probe_planar_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL);
+
+ MEM_freeN(vert_str);
+ MEM_freeN(shader_str);
e_data.probe_planar_downsample_sh = DRW_shader_create(
datatoc_lightprobe_planar_downsample_vert_glsl,
@@ -304,6 +326,9 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
}
+ /* Only start doing probes if all materials have finished compiling. */
+ sldata->probes->all_materials_updated = true;
+
common_data->spec_toggle = true;
common_data->ssr_toggle = true;
common_data->sss_toggle = true;
@@ -321,8 +346,10 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
sldata->probes->target_size = prop_cubemap_res >> 1;
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
}
int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution");
@@ -332,7 +359,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
}
if (update_all) {
- e_data.update_world |= PROBE_UPDATE_ALL;
+ sldata->probes->update_world |= PROBE_UPDATE_ALL;
sldata->probes->updated_bounce = 0;
sldata->probes->grid_initialized = false;
}
@@ -393,36 +420,47 @@ 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 || pinfo->prev_world != wo) {
- e_data.update_world |= PROBE_UPDATE_ALL;
- pinfo->updated_bounce = 0;
- pinfo->grid_initialized = false;
- }
- wo->update_flag = 0;
+ bool wo_sh_compiled = true;
if (wo->use_nodes && wo->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
- grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
-
- if (grp) {
- DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- DRW_shgroup_call_add(grp, geom, NULL);
- }
- else {
- /* Shader failed : pink background */
- static float pink[3] = {1.0f, 0.0f, 1.0f};
- col = pink;
+ GPUMaterialStatus status = GPU_material_status(gpumat);
+
+ switch (status) {
+ case GPU_MAT_SUCCESS:
+ grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ wo_sh_compiled = true;
+ break;
+ case GPU_MAT_QUEUED:
+ pinfo->all_materials_updated = false;
+ wo_sh_compiled = false;
+ /* TODO Bypass probe compilation. */
+ col = compile_col;
+ break;
+ case GPU_MAT_FAILED:
+ default:
+ wo_sh_compiled = true;
+ col = error_col;
+ break;
}
}
- pinfo->prev_world = wo;
+ if (wo->update_flag != 0 || pinfo->prev_world != wo || pinfo->prev_wo_sh_compiled != wo_sh_compiled) {
+ pinfo->update_world |= PROBE_UPDATE_ALL;
+ pinfo->prev_wo_sh_compiled = wo_sh_compiled;
+ pinfo->prev_world = wo;
+ }
+ wo->update_flag = 0;
}
else if (pinfo->prev_world) {
+ pinfo->update_world |= PROBE_UPDATE_ALL;
+ pinfo->prev_wo_sh_compiled = false;
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. */
@@ -538,14 +576,10 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
{
psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR);
- struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
- DRWShadingGroup *grp = DRW_shgroup_instance_create(
- e_data.probe_planar_downsample_sh,
- psl->probe_planar_downsample_ps,
- geom, NULL);
- stl->g_data->planar_downsample = grp;
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps);
DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool);
DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
+ DRW_shgroup_call_instances_add(grp, DRW_cache_fullscreen_quad_get(), NULL, (unsigned int *)&pinfo->num_planar);
}
}
@@ -554,14 +588,34 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
EEVEE_LightProbesInfo *pinfo = sldata->probes;
LightProbe *probe = (LightProbe *)ob->data;
- /* Step 1 find all lamps in the scene and setup them */
if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) ||
- (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE))
+ (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) ||
+ (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_grid >= MAX_PLANAR))
{
printf("Too much probes in the scene !!!\n");
return;
}
+ if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
+ /* See if this planar probe is inside the view frustum. If not, no need to update it. */
+ /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */
+ BoundBox bbox; float tmp[4][4];
+ const float min[3] = {-1.0f, -1.0f, -1.0f};
+ const float max[3] = { 1.0f, 1.0f, 1.0f};
+ BKE_boundbox_init_from_minmax(&bbox, min, max);
+
+ copy_m4_m4(tmp, ob->obmat);
+ normalize_v3(tmp[2]);
+ mul_v3_fl(tmp[2], probe->distinf);
+
+ for (int v = 0; v < 8; ++v) {
+ mul_m4_v3(tmp, bbox.vec[v]);
+ }
+ if (!DRW_culling_box_test(&bbox)) {
+ return; /* Culled */
+ }
+ }
+
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
@@ -586,7 +640,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
}
}
- if (e_data.update_world) {
+ if (pinfo->update_world) {
ped->need_update = true;
ped->updated_cells = 0;
ped->updated_lvl = 0;
@@ -595,18 +649,20 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
pinfo->do_cube_update |= ped->need_update;
- if (probe->type == LIGHTPROBE_TYPE_CUBE) {
- pinfo->probes_cube_ref[pinfo->num_cube] = ob;
- pinfo->num_cube++;
- }
- else if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
- pinfo->probes_planar_ref[pinfo->num_planar] = ob;
- pinfo->num_planar++;
- }
- else { /* GRID */
- pinfo->probes_grid_ref[pinfo->num_grid] = ob;
- pinfo->num_grid++;
- pinfo->total_irradiance_samples += ped->num_cell;
+ switch (probe->type) {
+ case LIGHTPROBE_TYPE_CUBE:
+ pinfo->probes_cube_ref[pinfo->num_cube] = ob;
+ pinfo->num_cube++;
+ break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ pinfo->probes_planar_ref[pinfo->num_planar] = ob;
+ pinfo->num_planar++;
+ break;
+ case LIGHTPROBE_TYPE_GRID:
+ pinfo->probes_grid_ref[pinfo->num_grid] = ob;
+ pinfo->num_grid++;
+ pinfo->total_irradiance_samples += ped->num_cell;
+ break;
}
}
@@ -617,15 +673,34 @@ static void scale_m4_v3(float R[4][4], float v[3])
mul_v3_v3(R[i], v);
}
-static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl)
+static void EEVEE_planar_reflections_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+
+ for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
+ LightProbe *probe = (LightProbe *)ob->data;
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+
+ ped->probe_id = i;
+
+ /* Debug Display */
+ 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);
+ }
+ }
+}
+
+static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
Object *ob;
float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4];
- float viewmat[4][4], winmat[4][4];
+ float viewmat[4][4];
DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
- DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
zero_m4(rangemat);
rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f;
@@ -637,36 +712,27 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_
LightProbe *probe = (LightProbe *)ob->data;
EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
-
/* Computing mtx : matrix that mirror position around object's XY plane. */
normalize_m4_m4(normat, ob->obmat); /* object > world */
invert_m4_m4(imat, normat); /* world > object */
-
float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */
scale_m4_v3(imat, reflect); /* world > object > mirrored obj */
mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */
-
/* Reflect Camera Matrix. */
- mul_m4_m4m4(ped->viewmat, viewmat, mtx);
-
+ mul_m4_m4m4(ped->mats.mat[DRW_MAT_VIEW], viewmat, mtx);
/* TODO FOV margin */
- float winmat_fov[4][4];
- copy_m4_m4(winmat_fov, winmat);
-
- /* Apply Perspective Matrix. */
- mul_m4_m4m4(ped->persmat, winmat_fov, ped->viewmat);
-
+ /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */
+ DRW_viewport_matrix_get(ped->mats.mat[DRW_MAT_WIN], DRW_MAT_WIN);
+ /* Apply Projection Matrix. */
+ mul_m4_m4m4(ped->mats.mat[DRW_MAT_PERS], ped->mats.mat[DRW_MAT_WIN], ped->mats.mat[DRW_MAT_VIEW]);
/* This is the matrix used to reconstruct texture coordinates.
* We use the original view matrix because it does not create
* visual artifacts if receiver is not perfectly aligned with
* the planar reflection probe. */
- mul_m4_m4m4(eplanar->reflectionmat, winmat_fov, viewmat); /* TODO FOV margin */
+ mul_m4_m4m4(eplanar->reflectionmat, ped->mats.mat[DRW_MAT_WIN], viewmat); /* TODO FOV margin */
/* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat);
- /* TODO frustum check. */
- ped->need_update = true;
-
/* Compute clip plane equation / normal. */
float refpoint[3];
copy_v3_v3(eplanar->plane_equation, ob->obmat[2]);
@@ -711,13 +777,6 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_
float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf;
eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist);
eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
-
- /* Debug Display */
- 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);
- }
}
}
@@ -846,12 +905,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
if (DRW_state_draw_support() &&
(probe->flag & LIGHTPROBE_FLAG_SHOW_DATA))
{
- struct Gwn_Batch *geom = DRW_cache_sphere_get();
- DRWShadingGroup *grp = DRW_shgroup_instance_create(
- e_data.probe_grid_display_sh,
- psl->probe_display,
- geom, NULL);
- DRW_shgroup_set_instance_count(grp, ped->num_cell);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_display_sh, psl->probe_display);
DRW_shgroup_uniform_int(grp, "offset", &egrid->offset, 1);
DRW_shgroup_uniform_ivec3(grp, "grid_resolution", egrid->resolution, 1);
DRW_shgroup_uniform_vec3(grp, "corner", egrid->corner, 1);
@@ -860,6 +914,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
DRW_shgroup_uniform_vec3(grp, "increment_z", egrid->increment_z, 1);
DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
DRW_shgroup_uniform_float(grp, "sphere_size", &probe->data_draw_size, 1);
+ DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, (unsigned int *)&ped->num_cell);
}
}
}
@@ -867,7 +922,6 @@ 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;
@@ -875,6 +929,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
/* Free textures if number mismatch. */
if (pinfo->num_cube != pinfo->cache_num_cube) {
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
+ pinfo->cache_num_cube = pinfo->num_cube;
}
if (pinfo->num_planar != pinfo->cache_num_planar) {
@@ -898,21 +953,18 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
/* XXX this should be run each frame as it ensure planar_depth is set */
planar_pool_ensure_alloc(vedata, pinfo->num_planar);
- /* Setup planar filtering pass */
- DRW_shgroup_set_instance_count(stl->g_data->planar_downsample, pinfo->num_planar);
-
if (!sldata->probe_pool) {
sldata->probe_pool = DRW_texture_create_2D_array(pinfo->cubemap_res, pinfo->cubemap_res, max_ff(1, pinfo->num_cube),
DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
if (sldata->probe_filter_fb) {
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
}
-
/* Tag probes to refresh */
- e_data.update_world |= PROBE_UPDATE_CUBE;
- common_data->prb_num_render_cube = 0;
- pinfo->cache_num_cube = pinfo->num_cube;
+ pinfo->update_world |= PROBE_UPDATE_CUBE;
+ }
+ if ((pinfo->update_world & PROBE_UPDATE_CUBE) != 0) {
+ common_data->prb_num_render_cube = 0;
for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
ped->need_update = true;
@@ -942,11 +994,14 @@ 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);
}
- common_data->prb_num_render_grid = 0;
- pinfo->updated_bounce = 0;
+ /* Tag probes to refresh */
+ pinfo->update_world |= PROBE_UPDATE_GRID;
pinfo->grid_initialized = false;
- e_data.update_world |= PROBE_UPDATE_GRID;
+ }
+ if ((pinfo->update_world & PROBE_UPDATE_GRID) != 0) {
+ common_data->prb_num_render_grid = 0;
+ pinfo->updated_bounce = 0;
for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
ped->need_update = true;
@@ -959,12 +1014,12 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
common_data->prb_num_render_grid = pinfo->num_grid;
}
+ EEVEE_planar_reflections_cache_finish(sldata, vedata->stl);
+
EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl);
- EEVEE_planar_reflections_updates(sldata, vedata->stl);
DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
}
static void downsample_planar(void *vedata, int level)
@@ -1152,8 +1207,15 @@ 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];
+ DRWMatrixState matstate;
+ float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW];
+ float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV];
+ float (*persmat)[4] = matstate.mat[DRW_MAT_PERS];
+ float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV];
+ float (*winmat)[4] = matstate.mat[DRW_MAT_WIN];
+ float (*wininv)[4] = matstate.mat[DRW_MAT_WININV];
+ float posmat[4][4];
unit_m4(posmat);
/* Move to capture position */
@@ -1182,9 +1244,6 @@ static void render_scene_to_probe(
DRW_framebuffer_texture_detach(sldata->probe_rt);
DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
for (int i = 0; i < 6; ++i) {
- float viewmat[4][4], persmat[4][4];
- float viewinv[4][4], persinv[4][4];
-
/* Setup custom matrices */
mul_m4_m4m4(viewmat, cubefacemat[i], posmat);
mul_m4_m4m4(persmat, winmat, viewmat);
@@ -1192,12 +1251,7 @@ static void render_scene_to_probe(
invert_m4_m4(viewinv, viewmat);
invert_m4_m4(wininv, winmat);
- DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
- DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
- DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
- DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
- DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set_all(&matstate);
/* Be sure that cascaded shadow maps are updated. */
EEVEE_draw_shadows(sldata, psl);
@@ -1230,13 +1284,6 @@ static void render_scene_to_probe(
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0);
- DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
- DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
- DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
- DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
- DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
-
/* Restore */
txl->planar_pool = tmp_planar_pool;
stl->g_data->minzbuffer = tmp_minz;
@@ -1245,32 +1292,35 @@ static void render_scene_to_probe(
static void render_scene_to_planar(
EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int layer,
- float (*viewmat)[4], float (*persmat)[4],
- float clip_plane[4])
+ EEVEE_LightProbeEngineData *ped)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
- float viewinv[4][4];
- float persinv[4][4];
+ float (*viewmat)[4] = ped->mats.mat[DRW_MAT_VIEW];
+ float (*viewinv)[4] = ped->mats.mat[DRW_MAT_VIEWINV];
+ float (*persmat)[4] = ped->mats.mat[DRW_MAT_PERS];
+ float (*persinv)[4] = ped->mats.mat[DRW_MAT_PERSINV];
+ float (*winmat)[4] = ped->mats.mat[DRW_MAT_WIN];
+ float (*wininv)[4] = ped->mats.mat[DRW_MAT_WININV];
invert_m4_m4(viewinv, viewmat);
invert_m4_m4(persinv, persmat);
+ invert_m4_m4(wininv, winmat);
- DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
- DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
- DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
-
- /* Since we are rendering with an inverted view matrix, we need
- * to invert the facing for backface culling to be the same. */
- DRW_state_invert_facing();
+ DRW_viewport_matrix_override_set_all(&ped->mats);
/* Be sure that cascaded shadow maps are updated. */
EEVEE_draw_shadows(sldata, psl);
- DRW_state_clip_planes_add(clip_plane);
+ /* Since we are rendering with an inverted view matrix, we need
+ * to invert the facing for backface culling to be the same. */
+ DRW_state_invert_facing();
+ /* Set clipping plan */
+ copy_v4_v4(sldata->clip_data.clip_planes[0], ped->planer_eq_offset);
+ DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data);
+ DRW_state_clip_planes_count_set(1);
/* Attach depth here since it's a DRW_TEX_TEMP */
DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_depth, 0, layer, 0);
@@ -1286,9 +1336,14 @@ static void render_scene_to_planar(
txl->planar_pool = e_data.planar_pool_placeholder;
txl->planar_depth = e_data.depth_array_placeholder;
+ /* Slight modification: we handle refraction as normal
+ * shading and don't do SSRefraction. */
+
/* Depth prepass */
DRW_draw_pass(psl->depth_pass_clip);
DRW_draw_pass(psl->depth_pass_clip_cull);
+ DRW_draw_pass(psl->refract_depth_pass);
+ DRW_draw_pass(psl->refract_depth_pass_cull);
/* Background */
DRW_draw_pass(psl->probe_background);
@@ -1305,6 +1360,14 @@ static void render_scene_to_planar(
EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
+ DRW_draw_pass(psl->refract_pass);
+
+ /* Transparent */
+ if (DRW_state_is_image_render()) {
+ /* Do the reordering only for offline because it can be costly. */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
+ }
+ DRW_draw_pass(psl->transparent_pass);
DRW_state_invert_facing();
DRW_state_clip_planes_reset();
@@ -1312,10 +1375,6 @@ static void render_scene_to_planar(
/* Restore */
txl->planar_pool = tmp_planar_pool;
txl->planar_depth = tmp_planar_depth;
- DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
- DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
- DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
DRW_framebuffer_texture_detach(txl->planar_pool);
DRW_framebuffer_texture_detach(txl->planar_depth);
@@ -1324,9 +1383,14 @@ static void render_scene_to_planar(
static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- float winmat[4][4], wininv[4][4];
+ DRWMatrixState matstate;
+ float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW];
+ float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV];
+ float (*persmat)[4] = matstate.mat[DRW_MAT_PERS];
+ float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV];
+ float (*winmat)[4] = matstate.mat[DRW_MAT_WIN];
+ float (*wininv)[4] = matstate.mat[DRW_MAT_WININV];
- /* 1 - Render to cubemap target using geometry shader. */
/* For world probe, we don't need to clear since we render the background directly. */
pinfo->layer = 0;
@@ -1338,24 +1402,15 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p
DRW_framebuffer_texture_detach(sldata->probe_rt);
DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
for (int i = 0; i < 6; ++i) {
- float viewmat[4][4], persmat[4][4];
- float viewinv[4][4], persinv[4][4];
-
- DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0);
- DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size);
-
/* Setup custom matrices */
copy_m4_m4(viewmat, cubefacemat[i]);
mul_m4_m4m4(persmat, winmat, viewmat);
invert_m4_m4(persinv, persmat);
invert_m4_m4(viewinv, viewmat);
+ DRW_viewport_matrix_override_set_all(&matstate);
- DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
- DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
- DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
- DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
- DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV);
+ DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0);
+ DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size);
DRW_draw_pass(psl->probe_background);
@@ -1363,13 +1418,6 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p
}
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0);
-
- DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
- DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
- DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
- DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
- DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
- DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
}
static void lightprobe_cell_grid_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_local_cell[3])
@@ -1396,14 +1444,20 @@ 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_LightProbesInfo *pinfo = sldata->probes;
EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ DRWMatrixState saved_mats;
+
+ /* We need to save the Matrices before overidding them */
+ DRW_viewport_matrix_get_all(&saved_mats);
render_world_to_probe(sldata, psl);
- if (e_data.update_world & PROBE_UPDATE_CUBE) {
+ if (pinfo->update_world & PROBE_UPDATE_CUBE) {
glossy_filter_probe(sldata, vedata, psl, 0, 1.0);
common_data->prb_num_render_cube = 1;
}
- if (e_data.update_world & PROBE_UPDATE_GRID) {
+ if (pinfo->update_world & PROBE_UPDATE_GRID) {
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);
@@ -1412,9 +1466,16 @@ static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
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;
+ /* Reset volume history. */
+ stl->effects->volume_current_sample = -1;
+ common_data->vol_history_alpha = 0.0f;
}
- e_data.update_world = 0;
+ pinfo->update_world = 0;
DRW_viewport_request_redraw();
+ /* Do not let this frame accumulate. */
+ stl->effects->taa_current_sample = 1;
+
+ DRW_viewport_matrix_override_set_all(&saved_mats);
}
static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
@@ -1449,17 +1510,24 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
EEVEE_TextureList *txl = vedata->txl;
Object *ob;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ DRWMatrixState saved_mats;
if (pinfo->num_planar == 0) {
/* Disable SSR if we cannot read previous frame */
common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer;
+ common_data->prb_num_planar = 0;
return;
}
+ EEVEE_planar_reflections_updates(sldata);
+ DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
+
+ /* We need to save the Matrices before overidding them */
+ DRW_viewport_matrix_get_all(&saved_mats);
+
/* 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;
@@ -1467,12 +1535,7 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
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;
- }
- render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
- ped->need_update = false;
- ped->probe_id = i;
+ render_scene_to_planar(sldata, vedata, i, ped);
}
/* Restore */
@@ -1480,8 +1543,8 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
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) {
+ /* Prefilter for SSR */
+ if ((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);
@@ -1490,6 +1553,13 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_stats_group_end();
}
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+
+ if (DRW_state_is_image_render()) {
+ /* Sort transparents because planar reflections could have re-sorted them. */
+ DRW_pass_sort_shgroup_z(vedata->psl->transparent_pass);
+ }
+
/* Disable SSR if we cannot read previous frame */
common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer;
}
@@ -1521,7 +1591,6 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
DRW_viewport_request_redraw();
/* Do not let this frame accumulate. */
stl->effects->taa_current_sample = 1;
-
/* Only do one probe per frame */
return;
}
@@ -1546,6 +1615,9 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
return;
}
}
+ /* We need to save the Matrices before overidding them */
+ DRWMatrixState saved_mats;
+ DRW_viewport_matrix_get_all(&saved_mats);
/* Make sure grid is initialized. */
lightprobes_refresh_initialize_grid(sldata, vedata);
/* Reflection probes depend on diffuse lighting thus on irradiance grid,
@@ -1645,6 +1717,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;
+ /* Reset volume history. */
+ stl->effects->volume_current_sample = -1;
+ common_data->vol_history_alpha = 0.0f;
+ /* Restore matrices */
+ DRW_viewport_matrix_override_set_all(&saved_mats);
return;
}
@@ -1673,6 +1750,8 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
}
/* Refresh cube probe when needed. */
lightprobes_refresh_cube(sldata, vedata);
+ /* Restore matrices */
+ DRW_viewport_matrix_override_set_all(&saved_mats);
}
bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
@@ -1688,6 +1767,7 @@ bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data
void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
/* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
common_data->spec_toggle = false;
@@ -1701,10 +1781,10 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->ao_dist = 0.0f;
/* Render world in priority */
- if (e_data.update_world) {
+ if (pinfo->update_world) {
lightprobes_refresh_world(sldata, vedata);
}
- else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false) {
+ else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false && pinfo->all_materials_updated) {
lightprobes_refresh_all_no_world(sldata, vedata);
}
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 582f7ea747a..b4afb8bb555 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -26,6 +26,7 @@
#include "DRW_render.h"
#include "BLI_dynstr.h"
+#include "BLI_rect.h"
#include "BKE_object.h"
@@ -205,9 +206,11 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
}
}
-void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
+void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
linfo->shcaster_frontbuffer->count = 0;
linfo->num_light = 0;
@@ -271,15 +274,11 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
}
{
- psl->shadow_cube_pass = DRW_pass_create(
- "Shadow Cube Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- }
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ psl->shadow_pass = DRW_pass_create("Shadow Pass", state);
- {
- psl->shadow_cascade_pass = DRW_pass_create(
- "Shadow Cascade Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWShadingGroup *grp = stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
}
}
@@ -378,24 +377,20 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Add a shadow caster to the shadowpasses */
void EEVEE_lights_cache_shcaster_add(
- EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct Gwn_Batch *geom, float (*obmat)[4])
+ EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, struct Gwn_Batch *geom, Object *ob)
{
- DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cube_pass, geom, NULL);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
- DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
- DRW_shgroup_set_instance_count(grp, 6);
-
- grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cascade_pass, geom, NULL);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
- DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
- DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM);
+ DRW_shgroup_call_object_instances_add(
+ stl->g_data->shadow_shgrp,
+ geom, ob,
+ &sldata->lamps->shadow_instance_count);
}
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)
{
- DRWShadingGroup *grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cube_pass, geom, ob, NULL);
+ /* TODO / PERF : reuse the same shading group for objects with the same material */
+ DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
if (grp == NULL) return;
@@ -405,16 +400,7 @@ void EEVEE_lights_cache_shcaster_material_add(
if (alpha_threshold != NULL)
DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
- DRW_shgroup_set_instance_count(grp, 6);
-
- grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cascade_pass, geom, ob, NULL);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
- DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
-
- if (alpha_threshold != NULL)
- DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
-
- DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM);
+ DRW_shgroup_call_object_instances_add(grp, geom, ob, &sldata->lamps->shadow_instance_count);
}
/* Make that object update shadow casting lamps inside its influence bounding box. */
@@ -653,9 +639,15 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La
#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
-static void frustum_min_bounding_sphere(const float corners[8][4], float r_center[3], float *r_radius)
+static double round_to_digits(double value, int digits)
+{
+ double factor = pow(10.0, digits - ceil(log10(fabs(value))));
+ return round(value * factor) / factor;
+}
+
+static void frustum_min_bounding_sphere(const float corners[8][3], float r_center[3], float *r_radius)
{
-#if 0 /* Simple solution but waist too much space. */
+#if 0 /* Simple solution but waste too much space. */
float minvec[3], maxvec[3];
/* compute the bounding box */
@@ -669,19 +661,27 @@ static void frustum_min_bounding_sphere(const float corners[8][4], float r_cente
add_v3_v3v3(r_center, minvec, maxvec);
mul_v3_fl(r_center, 0.5f);
#else
- /* Make the bouding sphere always centered on the front diagonal */
- add_v3_v3v3(r_center, corners[4], corners[7]);
- mul_v3_fl(r_center, 0.5f);
- *r_radius = len_v3v3(corners[0], r_center);
+ /* Find averaged center. */
+ zero_v3(r_center);
+ for (int i = 0; i < 8; ++i) {
+ add_v3_v3(r_center, corners[i]);
+ }
+ mul_v3_fl(r_center, 1.0f / 8.0f);
- /* Search the largest distance between the sphere center
- * and the front plane corners. */
- for (int i = 0; i < 4; ++i) {
- float rad = len_v3v3(corners[4 + i], r_center);
+ /* Search the largest distance from the sphere center. */
+ *r_radius = 0.0f;
+ for (int i = 0; i < 8; ++i) {
+ float rad = len_squared_v3v3(corners[i], r_center);
if (rad > *r_radius) {
*r_radius = rad;
}
}
+
+ /* TODO try to reduce the radius further by moving the center.
+ * Remember we need a __stable__ solution! */
+
+ /* Try to reduce float imprecision leading to shimmering. */
+ *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
#endif
}
@@ -711,7 +711,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
}
/* Lamps Matrices */
- float viewmat[4][4], projmat[4][4];
+ float (*viewmat)[4], projmat[4][4];
int sh_nbr = 1; /* TODO : MSM */
int cascade_nbr = la->cascade_count;
@@ -720,6 +720,13 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
+ /* obmat = Object Space > World Space */
+ /* viewmat = World Space > View Space */
+ invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_VIEW], ob->obmat);
+ viewmat = sh_data->clipmat.mat[DRW_MAT_VIEW];
+ normalize_m4(viewmat);
+ invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_VIEWINV], viewmat);
+
/* The technique consists into splitting
* the view frustum into several sub-frustum
* that are individually receiving one shadow map */
@@ -818,50 +825,41 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
cascade_data->split_start[0] = LERP(la->cascade_fade, cascade_data->split_end[cascade_nbr - 1], prev_split);
/* For each cascade */
+ rctf rect_clip, rect_cascade;
for (int c = 0; c < cascade_nbr; ++c) {
/* Given 8 frustum corners */
- float corners[8][4] = {
+ float corners[8][3] = {
/* Near Cap */
- {-1.0f, -1.0f, splits_start_ndc[c], 1.0f},
- { 1.0f, -1.0f, splits_start_ndc[c], 1.0f},
- {-1.0f, 1.0f, splits_start_ndc[c], 1.0f},
- { 1.0f, 1.0f, splits_start_ndc[c], 1.0f},
+ {-1.0f, -1.0f, splits_start_ndc[c]},
+ { 1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, 1.0f, splits_start_ndc[c]},
+ { 1.0f, 1.0f, splits_start_ndc[c]},
/* Far Cap */
- {-1.0f, -1.0f, splits_end_ndc[c], 1.0f},
- { 1.0f, -1.0f, splits_end_ndc[c], 1.0f},
- {-1.0f, 1.0f, splits_end_ndc[c], 1.0f},
- { 1.0f, 1.0f, splits_end_ndc[c], 1.0f}
+ {-1.0f, -1.0f, splits_end_ndc[c]},
+ { 1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, 1.0f, splits_end_ndc[c]},
+ { 1.0f, 1.0f, splits_end_ndc[c]}
};
/* Transform them into world space */
for (int i = 0; i < 8; ++i) {
- mul_m4_v4(persinv, corners[i]);
- mul_v3_fl(corners[i], 1.0f / corners[i][3]);
- corners[i][3] = 1.0f;
- }
-
-
- /* Project them into light space */
- invert_m4_m4(viewmat, ob->obmat);
- normalize_v3(viewmat[0]);
- normalize_v3(viewmat[1]);
- normalize_v3(viewmat[2]);
-
- for (int i = 0; i < 8; ++i) {
- mul_m4_v4(viewmat, corners[i]);
+ mul_project_m4_v3(persinv, corners[i]);
}
float center[3];
frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c]));
+ /* Project into lightspace */
+ mul_mat3_m4_v3(viewmat, center);
+
/* Snap projection center to nearest texel to cancel shimmering. */
float shadow_origin[2], shadow_texco[2];
/* Light to texture space. */
mul_v2_v2fl(shadow_origin, center, linfo->shadow_size / (2.0f * sh_data->radius[c]));
/* Find the nearest texel. */
- shadow_texco[0] = round(shadow_origin[0]);
- shadow_texco[1] = round(shadow_origin[1]);
+ shadow_texco[0] = roundf(shadow_origin[0]);
+ shadow_texco[1] = roundf(shadow_origin[1]);
/* Compute offset. */
sub_v2_v2(shadow_texco, shadow_origin);
@@ -871,17 +869,32 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
add_v2_v2(center, shadow_texco);
/* Expand the projection to cover frustum range */
+ BLI_rctf_init_pt_radius(&rect_cascade, center, sh_data->radius[c]);
orthographic_m4(projmat,
- center[0] - sh_data->radius[c],
- center[0] + sh_data->radius[c],
- center[1] - sh_data->radius[c],
- center[1] + sh_data->radius[c],
+ rect_cascade.xmin, rect_cascade.xmax,
+ rect_cascade.ymin, rect_cascade.ymax,
la->clipsta, la->clipend);
+ if (c == 0) {
+ memcpy(&rect_clip, &rect_cascade, sizeof(rect_clip));
+ }
+ else {
+ BLI_rctf_union(&rect_clip, &rect_cascade);
+ }
+
mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat);
mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]);
}
+ /* Clipping mats */
+ orthographic_m4(sh_data->clipmat.mat[DRW_MAT_WIN],
+ rect_clip.xmin, rect_clip.xmax,
+ rect_clip.ymin, rect_clip.ymax,
+ la->clipsta, la->clipend);
+ mul_m4_m4m4(sh_data->clipmat.mat[DRW_MAT_PERS], sh_data->clipmat.mat[DRW_MAT_WIN], viewmat);
+ invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_WININV], sh_data->clipmat.mat[DRW_MAT_WIN]);
+ invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_PERSINV], sh_data->clipmat.mat[DRW_MAT_PERS]);
+
ubo_data->bias = 0.05f * la->bias;
ubo_data->near = la->clipsta;
ubo_data->far = la->clipend;
@@ -983,6 +996,37 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
}
}
+static void eevee_shadows_cube_culling_frustum(EEVEE_ShadowRender *srd)
+{
+ float persmat[4][4], persinv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float winmat[4][4], wininv[4][4];
+ orthographic_m4(winmat, -srd->clip_far, srd->clip_far, -srd->clip_far, srd->clip_far, -srd->clip_far, srd->clip_far);
+ DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
+
+ invert_m4_m4(wininv, winmat);
+ DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV);
+
+ unit_m4(viewmat);
+ negate_v3_v3(viewmat[3], srd->position);
+ DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
+
+ unit_m4(viewinv);
+ copy_v3_v3(viewinv[3], srd->position);
+ DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
+
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
+
+ invert_m4_m4(persinv, persmat);
+ DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
+}
+
+static void eevee_shadows_cascade_culling_frustum(EEVEE_ShadowCascadeData *evscd)
+{
+ DRW_viewport_matrix_override_set_all(&evscd->clipmat);
+}
+
/* this refresh lamps shadow buffers */
void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
{
@@ -991,6 +1035,11 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
int i;
float clear_col[4] = {FLT_MAX};
+ DRWMatrixState saved_mats;
+
+ /* We need to save the Matrices before overidding them */
+ DRW_viewport_matrix_get_all(&saved_mats);
+
/* Cube Shadow Maps */
DRW_stats_group_start("Cube Shadow Maps");
DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0);
@@ -999,9 +1048,6 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
Lamp *la = (Lamp *)ob->data;
- float cube_projmat[4][4];
- perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
-
if (!led->need_update) {
continue;
}
@@ -1009,25 +1055,30 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
EEVEE_ShadowCubeData *evscd = &led->data.scd;
+ float cube_projmat[4][4];
+ float cube_viewmat[4][4];
+ perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
+ unit_m4(cube_viewmat);
+
srd->clip_near = la->clipsta;
srd->clip_far = la->clipend;
copy_v3_v3(srd->position, ob->obmat[3]);
- for (int j = 0; j < 6; j++) {
- float tmp[4][4];
-
- unit_m4(tmp);
- negate_v3_v3(tmp[3], ob->obmat[3]);
- mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp);
+ negate_v3_v3(cube_viewmat[3], srd->position);
+ for (int j = 0; j < 6; j++) {
+ mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], cube_viewmat);
mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]);
}
DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+ eevee_shadows_cube_culling_frustum(srd);
+
DRW_framebuffer_bind(sldata->shadow_target_fb);
DRW_framebuffer_clear(true, true, false, clear_col, 1.0f);
/* Render shadow cube */
- DRW_draw_pass(psl->shadow_cube_pass);
+ linfo->shadow_instance_count = 6;
+ DRW_draw_pass(psl->shadow_pass);
/* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */
float filter_texture_size = la->soft * 0.001f;
@@ -1078,6 +1129,8 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
DRW_framebuffer_texture_detach(sldata->shadow_cube_target);
DRW_stats_group_end();
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+
/* Cascaded Shadow Maps */
DRW_stats_group_start("Cascaded Shadow Maps");
DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cascade_target, 0, 0);
@@ -1100,8 +1153,11 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
DRW_framebuffer_bind(sldata->shadow_target_fb);
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+ eevee_shadows_cascade_culling_frustum(evscd);
+
/* Render shadow cascades */
- DRW_draw_pass(psl->shadow_cascade_pass);
+ linfo->shadow_instance_count = la->cascade_count;
+ DRW_draw_pass(psl->shadow_pass);
/* TODO: OPTI: Filter all cascade in one/two draw call */
for (linfo->current_shadow_cascade = 0;
@@ -1151,6 +1207,8 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
DRW_framebuffer_texture_detach(sldata->shadow_cascade_target);
DRW_stats_group_end();
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+
DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 0e444039573..6215445e113 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -47,6 +47,7 @@
/* *********** STATIC *********** */
static struct {
+ char *shadow_shader_lib;
char *frag_shader_lib;
char *volume_shader_lib;
@@ -81,6 +82,7 @@ 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_common_view_lib_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_lit_surface_frag_glsl[];
@@ -363,6 +365,7 @@ static void add_standard_uniforms(
DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo);
/* TODO if glossy or diffuse bsdf */
if (true) {
@@ -531,7 +534,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E
char *frag_str = NULL;
/* Shaders */
- e_data.frag_shader_lib = BLI_string_joinN(
+ e_data.shadow_shader_lib = BLI_string_joinN(
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_sampling_lib_glsl,
@@ -555,7 +558,12 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E
datatoc_lit_surface_frag_glsl,
datatoc_volumetric_lib_glsl);
+ e_data.frag_shader_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ e_data.shadow_shader_lib);
+
e_data.volume_shader_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_ambient_occlusion_lib_glsl,
@@ -626,12 +634,12 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
const void *engine = &DRW_engine_viewport_eevee_type;
const int options = VAR_WORLD_PROBE;
- GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options);
if (mat != NULL) {
return mat;
}
- return GPU_material_from_nodetree(
- scene, wo->nodetree, &wo->gpumaterial, engine, options,
+ return DRW_shader_create_from_world(
+ scene, wo, engine, options,
datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
SHADER_DEFINES "#define PROBE_CAPTURE\n");
}
@@ -641,12 +649,12 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_WORLD_BACKGROUND;
- GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options);
if (mat != NULL) {
return mat;
}
- return GPU_material_from_nodetree(
- scene, wo->nodetree, &wo->gpumaterial, engine, options,
+ return DRW_shader_create_from_world(
+ scene, wo, engine, options,
datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
SHADER_DEFINES "#define WORLD_BACKGROUND\n");
}
@@ -656,15 +664,15 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_WORLD_VOLUME;
- GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options);
if (mat != NULL) {
return mat;
}
char *defines = eevee_get_volume_defines(options);
- mat = GPU_material_from_nodetree(
- scene, wo->nodetree, &wo->gpumaterial, engine, options,
+ mat = DRW_shader_create_from_world(
+ scene, wo, engine, options,
datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib,
defines);
@@ -691,15 +699,15 @@ struct GPUMaterial *EEVEE_material_mesh_get(
options |= eevee_material_shadow_option(shadow_method);
- GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
if (mat) {
return mat;
}
char *defines = eevee_get_defines(options);
- mat = GPU_material_from_nodetree(
- scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib,
defines);
@@ -713,15 +721,15 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_VOLUME;
- GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
if (mat != NULL) {
return mat;
}
char *defines = eevee_get_volume_defines(options);
- mat = GPU_material_from_nodetree(
- scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib,
defines);
@@ -747,7 +755,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(
if (is_shadow)
options |= VAR_MAT_SHADOW;
- GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
if (mat) {
return mat;
}
@@ -755,11 +763,11 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(
char *defines = eevee_get_defines(options);
char *frag_str = BLI_string_joinN(
- e_data.frag_shader_lib,
+ (is_shadow) ? e_data.shadow_shader_lib : e_data.frag_shader_lib,
datatoc_prepass_frag_glsl);
- mat = GPU_material_from_nodetree(
- scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
(is_shadow) ? datatoc_shadow_vert_glsl : datatoc_lit_surface_vert_glsl,
(is_shadow) ? datatoc_shadow_geom_glsl : NULL,
frag_str,
@@ -779,15 +787,15 @@ struct GPUMaterial *EEVEE_material_hair_get(
options |= eevee_material_shadow_option(shadow_method);
- GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options);
if (mat) {
return mat;
}
char *defines = eevee_get_defines(options);
- mat = GPU_material_from_nodetree(
- scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib,
defines);
@@ -850,13 +858,15 @@ 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]);
+ /* XXX / WATCH: This creates non persistent binds for the ubos and textures.
+ * But it's currently OK because the following shgroups does not add any bind. */
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]);
}
-void EEVEE_materials_cache_init(EEVEE_Data *vedata)
+void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
@@ -883,17 +893,25 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
col = &wo->horr;
if (wo->use_nodes && wo->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo);
- grp = DRW_shgroup_material_create(gpumat, psl->background_pass);
- if (grp) {
- DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- DRW_shgroup_call_add(grp, geom, NULL);
- }
- else {
- /* Shader failed : pink background */
- static float pink[3] = {1.0f, 0.0f, 1.0f};
- col = pink;
+ switch (GPU_material_status(gpumat)) {
+ case GPU_MAT_SUCCESS:
+ grp = DRW_shgroup_material_create(gpumat, psl->background_pass);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ break;
+ case GPU_MAT_QUEUED:
+ sldata->probes->all_materials_updated = false;
+ /* TODO Bypass probe compilation. */
+ col = compile_col;
+ break;
+ case GPU_MAT_FAILED:
+ default:
+ col = error_col;
+ break;
}
}
}
@@ -919,10 +937,12 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
psl->depth_pass_clip = DRW_pass_create("Depth Pass Clip", state);
stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip);
+ DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip, "clip_block", sldata->clip_ubo);
state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK;
psl->depth_pass_clip_cull = DRW_pass_create("Depth Pass Cull Clip", state);
stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip_cull);
+ DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo);
}
{
@@ -942,10 +962,12 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
psl->refract_depth_pass_clip = DRW_pass_create("Refract Depth Pass Clip", state);
stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip);
+ DRW_shgroup_uniform_block(stl->g_data->refract_depth_shgrp_clip, "clip_block", sldata->clip_ubo);
state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK;
psl->refract_depth_pass_clip_cull = DRW_pass_create("Refract Depth Pass Cull Clip", state);
stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull);
+ DRW_shgroup_uniform_block(stl->g_data->refract_depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo);
}
{
@@ -1035,60 +1057,29 @@ static void material_opaque(
}
if (use_gpumat) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
+ static float half = 0.5f;
+
/* Shading */
*gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, false, use_refract,
use_sss, use_translucency, linfo->shadow_method);
- *shgrp = DRW_shgroup_material_create(*gpumat,
- (use_refract) ? psl->refract_pass :
- (use_sss) ? psl->sss_pass : psl->material_pass);
- if (*shgrp) {
- static int no_ssr = -1;
- static int first_ssr = 1;
- 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;
- struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(*gpumat,
- stl->effects->sss_sample_count,
- &sss_tex_profile);
-
- if (sss_profile) {
- if (use_translucency) {
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
- }
-
- /* Limit of 8 bit stencil buffer. ID 255 is refraction. */
- if (e_data.sss_count < 254) {
- DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
- EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
- e_data.sss_count++;
- }
- else {
- /* TODO : display message. */
- printf("Error: Too many different Subsurface shader in the scene.\n");
- }
- }
- }
- }
- else {
- /* Shader failed : pink color */
- static float col[3] = {1.0f, 0.0f, 1.0f};
- static float half = 0.5f;
-
- color_p = col;
- metal_p = spec_p = rough_p = &half;
- }
+ GPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
/* Alpha CLipped : Discard pixel from depth pass, then
* fail the depth test for shading. */
if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) {
*gpumat_depth = EEVEE_material_mesh_depth_get(scene, ma,
- (ma->blend_method == MA_BM_HASHED), false);
+ (ma->blend_method == MA_BM_HASHED), false);
- if (use_refract) {
+ GPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth);
+ if (status_mat_depth != GPU_MAT_SUCCESS) {
+ /* Mixing both flags. If depth shader fails, show it to the user by not using
+ * the surface shader. */
+ status_mat_surface = status_mat_depth;
+ }
+ else if (use_refract) {
*shgrp_depth = DRW_shgroup_material_create(*gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass);
*shgrp_depth_clip = DRW_shgroup_material_create(*gpumat_depth, (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip);
}
@@ -1099,6 +1090,7 @@ static void material_opaque(
if (*shgrp_depth != NULL) {
add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false);
+ add_standard_uniforms(*shgrp_depth_clip, sldata, vedata, NULL, NULL, false, false);
if (ma->blend_method == MA_BM_CLIP) {
DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1);
@@ -1110,6 +1102,59 @@ static void material_opaque(
}
}
}
+
+ switch (status_mat_surface) {
+ case GPU_MAT_SUCCESS:
+ {
+ static int no_ssr = -1;
+ static int first_ssr = 1;
+ int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr;
+
+ *shgrp = DRW_shgroup_material_create(*gpumat,
+ (use_refract) ? psl->refract_pass :
+ (use_sss) ? psl->sss_pass : psl->material_pass);
+ add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false);
+
+ if (use_sss) {
+ struct GPUTexture *sss_tex_profile = NULL;
+ struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(*gpumat,
+ stl->effects->sss_sample_count,
+ &sss_tex_profile);
+
+ if (sss_profile) {
+ if (use_translucency) {
+ DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
+ }
+
+ /* Limit of 8 bit stencil buffer. ID 255 is refraction. */
+ if (e_data.sss_count < 254) {
+ DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
+ EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
+ e_data.sss_count++;
+ }
+ else {
+ /* TODO : display message. */
+ printf("Error: Too many different Subsurface shader in the scene.\n");
+ }
+ }
+ }
+ break;
+ }
+ case GPU_MAT_QUEUED:
+ {
+ sldata->probes->all_materials_updated = false;
+ /* TODO Bypass probe compilation. */
+ color_p = compile_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
}
/* Fallback to default shader */
@@ -1134,7 +1179,7 @@ static void material_opaque(
}
}
- emsg = MEM_mallocN(sizeof("EeveeMaterialShadingGroups"), "EeveeMaterialShadingGroups");
+ emsg = MEM_mallocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups");
emsg->shading_grp = *shgrp;
emsg->depth_grp = *shgrp_depth;
emsg->depth_clip_grp = *shgrp_depth_clip;
@@ -1159,23 +1204,37 @@ static void material_transparent(
float *rough_p = &ma->gloss_mir;
if (ma->use_nodes && ma->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
+ static float half = 0.5f;
+
/* Shading */
*gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract,
false, false, linfo->shadow_method);
- *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
- 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);
- }
- else {
- /* Shader failed : pink color */
- static float col[3] = {1.0f, 0.0f, 1.0f};
- static float half = 0.5f;
+ switch (GPU_material_status(*gpumat)) {
+ case GPU_MAT_SUCCESS:
+ {
+ static int ssr_id = -1; /* TODO transparent SSR */
+ bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
- color_p = col;
- metal_p = spec_p = rough_p = &half;
+ *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
+ add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend);
+ break;
+ }
+ case GPU_MAT_QUEUED:
+ {
+ sldata->probes->all_materials_updated = false;
+ /* TODO Bypass probe compilation. */
+ color_p = compile_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
}
}
@@ -1221,6 +1280,7 @@ static void material_transparent(
/* Depth prepass */
if (use_prepass) {
*shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+ DRW_shgroup_uniform_block(*shgrp_depth, "clip_block", sldata->clip_ubo);
cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
@@ -1232,8 +1292,8 @@ static void material_transparent(
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob)
{
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
GHash *material_hash = stl->g_data->material_hash;
@@ -1349,7 +1409,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
struct GPUMaterial *gpumat;
switch (ma->blend_shadow) {
case MA_BS_SOLID:
- EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat);
+ EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
break;
case MA_BS_CLIP:
gpumat = EEVEE_material_mesh_depth_get(scene, ma, false, true);
@@ -1365,7 +1425,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
}
}
else {
- EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat);
+ EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
}
}
}
@@ -1471,6 +1531,7 @@ void EEVEE_materials_free(void)
for (int i = 0; i < VAR_MAT_MAX; ++i) {
DRW_SHADER_FREE_SAFE(e_data.default_lit[i]);
}
+ MEM_SAFE_FREE(e_data.shadow_shader_lib);
MEM_SAFE_FREE(e_data.frag_shader_lib);
MEM_SAFE_FREE(e_data.volume_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh);
diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c
index ba9157a7f91..e221ed865b5 100644
--- a/source/blender/draw/engines/eevee/eevee_mist.c
+++ b/source/blender/draw/engines/eevee/eevee_mist.c
@@ -35,6 +35,7 @@
#include "eevee_private.h"
+extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_mist_frag_glsl[];
@@ -59,6 +60,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if (e_data.mist_sh == NULL) {
char *frag_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_effect_mist_frag_glsl);
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index 944003d7d1f..d7d022e9b98 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -44,6 +44,7 @@ static struct {
} e_data = {NULL}; /* Engine data */
extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_gtao_frag_glsl[];
@@ -51,6 +52,7 @@ extern char datatoc_effect_gtao_frag_glsl[];
static void eevee_create_shader_occlusion(void)
{
char *frag_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_ambient_occlusion_lib_glsl,
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 85d6dd8b448..88fb55cfbdf 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -107,18 +107,18 @@ enum {
VAR_MAT_BLEND = (1 << 4),
VAR_MAT_VSM = (1 << 5),
VAR_MAT_ESM = (1 << 6),
+ VAR_MAT_VOLUME = (1 << 7),
/* Max number of variation */
/* IMPORTANT : Leave it last and set
* it's value accordingly. */
- VAR_MAT_MAX = (1 << 7),
+ VAR_MAT_MAX = (1 << 8),
/* These are options that are not counted in VAR_MAT_MAX
* because they are not cumulative with the others above. */
- VAR_MAT_CLIP = (1 << 8),
- VAR_MAT_HASH = (1 << 9),
- VAR_MAT_MULT = (1 << 10),
- VAR_MAT_SHADOW = (1 << 11),
- VAR_MAT_REFRACT = (1 << 12),
- VAR_MAT_VOLUME = (1 << 13),
+ VAR_MAT_CLIP = (1 << 9),
+ VAR_MAT_HASH = (1 << 10),
+ VAR_MAT_MULT = (1 << 11),
+ VAR_MAT_SHADOW = (1 << 12),
+ VAR_MAT_REFRACT = (1 << 13),
VAR_MAT_SSS = (1 << 14),
VAR_MAT_TRANSLUC = (1 << 15),
VAR_MAT_SSSALBED = (1 << 16),
@@ -142,10 +142,8 @@ typedef struct EEVEE_BoundBox {
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
- struct DRWPass *shadow_cube_pass;
struct DRWPass *shadow_cube_copy_pass;
struct DRWPass *shadow_cube_store_pass;
- struct DRWPass *shadow_cascade_pass;
struct DRWPass *shadow_cascade_copy_pass;
struct DRWPass *shadow_cascade_store_pass;
@@ -367,6 +365,7 @@ typedef struct EEVEE_LampsInfo {
int shadow_cube_target_size;
int current_shadow_cascade;
int current_shadow_face;
+ unsigned int shadow_instance_count;
float filter_size;
/* List of lights in the scene. */
/* XXX This is fragile, can get out of sync quickly. */
@@ -442,7 +441,10 @@ typedef struct EEVEE_LightProbesInfo {
int target_size;
int grid_initialized;
struct World *prev_world;
+ int update_world;
+ bool prev_wo_sh_compiled;
bool do_cube_update;
+ bool all_materials_updated;
/* For rendering probes */
float probemat[6][4][4];
int layer;
@@ -514,6 +516,8 @@ typedef struct EEVEE_EffectsInfo {
float dof_bokeh[4];
float dof_layer_select[2];
int dof_target_size[2];
+ /* Other */
+ float prev_persmat[4][4];
/* Bloom */
int bloom_iteration_ct;
float source_texel_size[2];
@@ -600,6 +604,12 @@ typedef struct EEVEE_CommonUniformBuffer {
float prb_lod_planar_max; /* float */
} EEVEE_CommonUniformBuffer;
+/* ***************** CLIP PLANES DATA **************** */
+
+typedef struct EEVEE_ClipPlanesUniformBuffer {
+ float clip_planes[1][4]; /* must be less than MAX_CLIP_PLANES */
+} EEVEE_ClipPlanesUniformBuffer;
+
/* ************** SCENE LAYER DATA ************** */
typedef struct EEVEE_ViewLayerData {
/* Lamps */
@@ -640,6 +650,9 @@ typedef struct EEVEE_ViewLayerData {
/* Common Uniform Buffer */
struct EEVEE_CommonUniformBuffer common_data;
struct GPUUniformBuffer *common_ubo;
+
+ struct EEVEE_ClipPlanesUniformBuffer clip_data;
+ struct GPUUniformBuffer *clip_ubo;
} EEVEE_ViewLayerData;
/* ************ OBJECT DATA ************ */
@@ -654,6 +667,7 @@ typedef struct 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. */
+ DRWMatrixState clipmat; /* Override matrices used for clipping. */
float radius[MAX_CASCADE_NUM];
} EEVEE_ShadowCascadeData;
@@ -696,9 +710,7 @@ typedef struct EEVEE_LightProbeEngineData {
int max_lvl;
int probe_id; /* Only used for display data */
float probe_size; /* Only used for display data */
- /* For planar reflection rendering */
- float viewmat[4][4];
- float persmat[4][4];
+ DRWMatrixState mats; /* For planar probes */
float planer_eq_offset[4];
struct ListBase captured_object_list;
} EEVEE_LightProbeEngineData;
@@ -732,7 +744,6 @@ typedef struct EEVEE_PrivateData {
struct DRWShadingGroup *refract_depth_shgrp_clip_cull;
struct DRWShadingGroup *cube_display_shgrp;
struct DRWShadingGroup *planar_display_shgrp;
- struct DRWShadingGroup *planar_downsample;
struct GHash *material_hash;
struct GHash *hair_material_hash;
struct GPUTexture *minzbuffer;
@@ -765,7 +776,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_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl);
-void EEVEE_materials_cache_init(EEVEE_Data *vedata);
+void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob);
void EEVEE_materials_cache_finish(EEVEE_Data *vedata);
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
@@ -783,10 +794,10 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d
/* eevee_lights.c */
void EEVEE_lights_init(EEVEE_ViewLayerData *sldata);
-void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
+void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_shcaster_add(
- EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct Gwn_Batch *geom, float (*obmat)[4]);
+ EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, struct Gwn_Batch *geom, Object *ob);
void EEVEE_lights_cache_shcaster_material_add(
EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl,
struct GPUMaterial *gpumat, struct Gwn_Batch *geom, struct Object *ob,
@@ -888,7 +899,7 @@ void EEVEE_effects_free(void);
/* eevee_render.c */
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 RenderResult *render_result, struct RenderLayer *render_layer);
+void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect);
void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer);
/* Shadow Matrix */
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index f2db27f812f..503c2da0544 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -31,8 +31,10 @@
#include "DRW_render.h"
#include "DNA_node_types.h"
+#include "DNA_object_types.h"
#include "BLI_rand.h"
+#include "BLI_rect.h"
#include "DEG_depsgraph_query.h"
@@ -46,7 +48,6 @@
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;
@@ -84,6 +85,9 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
if (sldata->common_ubo == NULL) {
sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
}
+ if (sldata->clip_ubo == NULL) {
+ sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data);
+ }
/* Set the pers & view matrix. */
struct Object *camera = RE_GetCamera(engine->re);
@@ -114,8 +118,8 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
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_lights_cache_init(sldata, vedata);
+ EEVEE_materials_cache_init(sldata, vedata);
EEVEE_motion_blur_cache_init(sldata, vedata);
EEVEE_occlusion_cache_init(sldata, vedata);
EEVEE_screen_raytrace_cache_init(sldata, vedata);
@@ -126,10 +130,14 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
void EEVEE_render_cache(
void *vedata, struct Object *ob,
- struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
+ struct RenderEngine *engine, struct Depsgraph *UNUSED(depsgraph))
{
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ char info[42];
+ BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2);
+ RE_engine_update_stats(engine, NULL, info);
+
if (DRW_check_object_visible_within_active_context(ob) == false) {
return;
}
@@ -152,18 +160,18 @@ void EEVEE_render_cache(
}
static void eevee_render_result_combined(
- RenderResult *rr, RenderLayer *rl, const char *viewname,
+ RenderLayer *rl, const char *viewname, const rcti *rect,
EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
{
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
DRW_framebuffer_bind(vedata->stl->effects->final_fb);
- DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 4, 0, rp->rect);
+ DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect);
}
static void eevee_render_result_subsurface(
- RenderResult *rr, RenderLayer *rl, const char *viewname,
- EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
@@ -176,30 +184,24 @@ static void eevee_render_result_subsurface(
if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname);
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
- float render_samples = (float)BKE_collection_engine_property_value_get_int(props, "taa_render_samples");
-
DRW_framebuffer_bind(vedata->fbl->sss_accum_fb);
- DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 3, 1, rp->rect);
+ DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 1, rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rr->rectx * rr->recty * 3; i++) {
- rp->rect[i] /= render_samples;
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
+ rp->rect[i] /= (float)render_samples;
}
}
if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname);
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
- float render_samples = (float)BKE_collection_engine_property_value_get_int(props, "taa_render_samples");
-
DRW_framebuffer_bind(vedata->fbl->sss_accum_fb);
- DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 3, 0, rp->rect);
+ DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 0, rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rr->rectx * rr->recty * 3; i++) {
- rp->rect[i] /= render_samples;
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
+ rp->rect[i] /= (float)render_samples;
}
}
@@ -210,7 +212,7 @@ static void eevee_render_result_subsurface(
}
static void eevee_render_result_normal(
- RenderResult *rr, RenderLayer *rl, const char *viewname,
+ RenderLayer *rl, const char *viewname, const rcti *rect,
EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -225,10 +227,10 @@ static void eevee_render_result_normal(
if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname);
- DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 3, 1, rp->rect);
+ DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 1, rp->rect);
/* Convert Eevee encoded normals to Blender normals. */
- for (int i = 0; i < rr->rectx * rr->recty * 3; i += 3) {
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) {
/* If normal is not correct then do not produce NANs. */
continue;
@@ -251,7 +253,7 @@ static void eevee_render_result_normal(
}
static void eevee_render_result_z(
- RenderResult *rr, RenderLayer *rl, const char *viewname,
+ RenderLayer *rl, const char *viewname, const rcti *rect,
EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -267,12 +269,12 @@ static void eevee_render_result_z(
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
- DRW_framebuffer_read_depth(rr->xof, rr->yof, rr->rectx, rr->recty, rp->rect);
+ DRW_framebuffer_read_depth(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 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 < rr->rectx * rr->recty; ++i) {
+ for (int i = 0; i < rp->rectx * rp->recty; ++i) {
if (rp->rect[i] == 1.0f ) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -290,8 +292,8 @@ static void eevee_render_result_z(
}
static void eevee_render_result_mist(
- RenderResult *rr, RenderLayer *rl, const char *viewname,
- EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
@@ -299,22 +301,19 @@ static void eevee_render_result_mist(
if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname);
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
- float render_samples = (float)BKE_collection_engine_property_value_get_int(props, "taa_render_samples");
-
DRW_framebuffer_bind(vedata->fbl->mist_accum_fb);
- DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 1, 0, rp->rect);
+ DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 1, 0, rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rr->rectx * rr->recty; i++) {
- rp->rect[i] /= render_samples;
+ for (int i = 0; i < rp->rectx * rp->recty; i++) {
+ rp->rect[i] /= (float)render_samples;
}
}
}
static void eevee_render_result_occlusion(
- RenderResult *rr, RenderLayer *rl, const char *viewname,
- EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
@@ -327,15 +326,12 @@ static void eevee_render_result_occlusion(
if ((view_layer->passflag & SCE_PASS_AO) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname);
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
- float render_samples = (float)BKE_collection_engine_property_value_get_int(props, "taa_render_samples");
-
DRW_framebuffer_bind(vedata->fbl->ao_accum_fb);
- DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 3, 0, rp->rect);
+ DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 0, rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rr->rectx * rr->recty * 3; i += 3) {
- rp->rect[i] = rp->rect[i + 1] = rp->rect[i+2] = min_ff(1.0f, rp->rect[i] / render_samples);
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
+ rp->rect[i] = rp->rect[i + 1] = rp->rect[i+2] = min_ff(1.0f, rp->rect[i] / (float)render_samples);
}
}
}
@@ -368,7 +364,7 @@ static void eevee_render_draw_background(EEVEE_Data *vedata)
DRW_framebuffer_bind(fbl->main);
}
-void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *rr, RenderLayer *rl)
+void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl, const rcti *rect)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
@@ -407,9 +403,14 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *r
}
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");
+ unsigned int tot_sample = BKE_collection_engine_property_value_get_int(props, "taa_render_samples");
+ unsigned int render_samples = 0;
- while (render_samples-- > 0) {
+ if (RE_engine_test_break(engine)) {
+ return;
+ }
+
+ while (render_samples < tot_sample && !RE_engine_test_break(engine)) {
float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
unsigned int primes[3] = {2, 3, 7};
double offset[3] = {0.0, 0.0, 0.0};
@@ -417,6 +418,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *r
/* Restore winmat before jittering again. */
copy_m4_m4(stl->effects->overide_winmat, g_data->winmat);
+ /* Copy previous persmat to UBO data */
+ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat);
BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r);
EEVEE_update_noise(psl, fbl, r);
@@ -424,12 +427,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *r
EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1);
EEVEE_materials_init(sldata, stl, fbl);
- /* Refresh Probes */
- while (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false) {
- EEVEE_lightprobes_refresh(sldata, vedata);
- }
- EEVEE_lightprobes_refresh_planar(sldata, vedata);
- DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
/* Set matrices. */
DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS);
DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV);
@@ -437,6 +434,23 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *r
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);
+
+ /* Refresh Probes */
+ while (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false) {
+ RE_engine_update_stats(engine, NULL, "Updating Probes");
+ EEVEE_lightprobes_refresh(sldata, vedata);
+ /* Refreshing probes can take some times, allow exit. */
+ if (RE_engine_test_break(engine)) {
+ return;
+ }
+ }
+ EEVEE_lightprobes_refresh_planar(sldata, vedata);
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ char info[42];
+ BLI_snprintf(info, sizeof(info), "Rendering %u / %u samples", render_samples+1, tot_sample);
+ RE_engine_update_stats(engine, NULL, info);
+
/* Refresh Shadows */
EEVEE_draw_shadows(sldata, psl);
@@ -470,7 +484,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *r
/* Occlusion output */
EEVEE_occlusion_output_accumulate(sldata, vedata);
/* Result NORMAL */
- eevee_render_result_normal(rr, rl, viewname, vedata, sldata);
+ eevee_render_result_normal(rl, viewname, rect, vedata, sldata);
/* Volumetrics Resolve Opaque */
EEVEE_volumes_resolve(sldata, vedata);
/* Mist output */
@@ -478,15 +492,17 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderResult *r
/* Transparent */
DRW_draw_pass(psl->transparent_pass);
/* Result Z */
- eevee_render_result_z(rr, rl, viewname, vedata, sldata);
+ eevee_render_result_z(rl, viewname, rect, vedata, sldata);
/* Post Process */
EEVEE_draw_effects(sldata, vedata);
+
+ RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample);
}
- eevee_render_result_combined(rr, rl, viewname, vedata, sldata);
- eevee_render_result_subsurface(rr, rl, viewname, vedata, sldata);
- eevee_render_result_mist(rr, rl, viewname, vedata, sldata);
- eevee_render_result_occlusion(rr, rl, viewname, vedata, sldata);
+ eevee_render_result_combined(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples);
+ eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples);
+ eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples);
}
void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 2917bfd1236..96d560688f3 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -48,9 +48,10 @@ static struct {
/* Theses are just references, not actually allocated */
struct GPUTexture *depth_src;
struct GPUTexture *color_src;
-} e_data = {NULL}; /* Engine data */
+} e_data = {{NULL}}; /* Engine data */
extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
@@ -63,6 +64,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
{
if (e_data.ssr_sh[options] == NULL) {
char *ssr_shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_sampling_lib_glsl,
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index c3079d931fb..12a70cc2fe7 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -34,14 +34,16 @@
static struct {
struct GPUShader *sss_sh[4];
-} e_data = {NULL}; /* Engine data */
+} e_data = {{NULL}}; /* Engine data */
+extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
static void eevee_create_shader_subsurface(void)
{
char *frag_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_effect_subsurface_frag_glsl);
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 2c5b9072837..0c0ffa39146 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -65,6 +65,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_common_view_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lamps_lib_glsl[];
@@ -80,11 +81,13 @@ extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
static void eevee_create_shader_volumes(void)
{
e_data.volumetric_common_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
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_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_direct_lib_glsl,
@@ -360,7 +363,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- DRWShadingGroup *grp;
+ DRWShadingGroup *grp = NULL;
/* Quick breakdown of the Volumetric rendering:
*
@@ -404,7 +407,8 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
}
}
- else {
+
+ if (grp == NULL) {
/* 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,
@@ -468,17 +472,20 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]);
+ /* If shader failed to compile or is currently compiling. */
+ if (grp == NULL) {
+ return;
+ }
+
/* Making sure it's updated. */
invert_m4_m4(ob->imat, ob->obmat);
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_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);
/* Smoke Simulation */
if (((ob->base_flag & BASE_FROMDUPLI) == 0) &&
@@ -506,6 +513,9 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
if (sds->tex_flame != NULL) {
DRW_shgroup_uniform_buffer(grp, "sampflame", &sds->tex_flame);
}
+
+ /* Output is such that 0..1 maps to 0..1000K */
+ DRW_shgroup_uniform_vec2(grp, "unftemperature", &sds->flame_ignition, 1);
}
}
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 f571d8c727b..23487e66a17 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -8,12 +8,7 @@
#define LUT_SIZE 64
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewProjectionMatrix;
-uniform mat4 ViewMatrixInverse;
-#ifndef SHADOW_SHADER
-uniform mat4 ViewMatrix;
-#else
+#ifdef SHADOW_SHADER
layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
@@ -27,7 +22,21 @@ layout(std140) uniform shadow_render_block {
};
flat in int shFace; /* Shadow layer we are rendering to. */
-#define ViewMatrix FaceViewMatrix[shFace]
+
+/* Replacing viewBlock */
+#define ViewMatrix FaceViewMatrix[shFace]
+#define ViewProjectionMatrix ShadowMatrix[shFace]
+/* TODO optimize */
+#define ProjectionMatrix \
+mat4(vec4(1.0, 0.0, 0.0, 0.0), \
+ vec4(0.0, 1.0, 0.0, 0.0), \
+ vec4(0.0, 0.0, -(farClip + nearClip) / (farClip - nearClip), -1.0), \
+ vec4(0.0, 0.0, (-2.0 * farClip * nearClip) / (farClip - nearClip), 0.0))
+
+#define ViewMatrixInverse invert(ViewMatrix)
+#define ViewProjectionMatrixInverse invert(ViewProjectionMatrix)
+#define ProjectionMatrixInverse invert(ProjectionMatrix)
+#define CameraTexCoFactors vec4(1.0f, 1.0f, 0.0f, 0.0f)
#endif
/* Buffers */
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 d9e12bcc4bd..5ecf6323255 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -23,8 +23,6 @@ layout(location = 0) out vec4 FragColor;
layout(location = 1) out vec4 sssColor;
#endif
-uniform mat4 ProjectionMatrix;
-
float get_view_z_from_depth(float depth)
{
if (ProjectionMatrix[3][3] == 0.0) {
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
index 202b27be0ef..57da4d0d1ec 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
@@ -6,8 +6,6 @@ in int probe_id;
in vec3 probe_location;
in float sphere_size;
-uniform mat4 ViewProjectionMatrix;
-
flat out int pid;
out vec3 worldNormal;
out vec3 worldPosition;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
index fd200ec5984..37f73714a8e 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
@@ -1,8 +1,6 @@
in vec3 pos;
-uniform mat4 ViewProjectionMatrix;
-
uniform float sphere_size;
uniform int offset;
uniform ivec3 grid_resolution;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
index 655cc626bba..3808b59761f 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
@@ -1,5 +1,4 @@
-uniform mat4 ViewProjectionMatrix;
uniform sampler2DArray probePlanars;
in vec3 worldPosition;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
index a9716332eb5..3ecd85fd72e 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
@@ -4,8 +4,6 @@ in vec3 pos;
in int probe_id;
in mat4 probe_mat;
-uniform mat4 ViewProjectionMatrix;
-
out vec3 worldPosition;
flat out int probeIdx;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl
index 40b04c986f3..23c16f0fa30 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl
@@ -11,13 +11,13 @@ void main() {
gl_Layer = instance[0];
layer = float(instance[0]);
- gl_Position = vec4(vPos[0], 0.0, 0.0);
+ gl_Position = vec4(vPos[0], 0.0, 1.0);
EmitVertex();
- gl_Position = vec4(vPos[1], 0.0, 0.0);
+ gl_Position = vec4(vPos[1], 0.0, 1.0);
EmitVertex();
- gl_Position = vec4(vPos[2], 0.0, 0.0);
+ gl_Position = vec4(vPos[2], 0.0, 1.0);
EmitVertex();
EndPrimitive();
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
index 998ccfa453a..d25c49098a6 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
@@ -14,7 +14,10 @@ out vec3 worldPosition;
out vec3 viewPosition;
/* Used for planar reflections */
-uniform vec4 ClipPlanes[1];
+/* keep in sync with EEVEE_ClipPlanesUniformBuffer */
+layout(std140) uniform clip_block {
+ vec4 ClipPlanes[1];
+};
#ifdef USE_FLAT_NORMAL
flat out vec3 worldNormal;
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
index 6f26a815736..c756e061d70 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
@@ -1,9 +1,11 @@
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelMatrix;
-#ifdef CLIP_PLANES
-uniform vec4 ClipPlanes[1];
-#endif
+
+/* keep in sync with DRWManager.view_data */
+layout(std140) uniform clip_block {
+ vec4 ClipPlanes[1];
+};
in vec3 pos;
@@ -12,7 +14,7 @@ void main()
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
#ifdef CLIP_PLANES
vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0));
- gl_ClipDistance[0] = dot(worldPosition, ClipPlanes[0]);
+ gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), ClipPlanes[0]);
#endif
/* TODO motion vectors */
}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
index fcc304ca289..0fc7e4c9396 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
@@ -47,7 +47,7 @@ vec4 ln_space_prefilter(float w0, vec4 x, float w1, vec4 y)
}
#ifdef CSM
-vec3 get_texco(vec3 cos, vec2 ofs)
+vec3 get_texco(vec3 cos, const vec2 ofs)
{
cos.xy += ofs * shadowFilterSize;
return cos;
@@ -64,13 +64,43 @@ void make_orthonormal_basis(vec3 N)
B = cross(N, T);
}
-vec3 get_texco(vec3 cos, vec2 ofs)
+vec3 get_texco(vec3 cos, const vec2 ofs)
{
return cos + ofs.x * T + ofs.y * B;
}
#endif
+#ifdef ESM
+void grouped_samples_accum(
+ vec3 cos,
+ const vec2 co1, const vec2 co2, const vec2 co3, const vec2 co4,
+ inout vec4 accum)
+{
+ vec4 depths;
+ depths.x = texture(shadowTexture, get_texco(cos, co1)).r;
+ depths.y = texture(shadowTexture, get_texco(cos, co2)).r;
+ depths.z = texture(shadowTexture, get_texco(cos, co3)).r;
+ depths.w = texture(shadowTexture, get_texco(cos, co4)).r;
+
+ accum = ln_space_prefilter(1.0, accum, shadowInvSampleCount, depths);
+}
+#else /* VSM */
+void grouped_samples_accum(
+ vec3 cos,
+ const vec2 co1, const vec2 co2, const vec2 co3, const vec2 co4,
+ inout vec2 accum)
+{
+ vec4 depths1, depths2;
+ depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg;
+ depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg;
+ depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg;
+ depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg;
+
+ accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
+}
+#endif
+
void main() {
vec3 cos;
@@ -105,9 +135,8 @@ void main() {
#endif
#ifdef ESM
- vec4 accum = vec4(0.0);
-
/* disc blur in log space. */
+ vec4 accum = vec4(0.0);
vec4 depths;
depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r;
depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r;
@@ -115,32 +144,102 @@ void main() {
depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r;
accum = ln_space_prefilter(0.0, accum, shadowInvSampleCount, depths);
- for (int i = 4; i < shadowSampleCount && i < CONCENTRIC_SAMPLE_NUM; i += 4) {
- depths.x = texture(shadowTexture, get_texco(cos, concentric[i+0])).r;
- depths.y = texture(shadowTexture, get_texco(cos, concentric[i+1])).r;
- depths.z = texture(shadowTexture, get_texco(cos, concentric[i+2])).r;
- depths.w = texture(shadowTexture, get_texco(cos, concentric[i+3])).r;
- accum = ln_space_prefilter(1.0, accum, shadowInvSampleCount, depths);
+#else /* VSM */
+ vec2 accum = vec2(0.0);
+ grouped_samples_accum(cos, concentric[0], concentric[1], concentric[2], concentric[3], accum);
+#endif
+
+ /**
+ * Making the `grouped_samples_accum` be called within a loop would be
+ * the most conventional solution, however in some older gpus, transverse the huge
+ * `const vec2 concentric[]` array with variable indices is extremely slow.
+ * The solution is to use constant indices to access the array.
+ */
+ if (shadowSampleCount > 4) {
+ grouped_samples_accum(cos, concentric[4], concentric[5], concentric[6], concentric[7], accum);
+ grouped_samples_accum(cos, concentric[8], concentric[9], concentric[10], concentric[11], accum);
+ grouped_samples_accum(cos, concentric[12], concentric[13], concentric[14], concentric[15], accum);
+ }
+ if (shadowSampleCount > 16) {
+ grouped_samples_accum(cos, concentric[16], concentric[17], concentric[18], concentric[19], accum);
+ grouped_samples_accum(cos, concentric[20], concentric[21], concentric[22], concentric[23], accum);
+ grouped_samples_accum(cos, concentric[24], concentric[25], concentric[26], concentric[27], accum);
+ grouped_samples_accum(cos, concentric[28], concentric[29], concentric[30], concentric[31], accum);
+ grouped_samples_accum(cos, concentric[32], concentric[33], concentric[34], concentric[35], accum);
+ }
+ if (shadowSampleCount > 36) {
+ grouped_samples_accum(cos, concentric[36], concentric[37], concentric[38], concentric[39], accum);
+ grouped_samples_accum(cos, concentric[40], concentric[41], concentric[42], concentric[43], accum);
+ grouped_samples_accum(cos, concentric[44], concentric[45], concentric[46], concentric[47], accum);
+ grouped_samples_accum(cos, concentric[48], concentric[49], concentric[50], concentric[51], accum);
+ grouped_samples_accum(cos, concentric[52], concentric[53], concentric[54], concentric[55], accum);
+ grouped_samples_accum(cos, concentric[56], concentric[57], concentric[58], concentric[59], accum);
+ grouped_samples_accum(cos, concentric[60], concentric[61], concentric[62], concentric[63], accum);
+ }
+ if (shadowSampleCount > 64) {
+ grouped_samples_accum(cos, concentric[64], concentric[65], concentric[66], concentric[67], accum);
+ grouped_samples_accum(cos, concentric[68], concentric[69], concentric[70], concentric[71], accum);
+ grouped_samples_accum(cos, concentric[72], concentric[73], concentric[74], concentric[75], accum);
+ grouped_samples_accum(cos, concentric[76], concentric[77], concentric[78], concentric[79], accum);
+ grouped_samples_accum(cos, concentric[80], concentric[81], concentric[82], concentric[83], accum);
+ grouped_samples_accum(cos, concentric[84], concentric[85], concentric[86], concentric[87], accum);
+ grouped_samples_accum(cos, concentric[88], concentric[89], concentric[90], concentric[91], accum);
+ grouped_samples_accum(cos, concentric[92], concentric[93], concentric[94], concentric[95], accum);
+ grouped_samples_accum(cos, concentric[96], concentric[97], concentric[98], concentric[99], accum);
+ }
+ if (shadowSampleCount > 100) {
+ grouped_samples_accum(cos, concentric[100], concentric[101], concentric[102], concentric[103], accum);
+ grouped_samples_accum(cos, concentric[104], concentric[105], concentric[106], concentric[107], accum);
+ grouped_samples_accum(cos, concentric[108], concentric[109], concentric[110], concentric[111], accum);
+ grouped_samples_accum(cos, concentric[112], concentric[113], concentric[114], concentric[115], accum);
+ grouped_samples_accum(cos, concentric[116], concentric[117], concentric[118], concentric[119], accum);
+ grouped_samples_accum(cos, concentric[120], concentric[121], concentric[122], concentric[123], accum);
+ grouped_samples_accum(cos, concentric[124], concentric[125], concentric[126], concentric[127], accum);
+ grouped_samples_accum(cos, concentric[128], concentric[129], concentric[130], concentric[131], accum);
+ grouped_samples_accum(cos, concentric[132], concentric[133], concentric[134], concentric[135], accum);
+ grouped_samples_accum(cos, concentric[136], concentric[137], concentric[138], concentric[139], accum);
+ grouped_samples_accum(cos, concentric[140], concentric[141], concentric[142], concentric[143], accum);
+ }
+ if (shadowSampleCount > 144) {
+ grouped_samples_accum(cos, concentric[144], concentric[145], concentric[146], concentric[147], accum);
+ grouped_samples_accum(cos, concentric[148], concentric[149], concentric[150], concentric[151], accum);
+ grouped_samples_accum(cos, concentric[152], concentric[153], concentric[154], concentric[155], accum);
+ grouped_samples_accum(cos, concentric[156], concentric[157], concentric[158], concentric[159], accum);
+ grouped_samples_accum(cos, concentric[160], concentric[161], concentric[162], concentric[163], accum);
+ grouped_samples_accum(cos, concentric[164], concentric[165], concentric[166], concentric[167], accum);
+ grouped_samples_accum(cos, concentric[168], concentric[169], concentric[170], concentric[171], accum);
+ grouped_samples_accum(cos, concentric[172], concentric[173], concentric[174], concentric[175], accum);
+ grouped_samples_accum(cos, concentric[176], concentric[177], concentric[178], concentric[179], accum);
+ grouped_samples_accum(cos, concentric[180], concentric[181], concentric[182], concentric[183], accum);
+ grouped_samples_accum(cos, concentric[184], concentric[185], concentric[186], concentric[187], accum);
+ grouped_samples_accum(cos, concentric[188], concentric[189], concentric[190], concentric[191], accum);
+ grouped_samples_accum(cos, concentric[192], concentric[193], concentric[194], concentric[195], accum);
+ }
+ if (shadowSampleCount > 196) {
+ grouped_samples_accum(cos, concentric[196], concentric[197], concentric[198], concentric[199], accum);
+ grouped_samples_accum(cos, concentric[200], concentric[201], concentric[202], concentric[203], accum);
+ grouped_samples_accum(cos, concentric[204], concentric[205], concentric[206], concentric[207], accum);
+ grouped_samples_accum(cos, concentric[208], concentric[209], concentric[210], concentric[211], accum);
+ grouped_samples_accum(cos, concentric[212], concentric[213], concentric[114], concentric[215], accum);
+ grouped_samples_accum(cos, concentric[216], concentric[217], concentric[218], concentric[219], accum);
+ grouped_samples_accum(cos, concentric[220], concentric[221], concentric[222], concentric[223], accum);
+ grouped_samples_accum(cos, concentric[224], concentric[225], concentric[226], concentric[227], accum);
+ grouped_samples_accum(cos, concentric[228], concentric[229], concentric[230], concentric[231], accum);
+ grouped_samples_accum(cos, concentric[232], concentric[233], concentric[234], concentric[235], accum);
+ grouped_samples_accum(cos, concentric[236], concentric[237], concentric[238], concentric[239], accum);
+ grouped_samples_accum(cos, concentric[240], concentric[241], concentric[242], concentric[243], accum);
+ grouped_samples_accum(cos, concentric[244], concentric[245], concentric[246], concentric[247], accum);
+ grouped_samples_accum(cos, concentric[248], concentric[249], concentric[250], concentric[251], accum);
+ grouped_samples_accum(cos, concentric[252], concentric[253], concentric[254], concentric[255], accum);
}
+#ifdef ESM
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.y);
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.z);
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.w);
FragColor = accum.xxxx;
#else /* VSM */
- vec2 accum = vec2(0.0);
-
- /* disc blur. */
- vec4 depths1, depths2;
- for (int i = 0; i < shadowSampleCount && i < CONCENTRIC_SAMPLE_NUM; i += 4) {
- depths1.xy = texture(shadowTexture, get_texco(cos, concentric[i+0])).rg;
- depths1.zw = texture(shadowTexture, get_texco(cos, concentric[i+1])).rg;
- depths2.xy = texture(shadowTexture, get_texco(cos, concentric[i+2])).rg;
- depths2.zw = texture(shadowTexture, get_texco(cos, concentric[i+3])).rg;
- accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
- }
-
FragColor = accum.xyxy * shadowInvSampleCount;
#endif
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 777902ccba8..29cbcfdd6e4 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -1,5 +1,5 @@
-uniform mat4 ShadowModelMatrix;
+uniform mat4 ModelMatrix;
#ifdef MESH_SHADER
uniform mat3 WorldNormalMatrix;
#endif
@@ -17,7 +17,7 @@ out vec3 vNor;
flat out int face;
void main() {
- vPos = ShadowModelMatrix * vec4(pos, 1.0);
+ vPos = ModelMatrix * vec4(pos, 1.0);
face = gl_InstanceID;
#ifdef MESH_SHADER
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index f62b224b094..791d38ff62f 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -55,6 +55,7 @@
#include "RE_engine.h"
+struct rcti;
struct bContext;
struct GPUFrameBuffer;
struct GPUShader;
@@ -76,6 +77,11 @@ typedef struct DRWInterface DRWInterface;
typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
+/* TODO Put it somewhere else? */
+typedef struct BoundSphere {
+ float center[3], radius;
+} BoundSphere;
+
/* declare members as empty (unused) */
typedef char DRWViewportEmptyList;
@@ -140,7 +146,7 @@ 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 RenderResult *result, struct RenderLayer *layer);
+ void (*render_to_image)(void *vedata, struct RenderEngine *engine, struct RenderLayer *layer, const struct rcti *rect);
} DrawEngineType;
#ifndef __DRW_ENGINE_H__
@@ -176,6 +182,7 @@ typedef enum {
DRW_TEX_RG_32,
DRW_TEX_R_8,
DRW_TEX_R_16,
+ DRW_TEX_R_16I,
DRW_TEX_R_32,
DRW_TEX_DEPTH_16,
DRW_TEX_DEPTH_24,
@@ -267,6 +274,14 @@ struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_3D_depth_only(void);
+struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, int options);
+struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options);
+struct GPUMaterial *DRW_shader_create_from_world(
+ struct Scene *scene, struct World *wo, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines);
+struct GPUMaterial *DRW_shader_create_from_material(
+ struct Scene *scene, struct Material *ma, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines);
void DRW_shader_free(struct GPUShader *shader);
#define DRW_SHADER_FREE_SAFE(shader) do { \
if (shader != NULL) { \
@@ -287,7 +302,7 @@ typedef enum {
DRW_STATE_CULL_BACK = (1 << 6),
DRW_STATE_CULL_FRONT = (1 << 7),
DRW_STATE_WIRE = (1 << 8),
- DRW_STATE_WIRE_LARGE = (1 << 9),
+// DRW_STATE_WIRE_LARGE = (1 << 9), /* Removed from ogl in 3.0 */
DRW_STATE_POINT = (1 << 10),
DRW_STATE_STIPPLE_2 = (1 << 11),
DRW_STATE_STIPPLE_3 = (1 << 12),
@@ -341,11 +356,16 @@ typedef void (DRWCallGenerateFn)(
void (*draw_fn)(DRWShadingGroup *shgroup, struct Gwn_Batch *geom),
void *user_data);
-void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances);
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batch);
void DRW_shgroup_free(struct DRWShadingGroup *shgroup);
void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4]);
void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob);
+/* Used for drawing a batch with instancing without instance attribs. */
+void DRW_shgroup_call_instances_add(
+ DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4], unsigned int *count);
+void DRW_shgroup_call_object_instances_add(
+ DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob, unsigned int *count);
void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]);
void DRW_shgroup_call_generate_add(
DRWShadingGroup *shgroup, DRWCallGenerateFn *geometry_fn, void *user_data, float (*obmat)[4]);
@@ -354,8 +374,7 @@ 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 to set a high number of instances. */
-void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, unsigned int count);
+
unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup);
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
@@ -363,7 +382,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask);
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex);
+void DRW_shgroup_uniform_texture_persistent(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_block_persistent(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_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);
@@ -393,13 +414,24 @@ typedef enum {
DRW_MAT_VIEWINV,
DRW_MAT_WIN,
DRW_MAT_WININV,
+
+ DRW_MAT_COUNT, // Don't use this.
} DRWViewportMatrixType;
+typedef struct DRWMatrixState {
+ float mat[DRW_MAT_COUNT][4][4];
+} DRWMatrixState;
+
void DRW_viewport_init(const bContext *C);
void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type);
+void DRW_viewport_matrix_get_all(DRWMatrixState *state);
void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type);
+void DRW_viewport_matrix_override_set_all(DRWMatrixState *state);
void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type);
+void DRW_viewport_matrix_override_unset_all(void);
+
const float *DRW_viewport_size_get(void);
+const float *DRW_viewport_invert_size_get(void);
const float *DRW_viewport_screenvecs_get(void);
const float *DRW_viewport_pixelsize_get(void);
bool DRW_viewport_is_persp_get(void);
@@ -409,7 +441,7 @@ 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_to_image(struct RenderEngine *engine, struct Depsgraph *graph);
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));
@@ -450,12 +482,17 @@ void DRW_draw_region_engine_info(void);
void DRW_state_reset_ex(DRWState state);
void DRW_state_reset(void);
+void DRW_state_lock(DRWState state);
void DRW_state_invert_facing(void);
-void DRW_state_clip_planes_add(float plane_eq[4]);
+void DRW_state_clip_planes_count_set(unsigned int plane_ct);
void DRW_state_clip_planes_reset(void);
+/* Culling, return true if object is inside view frustum. */
+bool DRW_culling_sphere_test(BoundSphere *bsphere);
+bool DRW_culling_box_test(BoundBox *bbox);
+
/* Selection */
void DRW_select_load_id(unsigned int id);
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 3b4180c0375..6b1a3356b51 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -45,6 +45,7 @@ static struct DRWShapeCache {
Gwn_Batch *drw_single_vertice;
Gwn_Batch *drw_fullscreen_quad;
Gwn_Batch *drw_quad;
+ Gwn_Batch *drw_sphere;
Gwn_Batch *drw_screenspace_circle;
Gwn_Batch *drw_plain_axes;
Gwn_Batch *drw_single_arrow;
@@ -266,7 +267,6 @@ Gwn_Batch *DRW_cache_fullscreen_quad_get(void)
Gwn_Batch *DRW_cache_quad_get(void)
{
if (!SHC.drw_quad) {
- /* Use a triangle instead of a real quad */
float pos[4][2] = {{-1.0f, -1.0f}, { 1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}};
float uvs[4][2] = {{ 0.0f, 0.0f}, { 1.0f, 0.0f}, {1.0f, 1.0f}, { 0.0f, 1.0f}};
@@ -294,7 +294,10 @@ Gwn_Batch *DRW_cache_quad_get(void)
/* Sphere */
Gwn_Batch *DRW_cache_sphere_get(void)
{
- return GPU_batch_preset_sphere(2);
+ if (!SHC.drw_sphere) {
+ SHC.drw_sphere = gpu_batch_sphere(32, 24);
+ }
+ return SHC.drw_sphere;
}
/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index b44c5b8a20b..f7a82c6d0c5 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -1665,6 +1665,46 @@ void DRW_mesh_batch_cache_dirty(Mesh *me, int mode)
}
}
+/**
+ * This only clear the batches associated to the given vertex buffer.
+ **/
+static void mesh_batch_cache_clear_selective(Mesh *me, Gwn_VertBuf *vert)
+{
+ MeshBatchCache *cache = me->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ BLI_assert(vert != NULL);
+
+ if (cache->pos_with_normals == vert) {
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_normals);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_weights);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_id);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_mask);
+ GWN_BATCH_DISCARD_SAFE(cache->points_with_normals);
+ if (cache->shaded_triangles) {
+ for (int i = 0; i < cache->mat_len; ++i) {
+ GWN_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->shaded_triangles);
+ if (cache->texpaint_triangles) {
+ for (int i = 0; i < cache->mat_len; ++i) {
+ GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->texpaint_triangles);
+ GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single);
+ }
+ /* TODO: add the other ones if needed. */
+ else {
+ /* Does not match any vertbuf in the batch cache! */
+ BLI_assert(0);
+ }
+}
+
static void mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->batch_cache;
@@ -3878,21 +3918,10 @@ void DRW_mesh_cache_sculpt_coords_ensure(Mesh *me)
if (me->batch_cache) {
MeshBatchCache *cache = mesh_batch_cache_get(me);
if (cache && cache->pos_with_normals && cache->is_sculpt_points_tag) {
-
- const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
- MeshRenderData *rdata = mesh_render_data_create(me, datatype);
-
- Gwn_VertBuf *pos_with_normals = cache->pos_with_normals;
- cache->pos_with_normals = NULL;
- GWN_vertbuf_clear(pos_with_normals);
- Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
- *pos_with_normals = *vbo;
- GWN_vertformat_copy(&pos_with_normals->format, &vbo->format);
-
- free(vbo);
- cache->pos_with_normals = pos_with_normals;
-
- mesh_render_data_free(rdata);
+ /* XXX Force update of all the batches that contains the pos_with_normals buffer.
+ * TODO(fclem): Ideally, Gawain should provide a way to update a buffer without destroying it. */
+ mesh_batch_cache_clear_selective(me, cache->pos_with_normals);
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos_with_normals);
}
cache->is_sculpt_points_tag = false;
}
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 62166092638..1299b1b757b 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -122,12 +122,12 @@ void DRW_globals_update(void)
ts.sizeEdge = 1.0f / 2.0f; /* TODO Theme */
ts.sizeEdgeFix = 0.5f + 2.0f * (2.0f * (MAX2(ts.sizeVertex, ts.sizeEdge)) * (float)M_SQRT1_2);
- /* TODO Waiting for notifiers to invalidate cache */
- if (globals_ubo) {
- DRW_uniformbuffer_free(globals_ubo);
+
+ if (globals_ubo == NULL) {
+ globals_ubo = DRW_uniformbuffer_create(sizeof(GlobalsUboStorage), &ts);
}
- globals_ubo = DRW_uniformbuffer_create(sizeof(GlobalsUboStorage), &ts);
+ DRW_uniformbuffer_update(globals_ubo, &ts);
ColorBand ramp = {0};
float *colors;
@@ -481,6 +481,7 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color
else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER;
else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA;
else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY;
+ else if (ob->type == OB_LIGHTPROBE) theme_id = TH_EMPTY; /* TODO add lightprobe color */
/* fallback to TH_WIRE */
}
}
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index c2aae8e33ae..ee73a2ba2c6 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -42,12 +42,29 @@
#define BUFFER_CHUNK_SIZE 32
#define BUFFER_VERTS_CHUNK 32
-typedef struct DRWInstanceBuffer {
+typedef struct DRWBatchingBuffer {
struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */
Gwn_VertFormat *format; /* Identifier. */
Gwn_VertBuf *vert; /* Gwn_VertBuf contained in the Gwn_Batch. */
Gwn_Batch *batch; /* Gwn_Batch containing the Gwn_VertBuf. */
-} DRWInstanceBuffer;
+} DRWBatchingBuffer;
+
+typedef struct DRWInstancingBuffer {
+ struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */
+ Gwn_VertFormat *format; /* Identifier. */
+ Gwn_Batch *instance; /* Identifier. */
+ Gwn_VertBuf *vert; /* Gwn_VertBuf contained in the Gwn_Batch. */
+ Gwn_Batch *batch; /* Gwn_Batch containing the Gwn_VertBuf. */
+} DRWInstancingBuffer;
+
+typedef struct DRWInstanceChunk {
+ size_t cursor; /* Offset to the next instance data. */
+ size_t alloc_size; /* Number of DRWBatchingBuffer/Batches alloc'd in ibufs/btchs. */
+ union {
+ DRWBatchingBuffer *bbufs;
+ DRWInstancingBuffer *ibufs;
+ };
+} DRWInstanceChunk;
struct DRWInstanceData {
struct DRWInstanceData *next;
@@ -60,19 +77,19 @@ struct DRWInstanceData {
};
struct DRWInstanceDataList {
+ struct DRWInstanceDataList *next, *prev;
/* 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];
- struct {
- size_t cursor; /* Offset to the next instance data. */
- size_t alloc_size; /* Number of DRWInstanceBuffer alloc'd in ibufs. */
- DRWInstanceBuffer *ibufs;
- } ibuffers;
+ DRWInstanceChunk instancing;
+ DRWInstanceChunk batching;
};
+static ListBase g_idatalists = {NULL, NULL};
+
/* -------------------------------------------------------------------- */
/** \name Instance Buffer Management
@@ -87,89 +104,174 @@ struct DRWInstanceDataList {
* that would be too slow]).
**/
-void DRW_instance_buffer_request(
- DRWInstanceDataList *idatalist, Gwn_VertFormat *format, struct DRWShadingGroup *shgroup,
- Gwn_Batch **r_batch, Gwn_VertBuf **r_vert, Gwn_PrimType type)
+static void instance_batch_free(Gwn_Batch *batch, void *UNUSED(user_data))
{
- BLI_assert(format);
+ /* Free all batches that have the same key before they are reused. */
+ /* TODO: Make it thread safe! Batch freeing can happen from another thread. */
+ /* XXX we need to iterate over all idatalists unless we make some smart
+ * data structure to store the locations to update. */
+ for (DRWInstanceDataList *idatalist = g_idatalists.first; idatalist; idatalist = idatalist->next) {
+ DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs;
+ for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) {
+ if (ibuf->instance == batch) {
+ BLI_assert(ibuf->shgroup == NULL); /* Make sure it has no other users. */
+ GWN_VERTBUF_DISCARD_SAFE(ibuf->vert);
+ GWN_BATCH_DISCARD_SAFE(ibuf->batch);
+ /* Tag as non alloced. */
+ ibuf->format = NULL;
+ }
+ }
+ }
+}
- DRWInstanceBuffer *ibuf = idatalist->ibuffers.ibufs;
- int first_non_alloced = -1;
+void DRW_batching_buffer_request(
+ DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_PrimType type, struct DRWShadingGroup *shgroup,
+ Gwn_Batch **r_batch, Gwn_VertBuf **r_vert)
+{
+ DRWInstanceChunk *chunk = &idatalist->batching;
+ DRWBatchingBuffer *bbuf = idatalist->batching.bbufs;
+ BLI_assert(format);
+ /* Search for an unused batch. */
+ for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) {
+ if (bbuf->shgroup == NULL) {
+ if (bbuf->format == format) {
+ bbuf->shgroup = shgroup;
+ *r_batch = bbuf->batch;
+ *r_vert = bbuf->vert;
+ return;
+ }
+ }
+ }
+ int new_id = 0; /* Find insertion point. */
+ for (; new_id < chunk->alloc_size; ++new_id) {
+ if (chunk->bbufs[new_id].format == NULL)
+ break;
+ }
+ /* If there is no batch left. Allocate more. */
+ if (new_id == chunk->alloc_size) {
+ new_id = chunk->alloc_size;
+ chunk->alloc_size += BUFFER_CHUNK_SIZE;
+ chunk->bbufs = MEM_reallocN(chunk->bbufs, chunk->alloc_size * sizeof(DRWBatchingBuffer));
+ memset(chunk->bbufs + new_id, 0, sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE);
+ }
+ /* Create the batch. */
+ bbuf = chunk->bbufs + new_id;
+ bbuf->vert = *r_vert = GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_DYNAMIC);
+ bbuf->batch = *r_batch = GWN_batch_create_ex(type, bbuf->vert, NULL, 0);
+ bbuf->format = format;
+ bbuf->shgroup = shgroup;
+ GWN_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK);
+}
+void DRW_instancing_buffer_request(
+ DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_Batch *instance, struct DRWShadingGroup *shgroup,
+ Gwn_Batch **r_batch, Gwn_VertBuf **r_vert)
+{
+ DRWInstanceChunk *chunk = &idatalist->instancing;
+ DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs;
+ BLI_assert(format);
/* Search for an unused batch. */
- for (int i = 0; i < idatalist->ibuffers.alloc_size; i++, ibuf++) {
+ for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) {
if (ibuf->shgroup == NULL) {
if (ibuf->format == format) {
- ibuf->shgroup = shgroup;
- *r_batch = ibuf->batch;
- *r_vert = ibuf->vert;
- return;
- }
- else if (ibuf->format == NULL && first_non_alloced == -1) {
- first_non_alloced = i;
+ if (ibuf->instance == instance) {
+ ibuf->shgroup = shgroup;
+ *r_batch = ibuf->batch;
+ *r_vert = ibuf->vert;
+ return;
+ }
}
}
}
-
- if (first_non_alloced == -1) {
- /* There is no batch left. Allocate more. */
- first_non_alloced = idatalist->ibuffers.alloc_size;
- idatalist->ibuffers.alloc_size += BUFFER_CHUNK_SIZE;
- idatalist->ibuffers.ibufs = MEM_reallocN(idatalist->ibuffers.ibufs,
- idatalist->ibuffers.alloc_size * sizeof(DRWInstanceBuffer));
- /* Clear new part of the memory. */
- memset(idatalist->ibuffers.ibufs + first_non_alloced, 0, sizeof(DRWInstanceBuffer) * BUFFER_CHUNK_SIZE);
+ int new_id = 0; /* Find insertion point. */
+ for (; new_id < chunk->alloc_size; ++new_id) {
+ if (chunk->ibufs[new_id].format == NULL)
+ break;
+ }
+ /* If there is no batch left. Allocate more. */
+ if (new_id == chunk->alloc_size) {
+ new_id = chunk->alloc_size;
+ chunk->alloc_size += BUFFER_CHUNK_SIZE;
+ chunk->ibufs = MEM_reallocN(chunk->ibufs, chunk->alloc_size * sizeof(DRWInstancingBuffer));
+ memset(chunk->ibufs + new_id, 0, sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE);
}
-
/* Create the batch. */
- ibuf = idatalist->ibuffers.ibufs + first_non_alloced;
- ibuf->vert = *r_vert = GWN_vertbuf_create_dynamic_with_format(format);
- ibuf->batch = *r_batch = GWN_batch_create_ex(type, ibuf->vert, NULL, GWN_BATCH_OWNS_VBO);
+ ibuf = chunk->ibufs + new_id;
+ ibuf->vert = *r_vert = GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_DYNAMIC);
+ ibuf->batch = *r_batch = GWN_batch_duplicate(instance);
ibuf->format = format;
ibuf->shgroup = shgroup;
-
+ ibuf->instance = instance;
GWN_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK);
+ GWN_batch_instbuf_set(ibuf->batch, ibuf->vert, false);
+ /* Make sure to free this ibuf if the instance batch gets free. */
+ GWN_batch_callback_free_set(instance, &instance_batch_free, NULL);
}
void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist)
{
- DRWInstanceBuffer *ibuf = idatalist->ibuffers.ibufs;
- size_t minimum_alloc_size = 1; /* Avoid 0 size realloc. */
+ size_t realloc_size = 1; /* Avoid 0 size realloc. */
+ /* Resize down buffers in use and send data to GPU & free unused buffers. */
+ DRWInstanceChunk *batching = &idatalist->batching;
+ DRWBatchingBuffer *bbuf = batching->bbufs;
+ for (int i = 0; i < batching->alloc_size; i++, bbuf++) {
+ if (bbuf->shgroup != NULL) {
+ realloc_size = i + 1;
+ unsigned int vert_ct = DRW_shgroup_get_instance_count(bbuf->shgroup);
+ vert_ct += (vert_ct == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */
+ if (vert_ct + BUFFER_VERTS_CHUNK <= bbuf->vert->vertex_ct) {
+ unsigned int size = vert_ct + BUFFER_VERTS_CHUNK - 1;
+ size = size - size % BUFFER_VERTS_CHUNK;
+ GWN_vertbuf_data_resize(bbuf->vert, size);
+ }
+ GWN_vertbuf_use(bbuf->vert); /* Send data. */
+ bbuf->shgroup = NULL; /* Set as non used for the next round. */
+ }
+ else {
+ GWN_VERTBUF_DISCARD_SAFE(bbuf->vert);
+ GWN_BATCH_DISCARD_SAFE(bbuf->batch);
+ bbuf->format = NULL; /* Tag as non alloced. */
+ }
+ }
+ /* Rounding up to nearest chunk size. */
+ realloc_size += BUFFER_CHUNK_SIZE - 1;
+ realloc_size -= realloc_size % BUFFER_CHUNK_SIZE;
+ /* Resize down if necessary. */
+ if (realloc_size < batching->alloc_size) {
+ batching->alloc_size = realloc_size;
+ batching->ibufs = MEM_reallocN(batching->ibufs, realloc_size * sizeof(DRWBatchingBuffer));
+ }
+ realloc_size = 1;
/* Resize down buffers in use and send data to GPU & free unused buffers. */
- for (int i = 0; i < idatalist->ibuffers.alloc_size; i++, ibuf++) {
+ DRWInstanceChunk *instancing = &idatalist->instancing;
+ DRWInstancingBuffer *ibuf = instancing->ibufs;
+ for (int i = 0; i < instancing->alloc_size; i++, ibuf++) {
if (ibuf->shgroup != NULL) {
- minimum_alloc_size = i + 1;
+ realloc_size = i + 1;
unsigned int vert_ct = DRW_shgroup_get_instance_count(ibuf->shgroup);
- /* Do not realloc to 0 size buffer */
- vert_ct += (vert_ct == 0) ? 1 : 0;
- /* Resize buffer to reclame space. */
+ vert_ct += (vert_ct == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */
if (vert_ct + BUFFER_VERTS_CHUNK <= ibuf->vert->vertex_ct) {
unsigned int size = vert_ct + BUFFER_VERTS_CHUNK - 1;
size = size - size % BUFFER_VERTS_CHUNK;
GWN_vertbuf_data_resize(ibuf->vert, size);
}
- /* Send data. */
- GWN_vertbuf_use(ibuf->vert);
- /* Set as non used for the next round. */
- ibuf->shgroup = NULL;
+ GWN_vertbuf_use(ibuf->vert); /* Send data. */
+ ibuf->shgroup = NULL; /* Set as non used for the next round. */
}
else {
+ GWN_VERTBUF_DISCARD_SAFE(ibuf->vert);
GWN_BATCH_DISCARD_SAFE(ibuf->batch);
- /* Tag as non alloced. */
- ibuf->format = NULL;
+ ibuf->format = NULL; /* Tag as non alloced. */
}
}
-
- /* Resize down the handle buffer (ibuffers). */
/* Rounding up to nearest chunk size. */
- minimum_alloc_size += BUFFER_CHUNK_SIZE - 1;
- minimum_alloc_size -= minimum_alloc_size % BUFFER_CHUNK_SIZE;
+ realloc_size += BUFFER_CHUNK_SIZE - 1;
+ realloc_size -= realloc_size % BUFFER_CHUNK_SIZE;
/* Resize down if necessary. */
- if (minimum_alloc_size < idatalist->ibuffers.alloc_size) {
- idatalist->ibuffers.alloc_size = minimum_alloc_size;
- idatalist->ibuffers.ibufs = MEM_reallocN(idatalist->ibuffers.ibufs,
- minimum_alloc_size * sizeof(DRWInstanceBuffer));
+ if (realloc_size < instancing->alloc_size) {
+ instancing->alloc_size = realloc_size;
+ instancing->ibufs = MEM_reallocN(instancing->ibufs, realloc_size * sizeof(DRWInstancingBuffer));
}
}
@@ -183,7 +285,7 @@ void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist)
static DRWInstanceData *drw_instance_data_create(
DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group)
{
- DRWInstanceData *idata = MEM_mallocN(sizeof(DRWInstanceData), "DRWInstanceData");
+ DRWInstanceData *idata = MEM_callocN(sizeof(DRWInstanceData), "DRWInstanceData");
idata->next = NULL;
idata->used = true;
idata->data_size = attrib_size;
@@ -263,15 +365,18 @@ DRWInstanceData *DRW_instance_data_request(
DRWInstanceDataList *DRW_instance_data_list_create(void)
{
DRWInstanceDataList *idatalist = MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList");
- idatalist->ibuffers.ibufs = MEM_callocN(sizeof(DRWInstanceBuffer) * BUFFER_CHUNK_SIZE, "DRWInstanceBuffers");
- idatalist->ibuffers.alloc_size = BUFFER_CHUNK_SIZE;
+ idatalist->batching.bbufs = MEM_callocN(sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE, "DRWBatchingBuffers");
+ idatalist->batching.alloc_size = BUFFER_CHUNK_SIZE;
+ idatalist->instancing.ibufs = MEM_callocN(sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE, "DRWInstancingBuffers");
+ idatalist->instancing.alloc_size = BUFFER_CHUNK_SIZE;
+
+ BLI_addtail(&g_idatalists, idatalist);
return idatalist;
}
void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
{
- DRWInstanceBuffer *ibuf = idatalist->ibuffers.ibufs;
DRWInstanceData *idata, *next_idata;
for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
@@ -284,10 +389,21 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
idatalist->idata_tail[i] = NULL;
}
- for (int i = 0; i < idatalist->ibuffers.alloc_size; i++, ibuf++) {
+ DRWBatchingBuffer *bbuf = idatalist->batching.bbufs;
+ for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) {
+ GWN_VERTBUF_DISCARD_SAFE(bbuf->vert);
+ GWN_BATCH_DISCARD_SAFE(bbuf->batch);
+ }
+ MEM_freeN(idatalist->batching.bbufs);
+
+ DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs;
+ for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) {
+ GWN_VERTBUF_DISCARD_SAFE(ibuf->vert);
GWN_BATCH_DISCARD_SAFE(ibuf->batch);
}
- MEM_freeN(idatalist->ibuffers.ibufs);
+ MEM_freeN(idatalist->instancing.ibufs);
+
+ BLI_remlink(&g_idatalists, idatalist);
}
void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist)
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index a7a66c9baff..3b0f7839277 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -43,9 +43,12 @@ 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_buffer_request(
- DRWInstanceDataList *idatalist, Gwn_VertFormat *format, struct DRWShadingGroup *shgroup,
- Gwn_Batch **r_batch, Gwn_VertBuf **r_vert, Gwn_PrimType type);
+void DRW_batching_buffer_request(
+ DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_PrimType type, struct DRWShadingGroup *shgroup,
+ Gwn_Batch **r_batch, Gwn_VertBuf **r_vert);
+void DRW_instancing_buffer_request(
+ DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_Batch *instance, struct DRWShadingGroup *shgroup,
+ Gwn_Batch **r_batch, Gwn_VertBuf **r_vert);
/* Upload all instance data to the GPU as soon as possible. */
void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index a3a59efc799..dbcfa02c555 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -29,45 +29,26 @@
#include "BLI_mempool.h"
#include "BLI_rect.h"
#include "BLI_string.h"
-#include "BLI_string_utils.h"
+#include "BLI_threads.h"
-#include "BIF_glutil.h"
-
-#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
-#include "BKE_pbvh.h"
-#include "BKE_paint.h"
#include "BKE_workspace.h"
-#include "BLT_translation.h"
-#include "BLF_api.h"
-
-#include "DRW_engine.h"
-#include "DRW_render.h"
-
+#include "draw_manager.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"
+#include "ED_view3d.h"
-#include "intern/gpu_codegen.h"
-#include "GPU_batch.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
-#include "GPU_lamp.h"
-#include "GPU_material.h"
-#include "GPU_shader.h"
-#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
#include "GPU_viewport.h"
#include "GPU_matrix.h"
@@ -81,7 +62,7 @@
#include "UI_resources.h"
#include "WM_api.h"
-#include "WM_types.h"
+#include "wm_window.h"
#include "draw_manager_text.h"
#include "draw_manager_profiling.h"
@@ -89,2019 +70,30 @@
/* 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"
#include "engines/basic/basic_engine.h"
#include "engines/external/external_engine.h"
+#include "../../../intern/gawain/gawain/gwn_context.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-/* -------------------------------------------------------------------- */
-/** \name Local Features
- * \{ */
-
-#define USE_PROFILE
-
-#ifdef USE_PROFILE
-# include "PIL_time.h"
-
-# define PROFILE_TIMER_FALLOFF 0.1
-
-# define PROFILE_START(time_start) \
- double time_start = PIL_check_seconds_timer();
-
-# define PROFILE_END_ACCUM(time_accum, time_start) { \
- time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \
-} ((void)0)
-
-/* exp average */
-# define PROFILE_END_UPDATE(time_update, time_start) { \
- double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \
- time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \
- (_time_delta * PROFILE_TIMER_FALLOFF); \
-} ((void)0)
-
-#else /* USE_PROFILE */
-
-# define PROFILE_START(time_start) ((void)0)
-# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0)
-# define PROFILE_END_UPDATE(time_update, time_start) ((void)0)
-
-#endif /* USE_PROFILE */
-
-
-/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
-#define USE_GPU_SELECT
-
#ifdef USE_GPU_SELECT
-# include "ED_view3d.h"
-# include "ED_armature.h"
# include "GPU_select.h"
#endif
-/** \} */
-
-
-#define MAX_ATTRIB_NAME 32
-#define MAX_ATTRIB_COUNT 6 /* Can be adjusted for more */
-#define MAX_PASS_NAME 32
-#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
-
-extern char datatoc_gpu_shader_2D_vert_glsl[];
-extern char datatoc_gpu_shader_3D_vert_glsl[];
-extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
-
-/* Prototypes. */
-static void drw_engines_enable_external(void);
-
-/* Structures */
-typedef enum {
- DRW_UNIFORM_BOOL,
- DRW_UNIFORM_SHORT_TO_INT,
- DRW_UNIFORM_SHORT_TO_FLOAT,
- DRW_UNIFORM_INT,
- DRW_UNIFORM_FLOAT,
- DRW_UNIFORM_TEXTURE,
- DRW_UNIFORM_BUFFER,
- DRW_UNIFORM_MAT3,
- DRW_UNIFORM_MAT4,
- DRW_UNIFORM_BLOCK
-} DRWUniformType;
-
-#define MAX_UNIFORM_DATA_SIZE 16
-
-struct DRWUniform {
- struct DRWUniform *next;
- const void *value;
- int location;
- char type; /* DRWUniformType */
- char length; /* cannot be more than 16 */
- char arraysize; /* cannot be more than 16 too */
-};
-
-struct DRWInterface {
- DRWUniform *uniforms; /* DRWUniform, single-linked list */
- /* Dynamic batch */
-#ifdef USE_GPU_SELECT
- struct DRWInstanceData *inst_selectid;
- /* Override for single object instances. */
- int override_selectid;
-#endif
- Gwn_VertBuf *instance_vbo;
- unsigned int instance_count;
-#ifndef NDEBUG
- char attribs_count;
-#endif
- /* matrices locations */
- int model;
- int modelinverse;
- int modelview;
- int modelviewinverse;
- int projection;
- int projectioninverse;
- int view;
- int viewinverse;
- int modelviewprojection;
- int viewprojection;
- int viewprojectioninverse;
- int normal;
- int worldnormal;
- int camtexfac;
- int orcotexfac;
- int eye;
- int clipplanes;
-};
-
-struct DRWPass {
- /* Single linked list with last member to append */
- DRWShadingGroup *shgroups;
- DRWShadingGroup *shgroups_last;
-
- DRWState state;
- char name[MAX_PASS_NAME];
-};
-
-typedef struct DRWCallHeader {
- void *prev;
-
-#ifdef USE_GPU_SELECT
- int select_id;
-#endif
- uchar type;
-} DRWCallHeader;
-
-typedef struct DRWCall {
- DRWCallHeader head;
-
- float obmat[4][4];
- Gwn_Batch *geometry;
-
- Object *ob; /* Optional */
- ID *ob_data; /* Optional. */
-} DRWCall;
-
-typedef struct DRWCallGenerate {
- DRWCallHeader head;
-
- float obmat[4][4];
-
- DRWCallGenerateFn *geometry_fn;
- void *user_data;
-} DRWCallGenerate;
-
-struct DRWShadingGroup {
- struct DRWShadingGroup *next;
-
- GPUShader *shader; /* Shader to bind */
- DRWInterface interface; /* Uniforms pointers */
-
- /* DRWCall or DRWCallDynamic depending of type */
- void *calls;
- void *calls_first; /* To be able to traverse the list in the order of addition */
-
- DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */
- DRWState state_extra_disable; /* State changes for this batch only (and'd with the pass's state) */
- unsigned int stencil_mask; /* Stencil mask to use for stencil test / write operations */
- int type;
-
- ID *instance_data; /* Object->data to instance */
- Gwn_Batch *instance_geom; /* Geometry to instance */
- Gwn_Batch *instancing_geom;/* Instances attributes */
- Gwn_Batch *batch_geom; /* Result of call batching */
-
-#ifdef USE_GPU_SELECT
- /* backlink to pass we're in */
- DRWPass *pass_parent;
-#endif
-};
-
-/* Used by DRWShadingGroup.type */
-enum {
- DRW_SHG_NORMAL,
- DRW_SHG_POINT_BATCH,
- DRW_SHG_LINE_BATCH,
- DRW_SHG_TRIANGLE_BATCH,
- DRW_SHG_INSTANCE,
- DRW_SHG_INSTANCE_EXTERNAL,
-};
-
-/* Used by DRWCall.type */
-enum {
- /* A single batch */
- DRW_CALL_SINGLE,
- /* Uses a callback to draw with any number of batches. */
- DRW_CALL_GENERATE,
- /* Arbitrary number of multiple args. */
- DRW_CALL_DYNAMIC,
-};
-
/** Render State: No persistent data between draw calls. */
-static struct DRWGlobalState {
- /* Cache generation */
- ViewportMemoryPool *vmempool;
- DRWUniform *last_uniform;
- DRWCall *last_call;
- DRWCallGenerate *last_callgenerate;
- DRWShadingGroup *last_shgroup;
- DRWInstanceDataList *idatalist;
- DRWInstanceData *common_instance_data[MAX_INSTANCE_DATA_SIZE];
-
- /* Rendering state */
- GPUShader *shader;
-
- /* Managed by `DRW_state_set`, `DRW_state_reset` */
- DRWState state;
- unsigned int stencil_mask;
-
- /* Per viewport */
- GPUViewport *viewport;
- struct GPUFrameBuffer *default_framebuffer;
- float size[2];
- float screenvecs[2][3];
- float pixsize;
-
- GLenum backface, frontface;
-
- /* Clip planes */
- int num_clip_planes;
- float clip_planes_eq[MAX_CLIP_PLANES][4];
-
- struct {
- unsigned int is_select : 1;
- 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 */
- DRWContextState draw_ctx;
-
- /* Convenience pointer to text_store owned by the viewport */
- struct DRWTextStore **text_store_p;
-
- ListBase enabled_engines; /* RenderEngineType */
-
- bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */
-
- /* Profiling */
- double cache_time;
-} DST = {NULL};
-
-/** GPU Resource State: Memory storage between drawing. */
-static struct DRWResourceState {
- GPUTexture **bound_texs;
-
- bool *bound_tex_slots;
-
- int bind_tex_inc;
- int bind_ubo_inc;
-} RST = {NULL};
-
-static struct DRWMatrixOveride {
- float mat[6][4][4];
- bool override[6];
-} viewport_matrix_override = {{{{0}}}};
+DRWManager DST = {NULL};
ListBase DRW_engines = {NULL, NULL};
-#ifdef USE_GPU_SELECT
-static unsigned int g_DRW_select_id = (unsigned int)-1;
-
-void DRW_select_load_id(unsigned int id)
-{
- BLI_assert(G.f & G_PICKSEL);
- g_DRW_select_id = id;
-}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Textures (DRW_texture)
- * \{ */
-
-static void drw_texture_get_format(
- DRWTextureFormat format,
- GPUTextureFormat *r_data_type, int *r_channels)
-{
- switch (format) {
- case DRW_TEX_RGBA_8: *r_data_type = GPU_RGBA8; break;
- case DRW_TEX_RGBA_16: *r_data_type = GPU_RGBA16F; break;
- case DRW_TEX_RGB_16: *r_data_type = GPU_RGB16F; break;
- 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;
- case DRW_TEX_R_32: *r_data_type = GPU_R32F; break;
-#if 0
- case DRW_TEX_RGBA_32: *r_data_type = GPU_RGBA32F; break;
- case DRW_TEX_RGB_8: *r_data_type = GPU_RGB8; break;
- case DRW_TEX_RGB_32: *r_data_type = GPU_RGB32F; break;
-#endif
- case DRW_TEX_DEPTH_16: *r_data_type = GPU_DEPTH_COMPONENT16; break;
- case DRW_TEX_DEPTH_24: *r_data_type = GPU_DEPTH_COMPONENT24; break;
- case DRW_TEX_DEPTH_24_STENCIL_8: *r_data_type = GPU_DEPTH24_STENCIL8; break;
- case DRW_TEX_DEPTH_32: *r_data_type = GPU_DEPTH_COMPONENT32F; break;
- default :
- /* file type not supported you must uncomment it from above */
- BLI_assert(false);
- break;
- }
-
- switch (format) {
- case DRW_TEX_RGBA_8:
- case DRW_TEX_RGBA_16:
- case DRW_TEX_RGBA_32:
- *r_channels = 4;
- break;
- case DRW_TEX_RGB_8:
- case DRW_TEX_RGB_16:
- case DRW_TEX_RGB_32:
- case DRW_TEX_RGB_11_11_10:
- *r_channels = 3;
- 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;
- default:
- *r_channels = 1;
- break;
- }
-}
-
-static void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags)
-{
- GPU_texture_bind(tex, 0);
- if (flags & DRW_TEX_MIPMAP) {
- GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER);
- DRW_texture_generate_mipmaps(tex);
- }
- else {
- GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER);
- }
- GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP);
- GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE);
- GPU_texture_unbind(tex);
-}
-
-GPUTexture *DRW_texture_create_1D(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
-{
- GPUTexture *tex;
- GPUTextureFormat data_type;
- int channels;
-
- drw_texture_get_format(format, &data_type, &channels);
- tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL);
- drw_texture_set_parameters(tex, flags);
-
- return tex;
-}
-
-GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
-{
- GPUTexture *tex;
- GPUTextureFormat data_type;
- int channels;
-
- drw_texture_get_format(format, &data_type, &channels);
- tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL);
- drw_texture_set_parameters(tex, flags);
-
- return tex;
-}
-
-GPUTexture *DRW_texture_create_2D_array(
- int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
-{
- GPUTexture *tex;
- GPUTextureFormat data_type;
- int channels;
-
- drw_texture_get_format(format, &data_type, &channels);
- tex = GPU_texture_create_2D_array_custom(w, h, d, channels, data_type, fpixels, NULL);
- drw_texture_set_parameters(tex, flags);
-
- return tex;
-}
-
-GPUTexture *DRW_texture_create_3D(
- int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
-{
- GPUTexture *tex;
- GPUTextureFormat data_type;
- int channels;
-
- drw_texture_get_format(format, &data_type, &channels);
- tex = GPU_texture_create_3D_custom(w, h, d, channels, data_type, fpixels, NULL);
- drw_texture_set_parameters(tex, flags);
-
- return tex;
-}
-
-GPUTexture *DRW_texture_create_cube(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
-{
- GPUTexture *tex;
- GPUTextureFormat data_type;
- int channels;
-
- drw_texture_get_format(format, &data_type, &channels);
- tex = GPU_texture_create_cube_custom(w, channels, data_type, fpixels, NULL);
- drw_texture_set_parameters(tex, flags);
-
- return tex;
-}
-
-void DRW_texture_generate_mipmaps(GPUTexture *tex)
-{
- GPU_texture_bind(tex, 0);
- GPU_texture_generate_mipmap(tex);
- GPU_texture_unbind(tex);
-}
-
-void DRW_texture_update(GPUTexture *tex, const float *pixels)
-{
- GPU_texture_update(tex, pixels);
-}
-
-void DRW_texture_free(GPUTexture *tex)
-{
- GPU_texture_free(tex);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Uniform Buffer Object (DRW_uniformbuffer)
- * \{ */
-
-GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
-{
- return GPU_uniformbuffer_create(size, data, NULL);
-}
-
-void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
-{
- GPU_uniformbuffer_update(ubo, data);
-}
-
-void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
-{
- GPU_uniformbuffer_free(ubo);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Shaders (DRW_shader)
- * \{ */
-
-GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines)
-{
- return GPU_shader_create(vert, frag, geom, NULL, defines);
-}
-
-GPUShader *DRW_shader_create_with_lib(
- const char *vert, const char *geom, const char *frag, const char *lib, const char *defines)
-{
- GPUShader *sh;
- char *vert_with_lib = NULL;
- char *frag_with_lib = NULL;
- char *geom_with_lib = NULL;
-
- vert_with_lib = BLI_string_joinN(lib, vert);
- frag_with_lib = BLI_string_joinN(lib, frag);
-
- if (geom) {
- geom_with_lib = BLI_string_joinN(lib, geom);
- }
-
- sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines);
-
- MEM_freeN(vert_with_lib);
- MEM_freeN(frag_with_lib);
- if (geom) {
- MEM_freeN(geom_with_lib);
- }
-
- return sh;
-}
-
-GPUShader *DRW_shader_create_2D(const char *frag, const char *defines)
-{
- return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines);
-}
-
-GPUShader *DRW_shader_create_3D(const char *frag, const char *defines)
-{
- return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines);
-}
-
-GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines)
-{
- return GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, frag, NULL, NULL, defines);
-}
-
-GPUShader *DRW_shader_create_3D_depth_only(void)
-{
- return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
-}
-
-void DRW_shader_free(GPUShader *shader)
-{
- GPU_shader_free(shader);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Interface (DRW_interface)
- * \{ */
-
-static void drw_interface_init(DRWInterface *interface, GPUShader *shader)
-{
- interface->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL);
- interface->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV);
- interface->modelview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW);
- interface->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW_INV);
- interface->projection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_PROJECTION);
- interface->projectioninverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_PROJECTION_INV);
- interface->view = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEW);
- interface->viewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEW_INV);
- interface->viewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEWPROJECTION);
- interface->viewprojectioninverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEWPROJECTION_INV);
- interface->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MVP);
- interface->normal = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_NORMAL);
- interface->worldnormal = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_WORLDNORMAL);
- interface->camtexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_CAMERATEXCO);
- interface->orcotexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_ORCO);
- interface->clipplanes = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_CLIPPLANES);
- interface->eye = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_EYE);
- interface->instance_count = 0;
-#ifndef NDEBUG
- interface->attribs_count = 0;
-#endif
- interface->uniforms = NULL;
-#ifdef USE_GPU_SELECT
- interface->inst_selectid = NULL;
- interface->override_selectid = -1;
-#endif
-}
-
-static void drw_interface_instance_init(
- DRWShadingGroup *shgroup, GPUShader *shader, Gwn_VertFormat *format)
-{
- DRWInterface *interface = &shgroup->interface;
- drw_interface_init(interface, shader);
-
-#ifndef NDEBUG
- interface->attribs_count = (format != NULL) ? format->attrib_ct : 0;
-#endif
-
- Gwn_PrimType type;
- Gwn_Batch **r_batch = NULL;
- switch (shgroup->type) {
- case DRW_SHG_INSTANCE:
- r_batch = &shgroup->instancing_geom;
- type = GWN_PRIM_POINTS;
- break;
- case DRW_SHG_POINT_BATCH:
- r_batch = &shgroup->batch_geom;
- type = GWN_PRIM_POINTS;
- break;
- case DRW_SHG_LINE_BATCH:
- r_batch = &shgroup->batch_geom;
- type = GWN_PRIM_LINES;
- break;
- case DRW_SHG_TRIANGLE_BATCH:
- r_batch = &shgroup->batch_geom;
- type = GWN_PRIM_TRIS;
- break;
- default:
- BLI_assert(0);
- }
-
- if (format != NULL) {
- DRW_instance_buffer_request(DST.idatalist, format, shgroup, r_batch, &interface->instance_vbo, type);
- }
- else {
- *r_batch = NULL;
- }
-}
-
-static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name,
- DRWUniformType type, const void *value, int length, int arraysize)
-{
- int location;
- if (type == DRW_UNIFORM_BLOCK) {
- location = GPU_shader_get_uniform_block(shgroup->shader, name);
- }
- else {
- location = GPU_shader_get_uniform(shgroup->shader, name);
- }
-
- if (location == -1) {
- if (G.debug & G_DEBUG)
- fprintf(stderr, "Uniform '%s' not found!\n", name);
- /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
- // BLI_assert(0);
- return;
- }
-
- DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms);
-
- BLI_assert(arraysize > 0 && arraysize <= 16);
- BLI_assert(arraysize * length <= MAX_UNIFORM_DATA_SIZE);
-
- uni->location = location;
- uni->type = type;
- uni->value = value;
- uni->length = length;
- uni->arraysize = arraysize;
-
- /* Prepend */
- uni->next = shgroup->interface.uniforms;
- shgroup->interface.uniforms = uni;
-}
-
-Gwn_VertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize)
-{
- Gwn_VertFormat *format = MEM_callocN(sizeof(Gwn_VertFormat), "Gwn_VertFormat");
-
- for (int i = 0; i < arraysize; ++i) {
- GWN_vertformat_attr_add(format, attribs[i].name,
- (attribs[i].type == DRW_ATTRIB_INT) ? GWN_COMP_I32 : GWN_COMP_F32,
- attribs[i].components,
- (attribs[i].type == DRW_ATTRIB_INT) ? GWN_FETCH_INT : GWN_FETCH_FLOAT);
- }
- return format;
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Shading Group (DRW_shgroup)
- * \{ */
-
-static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
-{
- DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups);
-
- /* Append */
- if (pass->shgroups != NULL) {
- pass->shgroups_last->next = shgroup;
- }
- else {
- pass->shgroups = shgroup;
- }
- pass->shgroups_last = shgroup;
- shgroup->next = NULL;
- shgroup->type = DRW_SHG_NORMAL;
- shgroup->shader = shader;
- shgroup->state_extra = 0;
- shgroup->state_extra_disable = ~0x0;
- shgroup->stencil_mask = 0;
- shgroup->batch_geom = NULL;
- shgroup->instancing_geom = NULL;
- shgroup->instance_geom = NULL;
- shgroup->instance_data = NULL;
-
- shgroup->calls = NULL;
- shgroup->calls_first = NULL;
-
-#ifdef USE_GPU_SELECT
- shgroup->pass_parent = pass;
-#endif
-
- return shgroup;
-}
-
-static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass *pass)
-{
- if (!gpupass) {
- /* Shader compilation error */
- return NULL;
- }
-
- DRWShadingGroup *grp = drw_shgroup_create_ex(GPU_pass_shader(gpupass), pass);
- return grp;
-}
-
-static DRWShadingGroup *drw_shgroup_material_inputs(
- DRWShadingGroup *grp, struct GPUMaterial *material, GPUPass *gpupass)
-{
- /* TODO : Ideally we should not convert. But since the whole codegen
- * is relying on GPUPass we keep it as is for now. */
-
- /* Converting dynamic GPUInput to DRWUniform */
- ListBase *inputs = &gpupass->inputs;
-
- for (GPUInput *input = inputs->first; input; input = input->next) {
- /* Textures */
- if (input->ima) {
- double time = 0.0; /* TODO make time variable */
- GPUTexture *tex = GPU_texture_from_blender(
- input->ima, input->iuser, input->textarget, input->image_isdata, time, 1);
-
- if (input->bindtex) {
- DRW_shgroup_uniform_texture(grp, input->shadername, tex);
- }
- }
- /* Color Ramps */
- else if (input->tex) {
- DRW_shgroup_uniform_texture(grp, input->shadername, input->tex);
- }
- /* Floats */
- else {
- switch (input->type) {
- case GPU_FLOAT:
- case GPU_VEC2:
- case GPU_VEC3:
- case GPU_VEC4:
- /* Should already be in the material ubo. */
- break;
- case GPU_MAT3:
- DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec);
- break;
- case GPU_MAT4:
- DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec);
- break;
- default:
- break;
- }
- }
- }
-
- GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material);
- if (ubo != NULL) {
- DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
- }
-
- return grp;
-}
-
-DRWShadingGroup *DRW_shgroup_material_create(
- struct GPUMaterial *material, DRWPass *pass)
-{
- GPUPass *gpupass = GPU_material_get_pass(material);
- DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
-
- if (shgroup) {
- drw_interface_init(&shgroup->interface, GPU_pass_shader(gpupass));
- drw_shgroup_material_inputs(shgroup, material, gpupass);
- }
-
- return shgroup;
-}
-
-DRWShadingGroup *DRW_shgroup_material_instance_create(
- struct GPUMaterial *material, DRWPass *pass, Gwn_Batch *geom, Object *ob, Gwn_VertFormat *format)
-{
- GPUPass *gpupass = GPU_material_get_pass(material);
- DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
-
- if (shgroup) {
- shgroup->type = DRW_SHG_INSTANCE;
- shgroup->instance_geom = geom;
- shgroup->instance_data = ob->data;
- drw_interface_instance_init(shgroup, GPU_pass_shader(gpupass), format);
- drw_shgroup_material_inputs(shgroup, material, gpupass);
- }
-
- return shgroup;
-}
-
-DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(
- struct GPUMaterial *material, DRWPass *pass, int size)
-{
-#ifdef USE_GPU_SELECT
- BLI_assert((G.f & G_PICKSEL) == 0);
-#endif
- GPUPass *gpupass = GPU_material_get_pass(material);
- DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
-
- if (shgroup) {
- shgroup->type = DRW_SHG_TRIANGLE_BATCH;
- shgroup->interface.instance_count = size * 3;
- /* Calling drw_interface_init will cause it to GWN_batch_draw_procedural. */
- drw_interface_init(&shgroup->interface, GPU_pass_shader(gpupass));
- drw_shgroup_material_inputs(shgroup, material, gpupass);
- }
-
- return shgroup;
-}
-
-DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
-{
- DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
- drw_interface_init(&shgroup->interface, shader);
- return shgroup;
-}
-
-DRWShadingGroup *DRW_shgroup_instance_create(
- struct GPUShader *shader, DRWPass *pass, Gwn_Batch *geom, Gwn_VertFormat *format)
-{
- DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
- shgroup->type = DRW_SHG_INSTANCE;
- shgroup->instance_geom = geom;
-
- drw_interface_instance_init(shgroup, shader, format);
-
- return shgroup;
-}
-
-static Gwn_VertFormat *g_pos_format = NULL;
-
-DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass)
-{
- DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
-
- DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
- shgroup->type = DRW_SHG_POINT_BATCH;
-
- drw_interface_instance_init(shgroup, shader, g_pos_format);
-
- return shgroup;
-}
-
-DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass)
-{
- DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
-
- DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
- shgroup->type = DRW_SHG_LINE_BATCH;
-
- drw_interface_instance_init(shgroup, shader, g_pos_format);
-
- return shgroup;
-}
-
-/* Very special batch. Use this if you position
- * your vertices with the vertex shader
- * and dont need any VBO attrib */
-DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int size)
-{
-#ifdef USE_GPU_SELECT
- BLI_assert((G.f & G_PICKSEL) == 0);
-#endif
- DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
-
- /* Calling drw_interface_init will cause it to GWN_batch_draw_procedural. */
- drw_interface_init(&shgroup->interface, shader);
-
- shgroup->type = DRW_SHG_TRIANGLE_BATCH;
- shgroup->interface.instance_count = size * 3;
-
- return shgroup;
-}
-
-void DRW_shgroup_free(struct DRWShadingGroup *UNUSED(shgroup))
-{
- return;
-}
-
-#define CALL_PREPEND(shgroup, call) { \
- if (shgroup->calls == NULL) { \
- shgroup->calls = call; \
- shgroup->calls_first = call; \
- } \
- else { \
- ((DRWCall *)(shgroup->calls))->head.prev = call; \
- shgroup->calls = call; \
- } \
- call->head.prev = NULL; \
-} ((void)0)
-
-/* Specify an external batch instead of adding each attrib one by one. */
-void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances)
-{
- BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
- BLI_assert(shgroup->instancing_geom == NULL);
-
- shgroup->type = DRW_SHG_INSTANCE_EXTERNAL;
- shgroup->instancing_geom = 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);
-
- CALL_PREPEND(shgroup, call);
-
- call->head.type = DRW_CALL_SINGLE;
-#ifdef USE_GPU_SELECT
- call->head.select_id = g_DRW_select_id;
-#endif
-
- if (obmat != NULL) {
- copy_m4_m4(call->obmat, obmat);
- }
-
- call->geometry = geom;
- call->ob_data = NULL;
-}
-
-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);
-
- CALL_PREPEND(shgroup, call);
-
- call->head.type = DRW_CALL_SINGLE;
-#ifdef USE_GPU_SELECT
- call->head.select_id = g_DRW_select_id;
-#endif
-
- copy_m4_m4(call->obmat, ob->obmat);
- call->geometry = geom;
- call->ob_data = ob->data;
-}
-
-void DRW_shgroup_call_generate_add(
- DRWShadingGroup *shgroup,
- DRWCallGenerateFn *geometry_fn, void *user_data,
- float (*obmat)[4])
-{
- BLI_assert(geometry_fn != NULL);
- BLI_assert(shgroup->type == DRW_SHG_NORMAL);
-
- DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate);
-
- CALL_PREPEND(shgroup, call);
-
- call->head.type = DRW_CALL_GENERATE;
-#ifdef USE_GPU_SELECT
- call->head.select_id = g_DRW_select_id;
-#endif
-
- if (obmat != NULL) {
- copy_m4_m4(call->obmat, obmat);
- }
-
- call->geometry_fn = geometry_fn;
- call->user_data = user_data;
-}
-
-static void sculpt_draw_cb(
- DRWShadingGroup *shgroup,
- void (*draw_fn)(DRWShadingGroup *shgroup, Gwn_Batch *geom),
- void *user_data)
-{
- Object *ob = user_data;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- if (pbvh) {
- BKE_pbvh_draw_cb(
- pbvh, NULL, NULL, false,
- (void (*)(void *, Gwn_Batch *))draw_fn, shgroup);
- }
-}
-
-void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4])
-{
- DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat);
-}
-
-void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len)
-{
- DRWInterface *interface = &shgroup->interface;
-
-#ifdef USE_GPU_SELECT
- if (G.f & G_PICKSEL) {
- if (interface->inst_selectid == NULL) {
- interface->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128);
- }
-
- int *select_id = DRW_instance_data_next(interface->inst_selectid);
- *select_id = g_DRW_select_id;
- }
-#endif
-
- BLI_assert(attr_len == interface->attribs_count);
- UNUSED_VARS_NDEBUG(attr_len);
-
- for (int i = 0; i < attr_len; ++i) {
- if (interface->instance_count == interface->instance_vbo->vertex_ct) {
- GWN_vertbuf_data_resize(interface->instance_vbo, interface->instance_count + 32);
- }
- GWN_vertbuf_attr_set(interface->instance_vbo, i, interface->instance_count, attr[i]);
- }
-
- interface->instance_count += 1;
-}
-
-/* Used for instancing with no attributes */
-void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, unsigned 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;
-}
-
-unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup)
-{
- BLI_assert(shgroup->type != DRW_SHG_NORMAL && shgroup->type != DRW_SHG_INSTANCE_EXTERNAL);
-
- return shgroup->interface.instance_count;
-}
-
-/**
- * State is added to #Pass.state while drawing.
- * Use to temporarily enable draw options.
- */
-void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
-{
- shgroup->state_extra |= state;
-}
-
-void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
-{
- shgroup->state_extra_disable &= ~state;
-}
-
-void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask)
-{
- BLI_assert(mask <= 255);
- shgroup->stencil_mask = mask;
-}
-
-void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
-}
-
-void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
-}
-
-void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1);
-}
-
-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);
-}
-
-void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize);
-}
-
-void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize);
-}
-
-void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize);
-}
-
-void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize);
-}
-
-void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize);
-}
-
-void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize);
-}
-
-void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
-}
-
-void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize);
-}
-
-void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize);
-}
-
-void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1);
-}
-
-void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value)
-{
- drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1);
-}
-
-/** \} */
-
+extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */
/* -------------------------------------------------------------------- */
-/** \name Passes (DRW_pass)
- * \{ */
-
-DRWPass *DRW_pass_create(const char *name, DRWState state)
-{
- DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes);
- pass->state = state;
- BLI_strncpy(pass->name, name, MAX_PASS_NAME);
-
- pass->shgroups = NULL;
- pass->shgroups_last = NULL;
-
- 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) {
- DRW_shgroup_free(shgroup);
- }
-
- pass->shgroups = NULL;
- pass->shgroups_last = NULL;
-}
-
-void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData)
-{
- for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) {
- callback(userData, shgroup);
- }
-}
-
-typedef struct ZSortData {
- float *axis;
- float *origin;
-} ZSortData;
-
-static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
-{
- const ZSortData *zsortdata = (ZSortData *)thunk;
- const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
- const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
-
- const DRWCall *call_a;
- const DRWCall *call_b;
-
- call_a = shgrp_a->calls_first;
- call_b = shgrp_b->calls_first;
-
- if (call_a == NULL) return -1;
- if (call_b == NULL) return -1;
-
- float tmp[3];
- sub_v3_v3v3(tmp, zsortdata->origin, call_a->obmat[3]);
- const float a_sq = dot_v3v3(zsortdata->axis, tmp);
- sub_v3_v3v3(tmp, zsortdata->origin, call_b->obmat[3]);
- const float b_sq = dot_v3v3(zsortdata->axis, tmp);
-
- if (a_sq < b_sq) return 1;
- else if (a_sq > b_sq) return -1;
- else {
- /* If there is a depth prepass put it before */
- if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
- return -1;
- }
- else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
- return 1;
- }
- else return 0;
- }
-}
-
-/* ------------------ Shading group sorting --------------------- */
-
-#define SORT_IMPL_LINKTYPE DRWShadingGroup
-
-#define SORT_IMPL_USE_THUNK
-#define SORT_IMPL_FUNC shgroup_sort_fn_r
-#include "../../blenlib/intern/list_sort_impl.h"
-#undef SORT_IMPL_FUNC
-#undef SORT_IMPL_USE_THUNK
-
-#undef SORT_IMPL_LINKTYPE
-
-/**
- * Sort Shading groups by decreasing Z of their first draw call.
- * This is usefull for order dependant effect such as transparency.
- **/
-void DRW_pass_sort_shgroup_z(DRWPass *pass)
-{
- RegionView3D *rv3d = DST.draw_ctx.rv3d;
-
- float (*viewinv)[4];
- viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV])
- ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv;
-
- ZSortData zsortdata = {viewinv[2], viewinv[3]};
-
- if (pass->shgroups && pass->shgroups->next) {
- pass->shgroups = shgroup_sort_fn_r(pass->shgroups, pass_shgroup_dist_sort, &zsortdata);
-
- /* Find the next last */
- DRWShadingGroup *last = pass->shgroups;
- while ((last = last->next)) {
- /* Do nothing */
- }
- pass->shgroups_last = last;
- }
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \name Draw (DRW_draw)
- * \{ */
-
-static void drw_state_set(DRWState state)
-{
- if (DST.state == state) {
- return;
- }
-
-
-#define CHANGED_TO(f) \
- ((DST.state & (f)) ? \
- ((state & (f)) ? 0 : -1) : \
- ((state & (f)) ? 1 : 0))
-
-#define CHANGED_ANY(f) \
- ((DST.state & (f)) != (state & (f)))
-
-#define CHANGED_ANY_STORE_VAR(f, enabled) \
- ((DST.state & (f)) != (enabled = (state & (f))))
-
- /* Depth Write */
- {
- int test;
- if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) {
- if (test == 1) {
- glDepthMask(GL_TRUE);
- }
- else {
- glDepthMask(GL_FALSE);
- }
- }
- }
-
- /* Color Write */
- {
- int test;
- if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) {
- if (test == 1) {
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- }
- else {
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- }
- }
- }
-
- /* Cull */
- {
- DRWState test;
- if (CHANGED_ANY_STORE_VAR(
- DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT,
- test))
- {
- if (test) {
- glEnable(GL_CULL_FACE);
-
- if ((state & DRW_STATE_CULL_BACK) != 0) {
- glCullFace(GL_BACK);
- }
- else if ((state & DRW_STATE_CULL_FRONT) != 0) {
- glCullFace(GL_FRONT);
- }
- else {
- BLI_assert(0);
- }
- }
- else {
- glDisable(GL_CULL_FACE);
- }
- }
- }
-
- /* Depth Test */
- {
- DRWState test;
- if (CHANGED_ANY_STORE_VAR(
- DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER | DRW_STATE_DEPTH_ALWAYS,
- test))
- {
- if (test) {
- glEnable(GL_DEPTH_TEST);
-
- if (state & DRW_STATE_DEPTH_LESS) {
- glDepthFunc(GL_LEQUAL);
- }
- else if (state & DRW_STATE_DEPTH_EQUAL) {
- glDepthFunc(GL_EQUAL);
- }
- else if (state & DRW_STATE_DEPTH_GREATER) {
- glDepthFunc(GL_GREATER);
- }
- else if (state & DRW_STATE_DEPTH_ALWAYS) {
- glDepthFunc(GL_ALWAYS);
- }
- else {
- BLI_assert(0);
- }
- }
- else {
- glDisable(GL_DEPTH_TEST);
- }
- }
- }
-
- /* Wire Width */
- {
- if (CHANGED_ANY(DRW_STATE_WIRE | DRW_STATE_WIRE_LARGE)) {
- if ((state & DRW_STATE_WIRE) != 0) {
- glLineWidth(1.0f);
- }
- else if ((state & DRW_STATE_WIRE_LARGE) != 0) {
- glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- }
- else {
- /* do nothing */
- }
- }
- }
-
- /* Points Size */
- {
- int test;
- if ((test = CHANGED_TO(DRW_STATE_POINT))) {
- if (test == 1) {
- GPU_enable_program_point_size();
- glPointSize(5.0f);
- }
- else {
- GPU_disable_program_point_size();
- }
- }
- }
-
- /* Blending (all buffer) */
- {
- int test;
- if (CHANGED_ANY_STORE_VAR(
- 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) {
- 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);
- }
- else if ((state & DRW_STATE_TRANSMISSION) != 0) {
- glBlendFunc(GL_ONE, GL_SRC_ALPHA);
- }
- else if ((state & DRW_STATE_ADDITIVE) != 0) {
- /* 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);
- }
- }
- else {
- glDisable(GL_BLEND);
- }
- }
- }
-
- /* Clip Planes */
- {
- int test;
- if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) {
- if (test == 1) {
- for (int i = 0; i < DST.num_clip_planes; ++i) {
- glEnable(GL_CLIP_DISTANCE0 + i);
- }
- }
- else {
- for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
- glDisable(GL_CLIP_DISTANCE0 + i);
- }
- }
- }
- }
-
- /* Line Stipple */
- {
- int test;
- if (CHANGED_ANY_STORE_VAR(
- DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4,
- test))
- {
- if (test) {
- if ((state & DRW_STATE_STIPPLE_2) != 0) {
- setlinestyle(2);
- }
- else if ((state & DRW_STATE_STIPPLE_3) != 0) {
- setlinestyle(3);
- }
- else if ((state & DRW_STATE_STIPPLE_4) != 0) {
- setlinestyle(4);
- }
- else {
- BLI_assert(0);
- }
- }
- else {
- setlinestyle(0);
- }
- }
- }
-
- /* Stencil */
- {
- DRWState test;
- if (CHANGED_ANY_STORE_VAR(
- DRW_STATE_WRITE_STENCIL |
- DRW_STATE_STENCIL_EQUAL,
- test))
- {
- if (test) {
- glEnable(GL_STENCIL_TEST);
-
- /* Stencil Write */
- if ((state & DRW_STATE_WRITE_STENCIL) != 0) {
- glStencilMask(0xFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- }
- /* Stencil Test */
- else if ((state & DRW_STATE_STENCIL_EQUAL) != 0) {
- glStencilMask(0x00); /* disable write */
- DST.stencil_mask = 0;
- }
- else {
- BLI_assert(0);
- }
- }
- else {
- /* disable write & test */
- DST.stencil_mask = 0;
- glStencilMask(0x00);
- glStencilFunc(GL_ALWAYS, 1, 0xFF);
- glDisable(GL_STENCIL_TEST);
- }
- }
- }
-
-#undef CHANGED_TO
-#undef CHANGED_ANY
-#undef CHANGED_ANY_STORE_VAR
-
- DST.state = state;
-}
-
-static void drw_stencil_set(unsigned int mask)
-{
- if (DST.stencil_mask != mask) {
- /* Stencil Write */
- if ((DST.state & DRW_STATE_WRITE_STENCIL) != 0) {
- glStencilFunc(GL_ALWAYS, mask, 0xFF);
- DST.stencil_mask = mask;
- }
- /* Stencil Test */
- else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) {
- glStencilFunc(GL_EQUAL, mask, 0xFF);
- DST.stencil_mask = mask;
- }
- }
-}
-
-typedef struct DRWBoundTexture {
- struct DRWBoundTexture *next, *prev;
- GPUTexture *tex;
-} DRWBoundTexture;
-
-static void draw_geometry_prepare(
- DRWShadingGroup *shgroup, const float (*obmat)[4], const float *texcoloc, const float *texcosize)
-{
- RegionView3D *rv3d = DST.draw_ctx.rv3d;
- DRWInterface *interface = &shgroup->interface;
-
- float mvp[4][4], mv[4][4], mi[4][4], mvi[4][4], pi[4][4], n[3][3], wn[3][3];
- float orcofacs[2][3] = {{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
- float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
- float viewcamtexcofac[4] = { 1.0f, 1.0f, 0.0f, 0.0f };
-
- if (rv3d != NULL) {
- copy_v4_v4(viewcamtexcofac, rv3d->viewcamtexcofac);
- }
-
- bool do_pi = (interface->projectioninverse != -1);
- bool do_mvp = (interface->modelviewprojection != -1);
- bool do_mi = (interface->modelinverse != -1);
- bool do_mv = (interface->modelview != -1);
- bool do_mvi = (interface->modelviewinverse != -1);
- bool do_n = (interface->normal != -1);
- bool do_wn = (interface->worldnormal != -1);
- bool do_eye = (interface->eye != -1);
- bool do_orco = (interface->orcotexfac != -1) && (texcoloc != NULL) && (texcosize != NULL);
-
- /* Matrix override */
- float (*persmat)[4];
- float (*persinv)[4];
- float (*viewmat)[4];
- float (*viewinv)[4];
- float (*winmat)[4];
- float (*wininv)[4];
-
- persmat = (viewport_matrix_override.override[DRW_MAT_PERS])
- ? viewport_matrix_override.mat[DRW_MAT_PERS] : rv3d->persmat;
- persinv = (viewport_matrix_override.override[DRW_MAT_PERSINV])
- ? viewport_matrix_override.mat[DRW_MAT_PERSINV] : rv3d->persinv;
- viewmat = (viewport_matrix_override.override[DRW_MAT_VIEW])
- ? viewport_matrix_override.mat[DRW_MAT_VIEW] : rv3d->viewmat;
- viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV])
- ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv;
- winmat = (viewport_matrix_override.override[DRW_MAT_WIN])
- ? viewport_matrix_override.mat[DRW_MAT_WIN] : rv3d->winmat;
- wininv = viewport_matrix_override.mat[DRW_MAT_WININV];
-
- if (do_pi) {
- if (!viewport_matrix_override.override[DRW_MAT_WININV]) {
- invert_m4_m4(pi, winmat);
- wininv = pi;
- }
- }
- if (do_mi) {
- invert_m4_m4(mi, obmat);
- }
- if (do_mvp) {
- mul_m4_m4m4(mvp, persmat, obmat);
- }
- if (do_mv || do_mvi || do_n || do_eye) {
- mul_m4_m4m4(mv, viewmat, obmat);
- }
- if (do_mvi) {
- invert_m4_m4(mvi, mv);
- }
- if (do_n || do_eye) {
- copy_m3_m4(n, mv);
- invert_m3(n);
- transpose_m3(n);
- }
- if (do_wn) {
- copy_m3_m4(wn, obmat);
- invert_m3(wn);
- transpose_m3(wn);
- }
- if (do_eye) {
- /* Used by orthographic wires */
- float tmp[3][3];
- invert_m3_m3(tmp, n);
- /* set eye vector, transformed to object coords */
- mul_m3_v3(tmp, eye);
- }
- if (do_orco) {
- mul_v3_v3fl(orcofacs[1], texcosize, 2.0f);
- invert_v3(orcofacs[1]);
- sub_v3_v3v3(orcofacs[0], texcoloc, texcosize);
- negate_v3(orcofacs[0]);
- mul_v3_v3(orcofacs[0], orcofacs[1]); /* result in a nice MADD in the shader */
- }
-
- /* Should be really simple */
- /* step 1 : bind object dependent matrices */
- /* TODO : Some of these are not object dependant.
- * They should be grouped inside a UBO updated once per redraw.
- * The rest can also go into a UBO to reduce API calls. */
- GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)obmat);
- GPU_shader_uniform_vector(shgroup->shader, interface->modelinverse, 16, 1, (float *)mi);
- GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp);
- GPU_shader_uniform_vector(shgroup->shader, interface->viewinverse, 16, 1, (float *)viewinv);
- GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)persmat);
- GPU_shader_uniform_vector(shgroup->shader, interface->viewprojectioninverse, 16, 1, (float *)persinv);
- GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)winmat);
- GPU_shader_uniform_vector(shgroup->shader, interface->projectioninverse, 16, 1, (float *)wininv);
- GPU_shader_uniform_vector(shgroup->shader, interface->view, 16, 1, (float *)viewmat);
- GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv);
- GPU_shader_uniform_vector(shgroup->shader, interface->modelviewinverse, 16, 1, (float *)mvi);
- GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n);
- GPU_shader_uniform_vector(shgroup->shader, interface->worldnormal, 9, 1, (float *)wn);
- GPU_shader_uniform_vector(shgroup->shader, interface->camtexfac, 4, 1, (float *)viewcamtexcofac);
- GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)orcofacs);
- GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye);
- GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq);
-}
-
-static void draw_geometry_execute_ex(
- DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count)
-{
- /* Special case: empty drawcall, placement is done via shader, don't bind anything. */
- if (geom == NULL) {
- BLI_assert(shgroup->type == DRW_SHG_TRIANGLE_BATCH); /* Add other type if needed. */
- /* Shader is already bound. */
- Gwn_Batch *batch = DRW_cache_fullscreen_quad_get();
- GWN_batch_draw_procedural(batch, GWN_PRIM_TRIS, count);
- return;
- }
-
- /* step 2 : bind vertex array & draw */
- GWN_batch_program_set(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
- if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) {
- GWN_batch_draw_stupid_instanced(geom, shgroup->instancing_geom, start, count);
- }
- else {
- 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_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;
-
- if (ob_data != NULL) {
- switch (GS(ob_data->name)) {
- 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:
- break;
- }
- }
-
- draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize);
-
- draw_geometry_execute_ex(shgroup, geom, start, count);
-}
-
-static void bind_texture(GPUTexture *tex)
-{
- int bind_num = GPU_texture_bound_number(tex);
- if (bind_num == -1) {
- for (int i = 0; i < GPU_max_textures(); ++i) {
- RST.bind_tex_inc = (RST.bind_tex_inc + 1) % GPU_max_textures();
- if (RST.bound_tex_slots[RST.bind_tex_inc] == false) {
- if (RST.bound_texs[RST.bind_tex_inc] != NULL) {
- GPU_texture_unbind(RST.bound_texs[RST.bind_tex_inc]);
- }
- GPU_texture_bind(tex, RST.bind_tex_inc);
- RST.bound_texs[RST.bind_tex_inc] = tex;
- RST.bound_tex_slots[RST.bind_tex_inc] = true;
- // printf("Binds Texture %d %p\n", RST.bind_tex_inc, tex);
- return;
- }
- }
-
- printf("Not enough texture slots! Reduce number of textures used by your shader.\n");
- }
- RST.bound_tex_slots[bind_num] = true;
-}
-
-static void bind_ubo(GPUUniformBuffer *ubo)
-{
- if (RST.bind_ubo_inc < GPU_max_ubo_binds()) {
- GPU_uniformbuffer_bind(ubo, RST.bind_ubo_inc);
- RST.bind_ubo_inc++;
- }
- else {
- /* This is not depending on user input.
- * It is our responsability to make sure there enough slots. */
- BLI_assert(0 && "Not enough ubo slots! This should not happen!\n");
-
- /* printf so user can report bad behaviour */
- printf("Not enough ubo slots! This should not happen!\n");
- }
-}
-
-static void release_texture_slots(void)
-{
- memset(RST.bound_tex_slots, 0x0, sizeof(bool) * GPU_max_textures());
-}
-
-static void release_ubo_slots(void)
-{
- RST.bind_ubo_inc = 0;
-}
-
-static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
-{
- BLI_assert(shgroup->shader);
-
- DRWInterface *interface = &shgroup->interface;
- GPUTexture *tex;
- GPUUniformBuffer *ubo;
- int val;
- float fval;
-
- if (DST.shader != shgroup->shader) {
- if (DST.shader) GPU_shader_unbind();
- GPU_shader_bind(shgroup->shader);
- DST.shader = shgroup->shader;
- }
-
- release_texture_slots();
- release_ubo_slots();
-
- drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
- drw_stencil_set(shgroup->stencil_mask);
-
- /* Binding Uniform */
- /* Don't check anything, Interface should already contain the least uniform as possible */
- for (DRWUniform *uni = interface->uniforms; uni; uni = uni->next) {
- switch (uni->type) {
- case DRW_UNIFORM_SHORT_TO_INT:
- val = (int)*((short *)uni->value);
- GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)&val);
- break;
- case DRW_UNIFORM_SHORT_TO_FLOAT:
- fval = (float)*((short *)uni->value);
- GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval);
- break;
- case DRW_UNIFORM_BOOL:
- case DRW_UNIFORM_INT:
- GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value);
- break;
- case DRW_UNIFORM_FLOAT:
- case DRW_UNIFORM_MAT3:
- case DRW_UNIFORM_MAT4:
- GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value);
- break;
- case DRW_UNIFORM_TEXTURE:
- tex = (GPUTexture *)uni->value;
- BLI_assert(tex);
- bind_texture(tex);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_BUFFER:
- if (!DRW_state_is_fbo()) {
- break;
- }
- tex = *((GPUTexture **)uni->value);
- BLI_assert(tex);
- bind_texture(tex);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_BLOCK:
- ubo = (GPUUniformBuffer *)uni->value;
- bind_ubo(ubo);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
- }
- }
-
-#ifdef USE_GPU_SELECT
- /* use the first item because of selection we only ever add one */
-# define GPU_SELECT_LOAD_IF_PICKSEL(_call) \
- if ((G.f & G_PICKSEL) && (_call)) { \
- GPU_select_load_id((_call)->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_END(start, count)
-# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \
- _start = 0; \
- _count = _shgroup->interface.instance_count;
-
-#endif
-
- /* Rendering Calls */
- if (!ELEM(shgroup->type, DRW_SHG_NORMAL)) {
- /* Replacing multiple calls with only one */
- float obmat[4][4];
- unit_m4(obmat);
-
- if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) {
- if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) {
- if (shgroup->instancing_geom != NULL) {
- GPU_SELECT_LOAD_IF_PICKSEL((DRWCall *)shgroup->calls_first);
- draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, 0, 0);
- }
- }
- else {
- if (shgroup->interface.instance_count > 0) {
- 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->interface.instance_count > 0) {
- 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)
- }
- }
- }
- else {
- for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) {
- bool neg_scale = is_negative_m4(call->obmat);
-
- /* Negative scale objects */
- if (neg_scale) {
- glFrontFace(DST.backface);
- }
-
- GPU_SELECT_LOAD_IF_PICKSEL(call);
-
- if (call->head.type == DRW_CALL_SINGLE) {
- draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data, 0, 0);
- }
- else {
- BLI_assert(call->head.type == DRW_CALL_GENERATE);
- DRWCallGenerate *callgen = ((DRWCallGenerate *)call);
- draw_geometry_prepare(shgroup, callgen->obmat, NULL, NULL);
- callgen->geometry_fn(shgroup, draw_geometry_execute, callgen->user_data);
- }
-
- /* Reset state */
- if (neg_scale) {
- glFrontFace(DST.frontface);
- }
- }
- }
-
- /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */
- DRW_state_reset();
-}
-
-static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
-{
- /* Start fresh */
- DST.shader = NULL;
-
- BLI_assert(DST.buffer_finish_called && "DRW_render_instance_buffer_finish had not been called before drawing");
-
- drw_state_set(pass->state);
-
- DRW_stats_query_start(pass->name);
-
- for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) {
- draw_shgroup(shgroup, pass->state);
- /* break if upper limit */
- if (shgroup == end_group) {
- break;
- }
- }
-
- /* Clear Bound textures */
- for (int i = 0; i < GPU_max_textures(); i++) {
- if (RST.bound_texs[i] != NULL) {
- GPU_texture_unbind(RST.bound_texs[i]);
- RST.bound_texs[i] = NULL;
- }
- }
-
- if (DST.shader) {
- GPU_shader_unbind();
- DST.shader = NULL;
- }
-
- DRW_stats_query_end();
-}
-
-void DRW_draw_pass(DRWPass *pass)
-{
- drw_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last);
-}
-
-/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
-void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
-{
- drw_draw_pass_ex(pass, start_group, end_group);
-}
-
void DRW_draw_callbacks_pre_scene(void)
{
RegionView3D *rv3d = DST.draw_ctx.rv3d;
@@ -2118,46 +110,6 @@ void DRW_draw_callbacks_post_scene(void)
gpuLoadMatrix(rv3d->viewmat);
}
-/* Reset state to not interfer with other UI drawcall */
-void DRW_state_reset_ex(DRWState state)
-{
- DST.state = ~state;
- drw_state_set(state);
-}
-
-void DRW_state_reset(void)
-{
- /* Reset blending function */
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- DRW_state_reset_ex(DRW_STATE_DEFAULT);
-}
-
-/* NOTE : Make sure to reset after use! */
-void DRW_state_invert_facing(void)
-{
- SWAP(GLenum, DST.backface, DST.frontface);
- glFrontFace(DST.frontface);
-}
-
-/**
- * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
- * and if the shaders have support for it (see usage of gl_ClipDistance).
- * Be sure to call DRW_state_clip_planes_reset() after you finish drawing.
- **/
-void DRW_state_clip_planes_add(float plane_eq[4])
-{
- copy_v4_v4(DST.clip_planes_eq[DST.num_clip_planes++], plane_eq);
-}
-
-void DRW_state_clip_planes_reset(void)
-{
- DST.num_clip_planes = 0;
-}
-
-/** \} */
-
-
struct DRWTextStore *DRW_text_cache_ensure(void)
{
BLI_assert(DST.text_store_p);
@@ -2223,6 +175,7 @@ bool DRW_object_is_flat_normal(const Object *ob)
int DRW_object_is_mode_shade(const Object *ob)
{
BLI_assert(ob == DST.draw_ctx.obact);
+ UNUSED_VARS_NDEBUG(ob);
if ((DST.draw_ctx.object_mode & OB_MODE_EDIT) == 0) {
if (DST.draw_ctx.object_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) {
if ((DST.draw_ctx.v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) == 0) {
@@ -2241,198 +194,9 @@ int DRW_object_is_mode_shade(const Object *ob)
/* -------------------------------------------------------------------- */
-/** \name Framebuffers (DRW_framebuffer)
+/** \name Color Management
* \{ */
-static GPUTextureFormat convert_tex_format(
- int fbo_format,
- int *r_channels, bool *r_is_depth)
-{
- *r_is_depth = ELEM(fbo_format, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24, DRW_TEX_DEPTH_24_STENCIL_8);
-
- switch (fbo_format) {
- case DRW_TEX_R_16: *r_channels = 1; return GPU_R16F;
- 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;
- case DRW_TEX_RGBA_32: *r_channels = 4; return GPU_RGBA32F;
- case DRW_TEX_DEPTH_16: *r_channels = 1; return GPU_DEPTH_COMPONENT16;
- case DRW_TEX_DEPTH_24: *r_channels = 1; return GPU_DEPTH_COMPONENT24;
- case DRW_TEX_DEPTH_24_STENCIL_8: *r_channels = 1; return GPU_DEPTH24_STENCIL8;
- case DRW_TEX_DEPTH_32: *r_channels = 1; return GPU_DEPTH_COMPONENT32F;
- case DRW_TEX_RGB_11_11_10: *r_channels = 3; return GPU_R11F_G11F_B10F;
- default:
- BLI_assert(false && "Texture format unsupported as render target!");
- *r_channels = 4; return GPU_RGBA8;
- }
-}
-
-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;
-
- if (!*fb) {
- *fb = GPU_framebuffer_create();
- create_fb = true;
- }
-
- 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;
-
- GPUTextureFormat gpu_format = convert_tex_format(fbotex.format, &channels, &is_depth);
-
- if (!*fbotex.tex || is_temp) {
- /* Temp textures need to be queried each frame, others not. */
- if (is_temp) {
- *fbotex.tex = GPU_viewport_texture_pool_query(
- DST.viewport, engine_type, width, height, channels, gpu_format);
- }
- else {
- *fbotex.tex = GPU_texture_create_2D_custom(
- width, height, channels, gpu_format, NULL, NULL);
- create_tex = true;
- }
- }
-
- 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);
- }
- }
-
- if (create_fb && (textures_len > 0)) {
- if (!GPU_framebuffer_check_valid(*fb, NULL)) {
- printf("Error invalid framebuffer\n");
- }
-
- /* Detach temp textures */
- for (int i = 0; i < textures_len; ++i) {
- DRWFboTexture fbotex = textures[i];
-
- if ((fbotex.flag & DRW_TEX_TEMP) != 0) {
- GPU_framebuffer_texture_detach(*fbotex.tex);
- }
- }
-
- if (DST.default_framebuffer != NULL) {
- GPU_framebuffer_bind(DST.default_framebuffer);
- }
- }
-}
-
-void DRW_framebuffer_free(struct GPUFrameBuffer *fb)
-{
- GPU_framebuffer_free(fb);
-}
-
-void DRW_framebuffer_bind(struct GPUFrameBuffer *fb)
-{
- GPU_framebuffer_bind(fb);
-}
-
-void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth)
-{
- if (color) {
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
- }
- if (depth) {
- glDepthMask(GL_TRUE);
- glClearDepth(clear_depth);
- }
- if (stencil) {
- glStencilMask(0xFF);
- }
- glClear(((color) ? GL_COLOR_BUFFER_BIT : 0) |
- ((depth) ? GL_DEPTH_BUFFER_BIT : 0) |
- ((stencil) ? GL_STENCIL_BUFFER_BIT : 0));
-}
-
-void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data)
-{
- GLenum type;
- switch (channels) {
- case 1: type = GL_RED; break;
- case 2: type = GL_RG; break;
- case 3: type = GL_RGB; break;
- case 4: type = GL_RGBA; break;
- default:
- BLI_assert(false && "wrong number of read channels");
- return;
- }
- glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
- 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);
-}
-
-void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip)
-{
- GPU_framebuffer_texture_layer_attach(fb, tex, slot, layer, mip);
-}
-
-void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
-{
- GPU_framebuffer_texture_cubeface_attach(fb, tex, slot, face, mip);
-}
-
-void DRW_framebuffer_texture_detach(GPUTexture *tex)
-{
- GPU_framebuffer_texture_detach(tex);
-}
-
-void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth, bool stencil)
-{
- GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth, stencil);
-}
-
-void DRW_framebuffer_recursive_downsample(
- struct GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter,
- void (*callback)(void *userData, int level), void *userData)
-{
- GPU_framebuffer_recursive_downsample(fb, tex, num_iter, callback, userData);
-}
-
-void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h)
-{
- glViewport(x, y, w, h);
-}
-
/* Use color management profile to draw texture to framebuffer */
void DRW_transform_to_display(GPUTexture *tex)
{
@@ -2501,7 +265,7 @@ void DRW_transform_to_display(GPUTexture *tex)
/** \name Viewport (DRW_viewport)
* \{ */
-static void *DRW_viewport_engine_data_ensure(void *engine_type)
+void *drw_viewport_engine_data_ensure(void *engine_type)
{
void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type);
@@ -2533,7 +297,12 @@ void DRW_engine_viewport_data_size_get(
const float *DRW_viewport_size_get(void)
{
- return &DST.size[0];
+ return DST.size;
+}
+
+const float *DRW_viewport_invert_size_get(void)
+{
+ return DST.inv_size;
}
const float *DRW_viewport_screenvecs_get(void)
@@ -2553,7 +322,7 @@ static void drw_viewport_cache_resize(void)
if (DST.vmempool != NULL) {
BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_len(DST.vmempool->calls));
- BLI_mempool_clear_ex(DST.vmempool->calls_generate, BLI_mempool_len(DST.vmempool->calls_generate));
+ BLI_mempool_clear_ex(DST.vmempool->states, BLI_mempool_len(DST.vmempool->states));
BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_len(DST.vmempool->shgroups));
BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_len(DST.vmempool->uniforms));
BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_len(DST.vmempool->passes));
@@ -2600,6 +369,8 @@ static void drw_viewport_var_init(void)
GPU_viewport_size_get(DST.viewport, size);
DST.size[0] = size[0];
DST.size[1] = size[1];
+ DST.inv_size[0] = 1.0f / size[0];
+ DST.inv_size[1] = 1.0f / size[1];
DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport);
DST.default_framebuffer = fbl->default_fb;
@@ -2609,8 +380,8 @@ static void drw_viewport_var_init(void)
if (DST.vmempool->calls == NULL) {
DST.vmempool->calls = BLI_mempool_create(sizeof(DRWCall), 0, 512, 0);
}
- if (DST.vmempool->calls_generate == NULL) {
- DST.vmempool->calls_generate = BLI_mempool_create(sizeof(DRWCallGenerate), 0, 512, 0);
+ if (DST.vmempool->states == NULL) {
+ DST.vmempool->states = BLI_mempool_create(sizeof(DRWCallState), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
}
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0);
@@ -2629,6 +400,9 @@ static void drw_viewport_var_init(void)
DST.size[0] = 0;
DST.size[1] = 0;
+ DST.inv_size[0] = 0;
+ DST.inv_size[1] = 0;
+
DST.default_framebuffer = NULL;
DST.vmempool = NULL;
}
@@ -2642,6 +416,20 @@ static void drw_viewport_var_init(void)
/* Refresh DST.pixelsize */
DST.pixsize = rv3d->pixsize;
+
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERS], rv3d->persmat);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERSINV], rv3d->persinv);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEW], rv3d->viewmat);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEWINV], rv3d->viewinv);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_WIN], rv3d->winmat);
+ invert_m4_m4(DST.original_mat.mat[DRW_MAT_WININV], rv3d->winmat);
+
+ memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DST.original_mat.mat));
+
+ copy_v4_v4(DST.view_data.viewcamtexcofac, rv3d->viewcamtexcofac);
+ }
+ else {
+ copy_v4_fl4(DST.view_data.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f);
}
/* Reset facing */
@@ -2654,62 +442,77 @@ static void drw_viewport_var_init(void)
}
/* Alloc array of texture reference. */
- if (RST.bound_texs == NULL) {
- RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs");
+ if (DST.RST.bound_texs == NULL) {
+ DST.RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs");
+ }
+ if (DST.RST.bound_tex_slots == NULL) {
+ DST.RST.bound_tex_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Texture Slots");
}
- if (RST.bound_tex_slots == NULL) {
- RST.bound_tex_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Texture Slots");
+ if (DST.RST.bound_ubos == NULL) {
+ DST.RST.bound_ubos = MEM_callocN(sizeof(GPUUniformBuffer *) * GPU_max_ubo_binds(), "Bound GPUUniformBuffer refs");
}
+ if (DST.RST.bound_ubo_slots == NULL) {
+ DST.RST.bound_ubo_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Ubo Slots");
+ }
+
+ if (view_ubo == NULL) {
+ view_ubo = DRW_uniformbuffer_create(sizeof(ViewUboStorage), NULL);
+ }
+
+ DST.override_mat = 0;
+ DST.dirty_mat = true;
+ DST.state_cache_id = 1;
+
+ DST.clipping.updated = false;
- memset(viewport_matrix_override.override, 0x0, sizeof(viewport_matrix_override.override));
memset(DST.common_instance_data, 0x0, sizeof(DST.common_instance_data));
}
void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
{
- RegionView3D *rv3d = DST.draw_ctx.rv3d;
- BLI_assert(type >= DRW_MAT_PERS && type <= DRW_MAT_WININV);
+ BLI_assert(type >= 0 && type < DRW_MAT_COUNT);
+ BLI_assert(((DST.override_mat & (1 << type)) != 0)|| DST.draw_ctx.rv3d != NULL); /* Can't use this in render mode. */
- if (viewport_matrix_override.override[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);
- break;
- case DRW_MAT_PERSINV:
- copy_m4_m4(mat, rv3d->persinv);
- break;
- case DRW_MAT_VIEW:
- copy_m4_m4(mat, rv3d->viewmat);
- break;
- case DRW_MAT_VIEWINV:
- copy_m4_m4(mat, rv3d->viewinv);
- break;
- case DRW_MAT_WIN:
- copy_m4_m4(mat, rv3d->winmat);
- break;
- case DRW_MAT_WININV:
- invert_m4_m4(mat, rv3d->winmat);
- break;
- default:
- BLI_assert(!"Matrix type invalid");
- break;
- }
- }
+ copy_m4_m4(mat, DST.view_data.matstate.mat[type]);
+}
+
+void DRW_viewport_matrix_get_all(DRWMatrixState *state)
+{
+ memcpy(state, DST.view_data.matstate.mat, sizeof(DRWMatrixState));
}
void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type)
{
- copy_m4_m4(viewport_matrix_override.mat[type], mat);
- viewport_matrix_override.override[type] = true;
+ BLI_assert(type < DRW_MAT_COUNT);
+ copy_m4_m4(DST.view_data.matstate.mat[type], mat);
+ DST.override_mat |= (1 << type);
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
}
void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type)
{
- viewport_matrix_override.override[type] = false;
+ BLI_assert(type < DRW_MAT_COUNT);
+ copy_m4_m4(DST.view_data.matstate.mat[type], DST.original_mat.mat[type]);
+ DST.override_mat &= ~(1 << type);
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
+}
+
+void DRW_viewport_matrix_override_set_all(DRWMatrixState *state)
+{
+ memcpy(DST.view_data.matstate.mat, state, sizeof(DRWMatrixState));
+ DST.override_mat = 0xFFFFFF;
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
+}
+
+void DRW_viewport_matrix_override_unset_all(void)
+{
+ memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DRWMatrixState));
+ DST.override_mat = 0;
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
}
bool DRW_viewport_is_persp_get(void)
@@ -2719,9 +522,7 @@ bool DRW_viewport_is_persp_get(void)
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;
- }
+ return DST.view_data.matstate.mat[DRW_MAT_WIN][3][3] == 0.0f;
}
BLI_assert(0);
return false;
@@ -2836,24 +637,6 @@ ObjectEngineData *DRW_object_engine_data_ensure(
return oed;
}
-/* XXX There is definitly some overlap between this and DRW_object_engine_data_ensure.
- * We should get rid of one of the two. */
-LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, RenderEngineType *engine_type)
-{
- BLI_assert(ob->type == OB_LAMP);
-
- Scene *scene = DST.draw_ctx.scene;
-
- /* TODO Dupliobjects */
- /* TODO Should be per scenelayer */
- return GPU_lamp_engine_data_get(scene, ob, NULL, engine_type);
-}
-
-void DRW_lamp_engine_data_free(LampEngineData *led)
-{
- GPU_lamp_engine_data_free(led);
-}
-
/** \} */
@@ -2866,7 +649,7 @@ static void drw_engines_init(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
if (engine->engine_init) {
@@ -2881,7 +664,7 @@ static void drw_engines_cache_init(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
if (data->text_draw_cache) {
DRW_text_cache_destroy(data->text_draw_cache);
@@ -2899,9 +682,11 @@ static void drw_engines_cache_init(void)
static void drw_engines_cache_populate(Object *ob)
{
+ DST.ob_state = NULL;
+
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
if (engine->id_update) {
engine->id_update(data, &ob->id);
@@ -2917,7 +702,7 @@ static void drw_engines_cache_finish(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
if (engine->cache_finish) {
engine->cache_finish(data);
@@ -2929,7 +714,7 @@ static void drw_engines_draw_background(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
if (engine->draw_background) {
PROFILE_START(stime);
@@ -2953,7 +738,7 @@ static void drw_engines_draw_scene(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
if (engine->draw_scene) {
@@ -2970,7 +755,7 @@ static void drw_engines_draw_text(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
if (data->text_draw_cache) {
@@ -2991,7 +776,7 @@ int DRW_draw_region_engine_info_offset(void)
int lines = 0;
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
/* Count the number of lines. */
if (data->info[0] != '\0') {
@@ -3026,7 +811,7 @@ void DRW_draw_region_engine_info(void)
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
if (data->info[0] != '\0') {
char *chr_current = data->info;
@@ -3070,6 +855,14 @@ static void use_drw_engine(DrawEngineType *engine)
BLI_addtail(&DST.enabled_engines, ld);
}
+/**
+ * Use for external render engines.
+ */
+static void drw_engines_enable_external(void)
+{
+ use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
+}
+
/* TODO revisit this when proper layering is implemented */
/* Gather all draw engines needed and store them in DST.enabled_engines
* That also define the rendering order of engines */
@@ -3149,14 +942,6 @@ static void drw_engines_enable_basic(void)
use_drw_engine(DRW_engine_viewport_basic_type.draw_engine);
}
-/**
- * Use for external render engines.
- */
-static void drw_engines_enable_external(void)
-{
- use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
-}
-
static void drw_engines_enable(ViewLayer *view_layer, RenderEngineType *engine_type)
{
Object *obact = OBACT(view_layer);
@@ -3188,127 +973,6 @@ static unsigned int DRW_engines_get_hash(void)
return hash;
}
-static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size)
-{
- BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit,
- rect->ymax - (3 + v) * U.widget_unit, 0.0f,
- txt, size);
-}
-
-/* CPU stats */
-static void drw_debug_cpu_stats(void)
-{
- int u, v;
- double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
- /* local coordinate visible rect inside region, to accomodate overlapping ui */
- rcti rect;
- struct ARegion *ar = DST.draw_ctx.ar;
- ED_region_visible_rect(ar, &rect);
-
- UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
-
- /* row by row */
- v = 0; u = 0;
- /* Label row */
- char col_label[32];
- sprintf(col_label, "Engine");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- sprintf(col_label, "Init");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- sprintf(col_label, "Background");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- sprintf(col_label, "Render");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- sprintf(col_label, "Total (w/o cache)");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- v++;
-
- /* Engines rows */
- char time_to_txt[16];
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
- u = 0;
- DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
-
- draw_stat(&rect, u++, v, engine->idname, sizeof(engine->idname));
-
- init_tot_time += data->init_time;
- sprintf(time_to_txt, "%.2fms", data->init_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
-
- background_tot_time += data->background_time;
- sprintf(time_to_txt, "%.2fms", data->background_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
-
- render_tot_time += data->render_time;
- sprintf(time_to_txt, "%.2fms", data->render_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
-
- tot_time += data->init_time + data->background_time + data->render_time;
- sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
- v++;
- }
-
- /* Totals row */
- u = 0;
- sprintf(col_label, "Sub Total");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- sprintf(time_to_txt, "%.2fms", init_tot_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
- sprintf(time_to_txt, "%.2fms", background_tot_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
- sprintf(time_to_txt, "%.2fms", render_tot_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
- sprintf(time_to_txt, "%.2fms", tot_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
- v += 2;
-
- u = 0;
- sprintf(col_label, "Cache Time");
- draw_stat(&rect, u++, v, col_label, sizeof(col_label));
- sprintf(time_to_txt, "%.2fms", DST.cache_time);
- draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
-}
-
-/* Display GPU time for each passes */
-static void drw_debug_gpu_stats(void)
-{
- /* local coordinate visible rect inside region, to accomodate overlapping ui */
- rcti rect;
- struct ARegion *ar = DST.draw_ctx.ar;
- ED_region_visible_rect(ar, &rect);
-
- UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
-
- int v = BLI_listbase_count(&DST.enabled_engines) + 5;
-
- char stat_string[32];
-
- /* Memory Stats */
- unsigned int tex_mem = GPU_texture_memory_usage_get();
- unsigned int vbo_mem = GWN_vertbuf_get_memory_usage();
-
- sprintf(stat_string, "GPU Memory");
- draw_stat(&rect, 0, v, stat_string, sizeof(stat_string));
- sprintf(stat_string, "%.2fMB", (double)(tex_mem + vbo_mem) / 1000000.0);
- draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string));
- sprintf(stat_string, " |--> Textures");
- draw_stat(&rect, 0, v, stat_string, sizeof(stat_string));
- sprintf(stat_string, "%.2fMB", (double)tex_mem / 1000000.0);
- draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string));
- sprintf(stat_string, " |--> Meshes");
- draw_stat(&rect, 0, v, stat_string, sizeof(stat_string));
- sprintf(stat_string, "%.2fMB", (double)vbo_mem / 1000000.0);
- draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string));
-
- /* Pre offset for stats_draw */
- rect.ymax -= (3 + ++v) * U.widget_unit;
-
- /* Rendering Stats */
- DRW_stats_draw(&rect);
-}
-
/* -------------------------------------------------------------------- */
/** \name View Update
@@ -3328,9 +992,13 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
return;
}
+ /* XXX Really nasty locking. But else this could
+ * be executed by the material previews thread
+ * while rendering a viewport. */
+ BLI_mutex_lock(&DST.ogl_context_mutex);
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
DST.viewport = rv3d->viewport;
DST.draw_ctx = (DRWContextState){
@@ -3342,7 +1010,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *draw_engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine);
if (draw_engine->view_update) {
draw_engine->view_update(data);
@@ -3352,6 +1020,8 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
DST.viewport = NULL;
drw_engines_disable();
+
+ BLI_mutex_unlock(&DST.ogl_context_mutex);
}
/** \} */
@@ -3378,7 +1048,7 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id)
return;
}
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
DST.viewport = rv3d->viewport;
DST.draw_ctx = (DRWContextState){
ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, OB_MODE_OBJECT, NULL,
@@ -3386,7 +1056,7 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id)
drw_engines_enable(view_layer, engine_type);
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *draw_engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine);
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine);
if (draw_engine->id_update) {
draw_engine->id_update(data, id);
}
@@ -3414,7 +1084,7 @@ void DRW_draw_view(const bContext *C)
View3D *v3d = CTX_wm_view3d(C);
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
DRW_draw_render_loop_ex(eval_ctx.depsgraph, engine_type, ar, v3d, eval_ctx.object_mode, C);
}
@@ -3428,6 +1098,7 @@ void DRW_draw_render_loop_ex(
ARegion *ar, View3D *v3d, const eObjectMode object_mode,
const bContext *evil_C)
{
+
Scene *scene = DEG_get_evaluated_scene(depsgraph);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = ar->regiondata;
@@ -3463,16 +1134,20 @@ void DRW_draw_render_loop_ex(
PROFILE_START(stime);
drw_engines_cache_init();
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get())
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get())
{
drw_engines_cache_populate(ob);
}
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
drw_engines_cache_finish();
DRW_render_instance_buffer_finish();
- PROFILE_END_ACCUM(DST.cache_time, stime);
+
+#ifdef USE_PROFILE
+ double *cache_time = GPU_viewport_cache_time_get(DST.viewport);
+ PROFILE_END_UPDATE(*cache_time, stime);
+#endif
}
DRW_stats_begin();
@@ -3535,8 +1210,11 @@ void DRW_draw_render_loop_ex(
}
if (G.debug_value > 20) {
- drw_debug_cpu_stats();
- drw_debug_gpu_stats();
+ glDisable(GL_DEPTH_TEST);
+ rcti rect; /* local coordinate visible rect inside region, to accomodate overlapping ui */
+ ED_region_visible_rect(DST.draw_ctx.ar, &rect);
+ DRW_stats_draw(&rect);
+ glEnable(GL_DEPTH_TEST);
}
DRW_state_reset();
@@ -3546,7 +1224,7 @@ void DRW_draw_render_loop_ex(
#ifdef DEBUG
/* Avoid accidental reuse. */
- memset(&DST, 0xFF, sizeof(DST));
+ memset(&DST, 0xFF, offsetof(DRWManager, ogl_context));
#endif
}
@@ -3555,7 +1233,7 @@ void DRW_draw_render_loop(
ARegion *ar, View3D *v3d, const eObjectMode object_mode)
{
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
@@ -3585,7 +1263,7 @@ void DRW_draw_render_loop_offscreen(
}
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
DST.options.is_image_render = true;
DST.options.draw_background = draw_background;
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, object_mode, NULL);
@@ -3596,7 +1274,6 @@ void DRW_draw_render_loop_offscreen(
/* 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;
@@ -3609,20 +1286,25 @@ void DRW_draw_render_loop_offscreen(
void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RenderEngineType *engine_type = engine->type;
DrawEngineType *draw_engine_type = engine_type->draw_engine;
RenderData *r = &scene->r;
Render *render = engine->re;
- const EvaluationContext *eval_ctx = RE_GetEvalCtx(render);
+ /* Changing Context */
+ DRW_opengl_context_enable();
+ /* IMPORTANT: We dont support immediate mode in render mode!
+ * This shall remain in effect until immediate mode supports
+ * multiple threads. */
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
DST.options.is_image_render = true;
DST.options.is_scene_render = true;
DST.options.draw_background = scene->r.alphamode == R_ADDSKY;
DST.draw_ctx = (DRWContextState){
- NULL, NULL, NULL, scene, NULL, NULL, engine_type, depsgraph, eval_ctx->object_mode, NULL,
+ NULL, NULL, NULL, scene, view_layer, NULL, engine_type, depsgraph, OB_MODE_OBJECT, NULL,
};
drw_context_state_init();
@@ -3632,48 +1314,49 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
drw_viewport_var_init();
- ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine_type);
+ 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]);
- /* Main rendering loop. */
+ /* Main rendering. */
+ rctf view_rect;
+ rcti render_rect;
+ RE_GetViewPlane(render, &view_rect, &render_rect);
+ if (BLI_rcti_is_empty(&render_rect)) {
+ BLI_rcti_init(&render_rect, 0, size[0], 0, size[1]);
+ }
/* Init render result. */
- const float *render_size = DRW_viewport_size_get();
- RenderResult *render_result = RE_engine_begin_result(engine, 0, 0, (int)render_size[0], (int)render_size[1], NULL, NULL);
-
+ RenderResult *render_result = RE_engine_begin_result(
+ engine,
+ 0,
+ 0,
+ (int)size[0],
+ (int)size[1],
+ view_layer->name,
+ /* RR_ALL_VIEWS */ NULL);
+
+ RenderLayer *render_layer = render_result->layers.first;
for (RenderView *render_view = render_result->views.first;
render_view != NULL;
render_view = render_view->next)
{
RE_SetActiveRenderView(render, render_view->name);
- for (RenderLayer *render_layer = render_result->layers.first;
- render_layer != NULL;
- render_layer = render_layer->next)
- {
- ViewLayer *view_layer = BLI_findstring(&scene->view_layers, render_layer->name, offsetof(ViewLayer, name));
- DST.draw_ctx.view_layer = view_layer;
-
- /* TODO(dfelinto/sergey) we should not get depsgraph from scene.
- * For rendering depsgraph is to be owned by Render. */
- DST.draw_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
-
- engine_type->draw_engine->render_to_image(data, engine, render_result, render_layer);
- DST.buffer_finish_called = false;
- /* Force cache to reset. */
- drw_viewport_cache_resize();
- }
+ engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
}
RE_engine_end_result(engine, render_result, false, false, false);
+ /* Force cache to reset. */
+ drw_viewport_cache_resize();
+
/* 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
@@ -3686,9 +1369,12 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
glEnable(GL_SCISSOR_TEST);
GPU_framebuffer_restore();
+ /* Changing Context */
+ DRW_opengl_context_disable();
+
#ifdef DEBUG
/* Avoid accidental reuse. */
- memset(&DST, 0xFF, sizeof(DST));
+ memset(&DST, 0xFF, offsetof(DRWManager, ogl_context));
#endif
}
@@ -3696,13 +1382,45 @@ 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())
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get())
{
+ DST.ob_state = NULL;
callback(vedata, ob, engine, depsgraph);
}
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
}
+static struct DRWSelectBuffer {
+ struct GPUFrameBuffer *framebuffer;
+ struct GPUTexture *texture_depth;
+} g_select_buffer = {NULL};
+
+static void draw_select_framebuffer_setup(const rcti *rect)
+{
+ if (g_select_buffer.framebuffer == NULL) {
+ g_select_buffer.framebuffer = GPU_framebuffer_create();
+ }
+
+ /* If size mismatch recreate the texture. */
+ if ((g_select_buffer.texture_depth != NULL) &&
+ ((GPU_texture_width(g_select_buffer.texture_depth) != BLI_rcti_size_x(rect)) ||
+ (GPU_texture_height(g_select_buffer.texture_depth) != BLI_rcti_size_y(rect))))
+ {
+ GPU_texture_free(g_select_buffer.texture_depth);
+ g_select_buffer.texture_depth = NULL;
+ }
+
+ if (g_select_buffer.texture_depth == NULL) {
+ g_select_buffer.texture_depth = GPU_texture_create_depth(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), NULL);
+
+ GPU_framebuffer_texture_attach(g_select_buffer.framebuffer, g_select_buffer.texture_depth, 0, 0);
+
+ if (!GPU_framebuffer_check_valid(g_select_buffer.framebuffer, NULL)) {
+ printf("Error invalid selection framebuffer\n");
+ }
+ }
+}
+
/* Must run after all instance datas have been added. */
void DRW_render_instance_buffer_finish(void)
{
@@ -3717,7 +1435,8 @@ void DRW_render_instance_buffer_finish(void)
void DRW_draw_select_loop(
struct Depsgraph *depsgraph,
ARegion *ar, View3D *v3d, const eObjectMode object_mode,
- bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect)
+ bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect,
+ DRW_SelectPassFn select_pass_fn, void *select_pass_user_data)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
@@ -3729,7 +1448,7 @@ void DRW_draw_select_loop(
RegionView3D *rv3d = ar->regiondata;
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
/* backup (_never_ use rv3d->viewport) */
void *backup_viewport = rv3d->viewport;
@@ -3748,13 +1467,20 @@ void DRW_draw_select_loop(
}
}
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
struct GPUViewport *viewport = GPU_viewport_create();
GPU_viewport_size_set(viewport, (const int[2]){BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)});
- bool cache_is_dirty;
DST.viewport = viewport;
v3d->zbuf = true;
+ /* Setup framebuffer */
+ draw_select_framebuffer_setup(rect);
+ GPU_framebuffer_bind(g_select_buffer.framebuffer);
+ DRW_framebuffer_clear(false, true, false, NULL, 1.0f);
+
DST.options.is_select = true;
/* Get list of enabled engines */
@@ -3767,7 +1493,6 @@ void DRW_draw_select_loop(
}
/* Setup viewport */
- cache_is_dirty = true;
/* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
DST.draw_ctx = (DRWContextState){
@@ -3783,27 +1508,25 @@ void DRW_draw_select_loop(
/* Init engines */
drw_engines_init();
- /* 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();
if (use_obedit) {
drw_engines_cache_populate(obact);
}
else {
- 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)
+ DEG_OBJECT_ITER_BEGIN(
+ 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);
drw_engines_cache_populate(ob);
}
}
- DEG_OBJECT_ITER_END
+ DEG_OBJECT_ITER_END;
}
drw_engines_cache_finish();
@@ -3814,7 +1537,31 @@ void DRW_draw_select_loop(
/* Start Drawing */
DRW_state_reset();
DRW_draw_callbacks_pre_scene();
- drw_engines_draw_scene();
+
+
+ DRW_state_lock(
+ DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_ALWAYS |
+ DRW_STATE_DEPTH_LESS |
+ DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_DEPTH_GREATER |
+ DRW_STATE_DEPTH_ALWAYS);
+
+ /* Only 1-2 passes. */
+ while (true) {
+ if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) {
+ break;
+ }
+
+ drw_engines_draw_scene();
+
+ if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) {
+ break;
+ }
+ }
+
+ DRW_state_lock(0);
+
DRW_draw_callbacks_post_scene();
DRW_state_reset();
@@ -3822,18 +1569,58 @@ void DRW_draw_select_loop(
#ifdef DEBUG
/* Avoid accidental reuse. */
- memset(&DST, 0xFF, sizeof(DST));
+ memset(&DST, 0xFF, offsetof(DRWManager, ogl_context));
#endif
+ GPU_framebuffer_restore();
/* Cleanup for selection state */
GPU_viewport_free(viewport);
- MEM_freeN(viewport);
+
+ /* Restore Drawing area. */
+ gpuPopAttrib();
+ glEnable(GL_SCISSOR_TEST);
/* restore */
rv3d->viewport = backup_viewport;
#endif /* USE_GPU_SELECT */
}
+static void draw_depth_texture_to_screen(GPUTexture *texture)
+{
+ const float w = (float)GPU_texture_width(texture);
+ const float h = (float)GPU_texture_height(texture);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH_COPY);
+
+ GPU_texture_bind(texture, 0);
+
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
+
+ immBegin(GWN_PRIM_TRI_STRIP, 4);
+
+ immAttrib2f(texcoord, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttrib2f(texcoord, 1.0f, 0.0f);
+ immVertex2f(pos, w, 0.0f);
+
+ immAttrib2f(texcoord, 0.0f, 1.0f);
+ immVertex2f(pos, 0.0f, h);
+
+ immAttrib2f(texcoord, 1.0f, 1.0f);
+ immVertex2f(pos, w, h);
+
+ immEnd();
+
+ GPU_texture_unbind(texture);
+
+ immUnbindProgram();
+}
+
/**
* object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
*/
@@ -3846,16 +1633,26 @@ void DRW_draw_depth_loop(
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = ar->regiondata;
+ DRW_opengl_context_enable();
+
/* backup (_never_ use rv3d->viewport) */
void *backup_viewport = rv3d->viewport;
rv3d->viewport = NULL;
/* Reset before using it. */
- memset(&DST, 0x0, sizeof(DST));
+ memset(&DST, 0x0, offsetof(DRWManager, ogl_context));
+
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
struct GPUViewport *viewport = GPU_viewport_create();
GPU_viewport_size_set(viewport, (const int[2]){ar->winx, ar->winy});
+ /* Setup framebuffer */
+ draw_select_framebuffer_setup(&ar->winrct);
+ GPU_framebuffer_bind(g_select_buffer.framebuffer);
+ DRW_framebuffer_clear(false, true, false, NULL, 1.0f);
+
bool cache_is_dirty;
DST.viewport = viewport;
v3d->zbuf = true;
@@ -3891,11 +1688,11 @@ void DRW_draw_depth_loop(
if (cache_is_dirty) {
drw_engines_cache_init();
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get())
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get())
{
drw_engines_cache_populate(ob);
}
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
drw_engines_cache_finish();
@@ -3913,12 +1710,36 @@ void DRW_draw_depth_loop(
#ifdef DEBUG
/* Avoid accidental reuse. */
- memset(&DST, 0xFF, sizeof(DST));
+ memset(&DST, 0xFF, offsetof(DRWManager, ogl_context));
#endif
+ /* TODO: Reading depth for operators should be done here. */
+
+ GPU_framebuffer_restore();
+
/* Cleanup for selection state */
GPU_viewport_free(viewport);
- MEM_freeN(viewport);
+
+ /* Restore Drawing area. */
+ gpuPopAttrib();
+ glEnable(GL_SCISSOR_TEST);
+
+ /* Changin context */
+ DRW_opengl_context_disable();
+
+ /* XXX Drawing the resulting buffer to the BACK_BUFFER */
+ gpuPushMatrix();
+ gpuPushProjectionMatrix();
+ wmOrtho2_region_pixelspace(ar);
+ gpuLoadIdentity();
+
+ glEnable(GL_DEPTH_TEST); /* Cannot write to depth buffer without testing */
+ glDepthFunc(GL_ALWAYS);
+ draw_depth_texture_to_screen(g_select_buffer.texture_depth);
+ glDepthFunc(GL_LEQUAL);
+
+ gpuPopMatrix();
+ gpuPopProjectionMatrix();
/* restore */
rv3d->viewport = backup_viewport;
@@ -4116,10 +1937,16 @@ void DRW_engines_register(void)
}
}
+extern struct Gwn_VertFormat *g_pos_format; /* draw_shgroup.c */
extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
extern struct GPUTexture *globals_ramp; /* draw_common.c */
void DRW_engines_free(void)
{
+ DRW_opengl_context_enable();
+
+ DRW_TEXTURE_FREE_SAFE(g_select_buffer.texture_depth);
+ DRW_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer);
+
DRW_shape_cache_free();
DRW_stats_free();
DRW_globals_free();
@@ -4134,16 +1961,17 @@ void DRW_engines_free(void)
}
}
- if (globals_ubo)
- GPU_uniformbuffer_free(globals_ubo);
-
- if (globals_ramp)
- GPU_texture_free(globals_ramp);
-
+ DRW_UBO_FREE_SAFE(globals_ubo);
+ DRW_UBO_FREE_SAFE(view_ubo);
+ DRW_TEXTURE_FREE_SAFE(globals_ramp);
MEM_SAFE_FREE(g_pos_format);
- MEM_SAFE_FREE(RST.bound_texs);
- MEM_SAFE_FREE(RST.bound_tex_slots);
+ MEM_SAFE_FREE(DST.RST.bound_texs);
+ MEM_SAFE_FREE(DST.RST.bound_tex_slots);
+ MEM_SAFE_FREE(DST.RST.bound_ubos);
+ MEM_SAFE_FREE(DST.RST.bound_ubo_slots);
+
+ DRW_opengl_context_disable();
#ifdef WITH_CLAY_ENGINE
BLI_remlink(&R_engines, &DRW_engine_viewport_clay_type);
@@ -4151,3 +1979,77 @@ void DRW_engines_free(void)
}
/** \} */
+
+/** \name Init/Exit (DRW_opengl_ctx)
+ * \{ */
+
+void DRW_opengl_context_create(void)
+{
+ BLI_assert(DST.ogl_context == NULL); /* Ensure it's called once */
+
+ BLI_mutex_init(&DST.ogl_context_mutex);
+
+ immDeactivate();
+ /* This changes the active context. */
+ DST.ogl_context = WM_opengl_context_create();
+ /* Be sure to create gawain.context too. */
+ DST.gwn_context = GWN_context_create();
+ immActivate();
+ /* Set default Blender OpenGL state */
+ GPU_state_init();
+ /* So we activate the window's one afterwards. */
+ wm_window_reset_drawable();
+}
+
+void DRW_opengl_context_destroy(void)
+{
+ BLI_assert(BLI_thread_is_main());
+ if (DST.ogl_context != NULL) {
+ WM_opengl_context_activate(DST.ogl_context);
+ GWN_context_active_set(DST.gwn_context);
+ GWN_context_discard(DST.gwn_context);
+ WM_opengl_context_dispose(DST.ogl_context);
+ BLI_mutex_end(&DST.ogl_context_mutex);
+ }
+}
+
+void DRW_opengl_context_enable(void)
+{
+ if (DST.ogl_context != NULL) {
+ /* IMPORTANT: We dont support immediate mode in render mode!
+ * This shall remain in effect until immediate mode supports
+ * multiple threads. */
+ BLI_mutex_lock(&DST.ogl_context_mutex);
+ if (BLI_thread_is_main()) {
+ immDeactivate();
+ }
+ WM_opengl_context_activate(DST.ogl_context);
+ GWN_context_active_set(DST.gwn_context);
+ if (BLI_thread_is_main()) {
+ immActivate();
+ }
+ }
+}
+
+void DRW_opengl_context_disable(void)
+{
+ if (DST.ogl_context != NULL) {
+#ifdef __APPLE__
+ /* Need to flush before disabling draw context, otherwise it does not
+ * always finish drawing and viewport can be empty or partially drawn */
+ glFlush();
+#endif
+
+ if (BLI_thread_is_main()) {
+ wm_window_reset_drawable();
+ }
+ else {
+ WM_opengl_context_release(DST.ogl_context);
+ GWN_context_active_set(NULL);
+ }
+
+ BLI_mutex_unlock(&DST.ogl_context_mutex);
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
new file mode 100644
index 00000000000..c7e9b3dc08d
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager.h
@@ -0,0 +1,358 @@
+/*
+ * 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_manager.h
+ * \ingroup draw
+ */
+
+/* Private functions / structs of the draw manager */
+
+#ifndef __DRAW_MANAGER_H__
+#define __DRAW_MANAGER_H__
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BLI_linklist.h"
+#include "BLI_threads.h"
+
+#include "GPU_batch.h"
+#include "GPU_framebuffer.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "draw_instance_data.h"
+
+/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
+#define USE_GPU_SELECT
+
+/* ------------ Profiling --------------- */
+
+#define USE_PROFILE
+
+#ifdef USE_PROFILE
+# include "PIL_time.h"
+
+# define PROFILE_TIMER_FALLOFF 0.04
+
+# define PROFILE_START(time_start) \
+ double time_start = PIL_check_seconds_timer();
+
+# define PROFILE_END_ACCUM(time_accum, time_start) { \
+ time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \
+} ((void)0)
+
+/* exp average */
+# define PROFILE_END_UPDATE(time_update, time_start) { \
+ double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \
+ time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \
+ (_time_delta * PROFILE_TIMER_FALLOFF); \
+} ((void)0)
+
+#else /* USE_PROFILE */
+
+# define PROFILE_START(time_start) ((void)0)
+# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0)
+# define PROFILE_END_UPDATE(time_update, time_start) ((void)0)
+
+#endif /* USE_PROFILE */
+
+/* ------------ Data Structure --------------- */
+/**
+ * Data structure containing all drawcalls organized by passes and materials.
+ * DRWPass > DRWShadingGroup > DRWCall > DRWCallState
+ * > DRWUniform
+ **/
+
+/* Used by DRWCallState.flag */
+enum {
+ DRW_CALL_CULLED = (1 << 0),
+ DRW_CALL_NEGSCALE = (1 << 1),
+};
+
+/* Used by DRWCallState.matflag */
+enum {
+ DRW_CALL_MODELINVERSE = (1 << 0),
+ DRW_CALL_MODELVIEW = (1 << 1),
+ DRW_CALL_MODELVIEWINVERSE = (1 << 2),
+ DRW_CALL_MODELVIEWPROJECTION = (1 << 3),
+ DRW_CALL_NORMALVIEW = (1 << 4),
+ DRW_CALL_NORMALWORLD = (1 << 5),
+ DRW_CALL_ORCOTEXFAC = (1 << 6),
+ DRW_CALL_EYEVEC = (1 << 7),
+};
+
+typedef struct DRWCallState {
+ unsigned char flag;
+ unsigned char cache_id; /* Compared with DST.state_cache_id to see if matrices are still valid. */
+ uint16_t matflag; /* Which matrices to compute. */
+ /* Culling: Using Bounding Sphere for now for faster culling.
+ * Not ideal for planes. */
+ BoundSphere bsphere;
+ /* Matrices */
+ float model[4][4];
+ float modelinverse[4][4];
+ float modelview[4][4];
+ float modelviewinverse[4][4];
+ float modelviewprojection[4][4];
+ float normalview[3][3];
+ float normalworld[3][3]; /* Not view dependant */
+ float orcotexfac[2][3]; /* Not view dependant */
+ float eyevec[3];
+} DRWCallState;
+
+typedef enum {
+ DRW_CALL_SINGLE, /* A single batch */
+ DRW_CALL_INSTANCES, /* Draw instances without any instancing attribs. */
+ DRW_CALL_GENERATE, /* Uses a callback to draw with any number of batches. */
+} DRWCallType;
+
+typedef struct DRWCall {
+ struct DRWCall *next;
+ DRWCallState *state;
+
+ union {
+ struct { /* type == DRW_CALL_SINGLE */
+ Gwn_Batch *geometry;
+ } single;
+ struct { /* type == DRW_CALL_INSTANCES */
+ Gwn_Batch *geometry;
+ /* Count can be adjusted between redraw. If needed, we can add fixed count. */
+ unsigned int *count;
+ } instances;
+ struct { /* type == DRW_CALL_GENERATE */
+ DRWCallGenerateFn *geometry_fn;
+ void *user_data;
+ } generate;
+ };
+
+ DRWCallType type;
+#ifdef USE_GPU_SELECT
+ int select_id;
+#endif
+} DRWCall;
+
+/* Used by DRWUniform.type */
+typedef enum {
+ DRW_UNIFORM_BOOL,
+ DRW_UNIFORM_SHORT_TO_INT,
+ DRW_UNIFORM_SHORT_TO_FLOAT,
+ DRW_UNIFORM_INT,
+ DRW_UNIFORM_FLOAT,
+ DRW_UNIFORM_TEXTURE,
+ DRW_UNIFORM_TEXTURE_PERSIST,
+ DRW_UNIFORM_BUFFER,
+ DRW_UNIFORM_BLOCK,
+ DRW_UNIFORM_BLOCK_PERSIST
+} DRWUniformType;
+
+struct DRWUniform {
+ DRWUniform *next; /* single-linked list */
+ const void *value;
+ int location;
+ char type; /* DRWUniformType */
+ char length; /* cannot be more than 16 */
+ char arraysize; /* cannot be more than 16 too */
+};
+
+typedef enum {
+ DRW_SHG_NORMAL,
+ DRW_SHG_POINT_BATCH,
+ DRW_SHG_LINE_BATCH,
+ DRW_SHG_TRIANGLE_BATCH,
+ DRW_SHG_INSTANCE,
+ DRW_SHG_INSTANCE_EXTERNAL,
+} DRWShadingGroupType;
+
+struct DRWShadingGroup {
+ DRWShadingGroup *next;
+
+ GPUShader *shader; /* Shader to bind */
+ DRWUniform *uniforms; /* Uniforms pointers */
+
+ /* Watch this! Can be nasty for debugging. */
+ union {
+ struct { /* DRW_SHG_NORMAL */
+ DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */
+ } calls;
+ struct { /* DRW_SHG_***_BATCH */
+ struct Gwn_Batch *batch_geom; /* Result of call batching */
+ struct Gwn_VertBuf *batch_vbo;
+ unsigned int primitive_count;
+ };
+ struct { /* DRW_SHG_INSTANCE[_EXTERNAL] */
+ struct Gwn_Batch *instance_geom;
+ struct Gwn_VertBuf *instance_vbo;
+ unsigned int instance_count;
+ float instance_orcofac[2][3]; /* TODO find a better place. */
+ };
+ };
+
+ DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */
+ DRWState state_extra_disable; /* State changes for this batch only (and'd with the pass's state) */
+ unsigned int stencil_mask; /* Stencil mask to use for stencil test / write operations */
+ DRWShadingGroupType type;
+
+ /* Builtin matrices locations */
+ int model;
+ int modelinverse;
+ int modelview;
+ int modelviewinverse;
+ int modelviewprojection;
+ int normalview;
+ int normalworld;
+ int orcotexfac;
+ int eye;
+ uint16_t matflag; /* Matrices needed, same as DRWCall.flag */
+
+#ifndef NDEBUG
+ char attribs_count;
+#endif
+
+#ifdef USE_GPU_SELECT
+ DRWInstanceData *inst_selectid;
+ DRWPass *pass_parent; /* backlink to pass we're in */
+ int override_selectid; /* Override for single object instances. */
+#endif
+};
+
+#define MAX_PASS_NAME 32
+
+struct DRWPass {
+ /* Linked list */
+ struct {
+ DRWShadingGroup *first;
+ DRWShadingGroup *last;
+ } shgroups;
+
+ DRWState state;
+ char name[MAX_PASS_NAME];
+};
+
+typedef struct ViewUboStorage {
+ DRWMatrixState matstate;
+ float viewcamtexcofac[4];
+ float clipplanes[2][4];
+} ViewUboStorage;
+
+/* ------------- DRAW MANAGER ------------ */
+
+#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
+
+typedef struct DRWManager {
+ /* TODO clean up this struct a bit */
+ /* Cache generation */
+ ViewportMemoryPool *vmempool;
+ DRWInstanceDataList *idatalist;
+ DRWInstanceData *common_instance_data[MAX_INSTANCE_DATA_SIZE];
+ /* State of the object being evaluated if already allocated. */
+ DRWCallState *ob_state;
+ unsigned char state_cache_id; /* Could be larger but 254 view changes is already a lot! */
+
+ /* Rendering state */
+ GPUShader *shader;
+
+ /* Managed by `DRW_state_set`, `DRW_state_reset` */
+ DRWState state;
+ DRWState state_lock;
+ unsigned int stencil_mask;
+
+ /* Per viewport */
+ GPUViewport *viewport;
+ struct GPUFrameBuffer *default_framebuffer;
+ float size[2];
+ float inv_size[2];
+ float screenvecs[2][3];
+ float pixsize;
+
+ GLenum backface, frontface;
+
+ struct {
+ unsigned int is_select : 1;
+ 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 */
+ DRWContextState draw_ctx;
+
+ /* Convenience pointer to text_store owned by the viewport */
+ struct DRWTextStore **text_store_p;
+
+ ListBase enabled_engines; /* RenderEngineType */
+
+ bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */
+
+ /* View dependant uniforms. */
+ DRWMatrixState original_mat; /* Original rv3d matrices. */
+ int override_mat; /* Bitflag of which matrices are overriden. */
+ int num_clip_planes; /* Number of active clipplanes. */
+ bool dirty_mat;
+
+ /* keep in sync with viewBlock */
+ ViewUboStorage view_data;
+
+ struct {
+ float frustum_planes[6][4];
+ BoundSphere frustum_bsphere;
+ bool updated;
+ } clipping;
+
+#ifdef USE_GPU_SELECT
+ unsigned int select_id;
+#endif
+
+ /* ---------- Nothing after this point is cleared after use ----------- */
+
+ /* ogl_context serves as the offset for clearing only
+ * the top portion of the struct so DO NOT MOVE IT! */
+ void *ogl_context; /* Unique ghost context used by the draw manager. */
+ Gwn_Context *gwn_context;
+ ThreadMutex ogl_context_mutex; /* Mutex to lock the drw manager and avoid concurent context usage. */
+
+ /** GPU Resource State: Memory storage between drawing. */
+ struct {
+ GPUTexture **bound_texs;
+ char *bound_tex_slots;
+ int bind_tex_inc;
+ GPUUniformBuffer **bound_ubos;
+ char *bound_ubo_slots;
+ int bind_ubo_inc;
+ } RST;
+} DRWManager;
+
+extern DRWManager DST; /* TODO : get rid of this and allow multithreaded rendering */
+
+/* --------------- FUNCTIONS ------------- */
+
+void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags);
+void drw_texture_get_format(
+ DRWTextureFormat format, bool is_framebuffer,
+ GPUTextureFormat *r_data_type, int *r_channels, bool *r_is_depth);
+
+void *drw_viewport_engine_data_ensure(void *engine_type);
+
+void drw_state_set(DRWState state);
+
+#endif /* __DRAW_MANAGER_H__ */
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
new file mode 100644
index 00000000000..b1db3b63777
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -0,0 +1,934 @@
+/*
+ * 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_manager_data.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+
+#include "BLI_link_utils.h"
+#include "BLI_mempool.h"
+
+#include "intern/gpu_codegen.h"
+
+struct Gwn_VertFormat *g_pos_format = NULL;
+
+extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Uniform Buffer Object (DRW_uniformbuffer)
+ * \{ */
+
+GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
+{
+ return GPU_uniformbuffer_create(size, data, NULL);
+}
+
+void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
+{
+ GPU_uniformbuffer_update(ubo, data);
+}
+
+void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
+{
+ GPU_uniformbuffer_free(ubo);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Uniforms (DRW_shgroup_uniform)
+ * \{ */
+
+static void drw_interface_uniform_create_ex(DRWShadingGroup *shgroup, int loc,
+ DRWUniformType type, const void *value, int length, int arraysize)
+{
+ DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms);
+ uni->location = loc;
+ uni->type = type;
+ uni->value = value;
+ uni->length = length;
+ uni->arraysize = arraysize;
+
+ BLI_LINKS_PREPEND(shgroup->uniforms, uni);
+}
+
+static void drw_interface_builtin_uniform(
+ DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize)
+{
+ int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin);
+
+ if (loc != -1) {
+ drw_interface_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize);
+ }
+}
+
+static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name,
+ DRWUniformType type, const void *value, int length, int arraysize)
+{
+ int location;
+ if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) {
+ location = GPU_shader_get_uniform_block(shgroup->shader, name);
+ }
+ else {
+ location = GPU_shader_get_uniform(shgroup->shader, name);
+ }
+
+ if (location == -1) {
+ if (G.debug & G_DEBUG)
+ fprintf(stderr, "Uniform '%s' not found!\n", name);
+ /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
+ // BLI_assert(0);
+ return;
+ }
+
+ BLI_assert(arraysize > 0 && arraysize <= 16);
+ BLI_assert(length >= 0 && length <= 16);
+
+ drw_interface_uniform_create_ex(shgroup, location, type, value, length, arraysize);
+}
+
+void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
+{
+ BLI_assert(tex != NULL);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
+}
+
+/* Same as DRW_shgroup_uniform_texture but is garanteed to be bound if shader does not change between shgrp. */
+void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
+{
+ BLI_assert(tex != NULL);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1);
+}
+
+void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
+{
+ BLI_assert(ubo != NULL);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
+}
+
+/* Same as DRW_shgroup_uniform_block but is garanteed to be bound if shader does not change between shgrp. */
+void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
+{
+ BLI_assert(ubo != NULL);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1);
+}
+
+void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1);
+}
+
+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);
+}
+
+void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize);
+}
+
+void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize);
+}
+
+void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize);
+}
+
+void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize);
+}
+
+void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize);
+}
+
+void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 9, 1);
+}
+
+void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 16, 1);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Call (DRW_calls)
+ * \{ */
+
+static void drw_call_calc_orco(ID *ob_data, float (*r_orcofacs)[3])
+{
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+ if (ob_data != NULL) {
+ switch (GS(ob_data->name)) {
+ 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:
+ break;
+ }
+ }
+
+ if ((texcoloc != NULL) && (texcosize != NULL)) {
+ mul_v3_v3fl(r_orcofacs[1], texcosize, 2.0f);
+ invert_v3(r_orcofacs[1]);
+ sub_v3_v3v3(r_orcofacs[0], texcoloc, texcosize);
+ negate_v3(r_orcofacs[0]);
+ mul_v3_v3(r_orcofacs[0], r_orcofacs[1]); /* result in a nice MADD in the shader */
+ }
+ else {
+ copy_v3_fl(r_orcofacs[0], 0.0f);
+ copy_v3_fl(r_orcofacs[1], 1.0f);
+ }
+}
+
+static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+{
+ DRWCallState *state = BLI_mempool_alloc(DST.vmempool->states);
+ state->flag = 0;
+ state->cache_id = 0;
+ state->matflag = shgroup->matflag;
+
+ /* Matrices */
+ if (obmat != NULL) {
+ copy_m4_m4(state->model, obmat);
+
+ if (is_negative_m4(state->model)) {
+ state->flag |= DRW_CALL_NEGSCALE;
+ }
+ }
+ else {
+ unit_m4(state->model);
+ }
+
+ if (ob != NULL) {
+ float corner[3];
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ /* Get BoundSphere center and radius from the BoundBox. */
+ mid_v3_v3v3(state->bsphere.center, bbox->vec[0], bbox->vec[6]);
+ mul_v3_m4v3(corner, obmat, bbox->vec[0]);
+ mul_m4_v3(obmat, state->bsphere.center);
+ state->bsphere.radius = len_v3v3(state->bsphere.center, corner);
+ }
+ else {
+ /* Bypass test. */
+ state->bsphere.radius = -1.0f;
+ }
+
+ /* Orco factors: We compute this at creation to not have to save the *ob_data */
+ if ((state->matflag & DRW_CALL_ORCOTEXFAC) != 0) {
+ drw_call_calc_orco(ob->data, state->orcotexfac);
+ state->matflag &= ~DRW_CALL_ORCOTEXFAC;
+ }
+
+ return state;
+}
+
+static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+{
+ if (DST.ob_state == NULL) {
+ DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
+ }
+ else {
+ /* If the DRWCallState is reused, add necessary matrices. */
+ DST.ob_state->matflag |= shgroup->matflag;
+ }
+
+ return DST.ob_state;
+}
+
+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);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_SINGLE;
+ call->single.geometry = geom;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+/* These calls can be culled and are optimized for redraw */
+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);
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ call->type = DRW_CALL_SINGLE;
+ call->single.geometry = geom;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4], unsigned int *count)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_INSTANCES;
+ call->instances.geometry = geom;
+ call->instances.count = count;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+/* These calls can be culled and are optimized for redraw */
+void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob, unsigned int *count)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ call->type = DRW_CALL_INSTANCES;
+ call->instances.geometry = geom;
+ call->instances.count = count;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_generate_add(
+ DRWShadingGroup *shgroup,
+ DRWCallGenerateFn *geometry_fn, void *user_data,
+ float (*obmat)[4])
+{
+ BLI_assert(geometry_fn != NULL);
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_GENERATE;
+ call->generate.geometry_fn = geometry_fn;
+ call->generate.user_data = user_data;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+static void sculpt_draw_cb(
+ DRWShadingGroup *shgroup,
+ void (*draw_fn)(DRWShadingGroup *shgroup, Gwn_Batch *geom),
+ void *user_data)
+{
+ Object *ob = user_data;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ if (pbvh) {
+ BKE_pbvh_draw_cb(
+ pbvh, NULL, NULL, false,
+ (void (*)(void *, Gwn_Batch *))draw_fn, shgroup);
+ }
+}
+
+void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4])
+{
+ DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat);
+}
+
+void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len)
+{
+#ifdef USE_GPU_SELECT
+ if (G.f & G_PICKSEL) {
+ if (shgroup->inst_selectid == NULL) {
+ shgroup->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128);
+ }
+
+ int *select_id = DRW_instance_data_next(shgroup->inst_selectid);
+ *select_id = DST.select_id;
+ }
+#endif
+
+ BLI_assert(attr_len == shgroup->attribs_count);
+ UNUSED_VARS_NDEBUG(attr_len);
+
+ for (int i = 0; i < attr_len; ++i) {
+ if (shgroup->instance_count == shgroup->instance_vbo->vertex_ct) {
+ GWN_vertbuf_data_resize(shgroup->instance_vbo, shgroup->instance_count + 32);
+ }
+ GWN_vertbuf_attr_set(shgroup->instance_vbo, i, shgroup->instance_count, attr[i]);
+ }
+
+ shgroup->instance_count += 1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shading Groups (DRW_shgroup)
+ * \{ */
+
+static void drw_interface_init(DRWShadingGroup *shgroup, GPUShader *shader)
+{
+ shgroup->instance_geom = NULL;
+ shgroup->instance_vbo = NULL;
+ shgroup->instance_count = 0;
+ shgroup->uniforms = NULL;
+#ifdef USE_GPU_SELECT
+ shgroup->inst_selectid = NULL;
+ shgroup->override_selectid = -1;
+#endif
+#ifndef NDEBUG
+ shgroup->attribs_count = 0;
+#endif
+
+ int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
+
+ if (view_ubo_location != -1) {
+ drw_interface_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, view_ubo, 0, 1);
+ }
+ else {
+ /* Only here to support builtin shaders. This should not be used by engines. */
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEW, DST.view_data.matstate.mat[DRW_MAT_VIEW], 16, 1);
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEW_INV, DST.view_data.matstate.mat[DRW_MAT_VIEWINV], 16, 1);
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEWPROJECTION, DST.view_data.matstate.mat[DRW_MAT_PERS], 16, 1);
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_VIEWPROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_PERSINV], 16, 1);
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_PROJECTION, DST.view_data.matstate.mat[DRW_MAT_WIN], 16, 1);
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_PROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_WININV], 16, 1);
+ drw_interface_builtin_uniform(shgroup, GWN_UNIFORM_CAMERATEXCO, DST.view_data.viewcamtexcofac, 3, 2);
+ }
+
+ shgroup->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL);
+ shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV);
+ shgroup->modelview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW);
+ shgroup->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW_INV);
+ shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MVP);
+ shgroup->normalview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_NORMAL);
+ shgroup->normalworld = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_WORLDNORMAL);
+ shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_ORCO);
+ shgroup->eye = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_EYE);
+
+ shgroup->matflag = 0;
+ if (shgroup->modelinverse > -1)
+ shgroup->matflag |= DRW_CALL_MODELINVERSE;
+ if (shgroup->modelview > -1)
+ shgroup->matflag |= DRW_CALL_MODELVIEW;
+ if (shgroup->modelviewinverse > -1)
+ shgroup->matflag |= DRW_CALL_MODELVIEWINVERSE;
+ if (shgroup->modelviewprojection > -1)
+ shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
+ if (shgroup->normalview > -1)
+ shgroup->matflag |= DRW_CALL_NORMALVIEW;
+ if (shgroup->normalworld > -1)
+ shgroup->matflag |= DRW_CALL_NORMALWORLD;
+ if (shgroup->orcotexfac > -1)
+ shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
+ if (shgroup->eye > -1)
+ shgroup->matflag |= DRW_CALL_EYEVEC;
+}
+
+static void drw_interface_instance_init(
+ DRWShadingGroup *shgroup, GPUShader *shader, Gwn_Batch *batch, Gwn_VertFormat *format)
+{
+ BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
+ BLI_assert(batch != NULL);
+ BLI_assert(format != NULL);
+
+ drw_interface_init(shgroup, shader);
+
+ shgroup->instance_geom = batch;
+#ifndef NDEBUG
+ shgroup->attribs_count = format->attrib_ct;
+#endif
+
+ DRW_instancing_buffer_request(DST.idatalist, format, batch, shgroup,
+ &shgroup->instance_geom, &shgroup->instance_vbo);
+}
+
+static void drw_interface_batching_init(
+ DRWShadingGroup *shgroup, GPUShader *shader, Gwn_VertFormat *format)
+{
+ drw_interface_init(shgroup, shader);
+
+#ifndef NDEBUG
+ shgroup->attribs_count = (format != NULL) ? format->attrib_ct : 0;
+#endif
+ BLI_assert(format != NULL);
+
+ Gwn_PrimType type;
+ switch (shgroup->type) {
+ case DRW_SHG_POINT_BATCH: type = GWN_PRIM_POINTS; break;
+ case DRW_SHG_LINE_BATCH: type = GWN_PRIM_LINES; break;
+ case DRW_SHG_TRIANGLE_BATCH: type = GWN_PRIM_TRIS; break;
+ default: type = GWN_PRIM_NONE; BLI_assert(0); break;
+ }
+
+ DRW_batching_buffer_request(DST.idatalist, format, type, shgroup,
+ &shgroup->batch_geom, &shgroup->batch_vbo);
+}
+
+static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups);
+
+ BLI_LINKS_APPEND(&pass->shgroups, shgroup);
+
+ shgroup->type = DRW_SHG_NORMAL;
+ shgroup->shader = shader;
+ shgroup->state_extra = 0;
+ shgroup->state_extra_disable = ~0x0;
+ shgroup->stencil_mask = 0;
+ shgroup->calls.first = NULL;
+ shgroup->calls.last = NULL;
+#if 0 /* All the same in the union! */
+ shgroup->batch_geom = NULL;
+ shgroup->batch_vbo = NULL;
+
+ shgroup->instance_geom = NULL;
+ shgroup->instance_vbo = NULL;
+#endif
+
+#ifdef USE_GPU_SELECT
+ shgroup->pass_parent = pass;
+#endif
+
+ return shgroup;
+}
+
+static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass *pass)
+{
+ if (!gpupass) {
+ /* Shader compilation error */
+ return NULL;
+ }
+
+ DRWShadingGroup *grp = drw_shgroup_create_ex(GPU_pass_shader(gpupass), pass);
+ return grp;
+}
+
+static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct GPUMaterial *material)
+{
+ /* TODO : Ideally we should not convert. But since the whole codegen
+ * is relying on GPUPass we keep it as is for now. */
+
+ ListBase *inputs = GPU_material_get_inputs(material);
+
+ /* Converting dynamic GPUInput to DRWUniform */
+ for (GPUInput *input = inputs->first; input; input = input->next) {
+ /* Textures */
+ if (input->ima) {
+ double time = 0.0; /* TODO make time variable */
+ GPUTexture *tex = GPU_texture_from_blender(
+ input->ima, input->iuser, input->textarget, input->image_isdata, time, 1);
+
+ if (input->bindtex) {
+ DRW_shgroup_uniform_texture(grp, input->shadername, tex);
+ }
+ }
+ /* Color Ramps */
+ else if (input->tex) {
+ DRW_shgroup_uniform_texture(grp, input->shadername, input->tex);
+ }
+ /* Floats */
+ else {
+ switch (input->type) {
+ case GPU_FLOAT:
+ case GPU_VEC2:
+ case GPU_VEC3:
+ case GPU_VEC4:
+ /* Should already be in the material ubo. */
+ break;
+ case GPU_MAT3:
+ DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec);
+ break;
+ case GPU_MAT4:
+ DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material);
+ if (ubo != NULL) {
+ DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
+ }
+
+ return grp;
+}
+
+Gwn_VertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize)
+{
+ Gwn_VertFormat *format = MEM_callocN(sizeof(Gwn_VertFormat), "Gwn_VertFormat");
+
+ for (int i = 0; i < arraysize; ++i) {
+ GWN_vertformat_attr_add(format, attribs[i].name,
+ (attribs[i].type == DRW_ATTRIB_INT) ? GWN_COMP_I32 : GWN_COMP_F32,
+ attribs[i].components,
+ (attribs[i].type == DRW_ATTRIB_INT) ? GWN_FETCH_INT : GWN_FETCH_FLOAT);
+ }
+ return format;
+}
+
+DRWShadingGroup *DRW_shgroup_material_create(
+ struct GPUMaterial *material, DRWPass *pass)
+{
+ GPUPass *gpupass = GPU_material_get_pass(material);
+ DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
+
+ if (shgroup) {
+ drw_interface_init(shgroup, GPU_pass_shader(gpupass));
+ drw_shgroup_material_inputs(shgroup, material);
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_material_instance_create(
+ struct GPUMaterial *material, DRWPass *pass, Gwn_Batch *geom, Object *ob, Gwn_VertFormat *format)
+{
+ GPUPass *gpupass = GPU_material_get_pass(material);
+ DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
+
+ if (shgroup) {
+ shgroup->type = DRW_SHG_INSTANCE;
+ shgroup->instance_geom = geom;
+ drw_call_calc_orco(ob->data, shgroup->instance_orcofac);
+ drw_interface_instance_init(shgroup, GPU_pass_shader(gpupass), geom, format);
+ drw_shgroup_material_inputs(shgroup, material);
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(
+ struct GPUMaterial *material, DRWPass *pass, int tri_count)
+{
+#ifdef USE_GPU_SELECT
+ BLI_assert((G.f & G_PICKSEL) == 0);
+#endif
+ GPUPass *gpupass = GPU_material_get_pass(material);
+ DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
+
+ if (shgroup) {
+ /* Calling drw_interface_init will cause it to call GWN_draw_primitive(). */
+ drw_interface_init(shgroup, GPU_pass_shader(gpupass));
+ shgroup->type = DRW_SHG_TRIANGLE_BATCH;
+ shgroup->instance_count = tri_count * 3;
+ drw_shgroup_material_inputs(shgroup, material);
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ drw_interface_init(shgroup, shader);
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_instance_create(
+ struct GPUShader *shader, DRWPass *pass, Gwn_Batch *geom, Gwn_VertFormat *format)
+{
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_INSTANCE;
+ shgroup->instance_geom = geom;
+ drw_call_calc_orco(NULL, shgroup->instance_orcofac);
+ drw_interface_instance_init(shgroup, shader, geom, format);
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
+
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_POINT_BATCH;
+
+ drw_interface_batching_init(shgroup, shader, g_pos_format);
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
+
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_LINE_BATCH;
+
+ drw_interface_batching_init(shgroup, shader, g_pos_format);
+
+ return shgroup;
+}
+
+/* Very special batch. Use this if you position
+ * your vertices with the vertex shader
+ * and dont need any VBO attrib */
+DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int tri_count)
+{
+#ifdef USE_GPU_SELECT
+ BLI_assert((G.f & G_PICKSEL) == 0);
+#endif
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+
+ /* Calling drw_interface_init will cause it to call GWN_draw_primitive(). */
+ drw_interface_init(shgroup, shader);
+
+ shgroup->type = DRW_SHG_TRIANGLE_BATCH;
+ shgroup->instance_count = tri_count * 3;
+
+ return shgroup;
+}
+
+/* Specify an external batch instead of adding each attrib one by one. */
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batch)
+{
+ BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
+ BLI_assert(shgroup->instance_count == 0);
+ /* You cannot use external instancing batch without a dummy format. */
+ BLI_assert(shgroup->attribs_count != 0);
+
+ shgroup->type = DRW_SHG_INSTANCE_EXTERNAL;
+ drw_call_calc_orco(NULL, shgroup->instance_orcofac);
+ /* PERF : This destroys the vaos cache so better check if it's necessary. */
+ /* Note: This WILL break if batch->verts[0] is destroyed and reallocated
+ * at the same adress. Bindings/VAOs would remain obsolete. */
+ //if (shgroup->instancing_geom->inst != batch->verts[0])
+ GWN_batch_instbuf_set(shgroup->instance_geom, batch->verts[0], false);
+
+#ifdef USE_GPU_SELECT
+ shgroup->override_selectid = DST.select_id;
+#endif
+}
+
+unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup)
+{
+ return shgroup->instance_count;
+}
+
+/**
+ * State is added to #Pass.state while drawing.
+ * Use to temporarily enable draw options.
+ */
+void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
+{
+ shgroup->state_extra |= state;
+}
+
+void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
+{
+ shgroup->state_extra_disable &= ~state;
+}
+
+void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask)
+{
+ BLI_assert(mask <= 255);
+ shgroup->stencil_mask = mask;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Passes (DRW_pass)
+ * \{ */
+
+DRWPass *DRW_pass_create(const char *name, DRWState state)
+{
+ DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes);
+ pass->state = state;
+ if (G.debug_value > 20) {
+ BLI_strncpy(pass->name, name, MAX_PASS_NAME);
+ }
+
+ pass->shgroups.first = NULL;
+ pass->shgroups.last = NULL;
+
+ return pass;
+}
+
+void DRW_pass_state_set(DRWPass *pass, DRWState state)
+{
+ pass->state = state;
+}
+
+void DRW_pass_free(DRWPass *pass)
+{
+ pass->shgroups.first = NULL;
+ pass->shgroups.last = NULL;
+}
+
+void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData)
+{
+ for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
+ callback(userData, shgroup);
+ }
+}
+
+typedef struct ZSortData {
+ float *axis;
+ float *origin;
+} ZSortData;
+
+static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
+{
+ const ZSortData *zsortdata = (ZSortData *)thunk;
+ const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
+ const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
+
+ const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
+ const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
+
+ if (call_a == NULL) return -1;
+ if (call_b == NULL) return -1;
+
+ float tmp[3];
+ sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
+ const float a_sq = dot_v3v3(zsortdata->axis, tmp);
+ sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
+ const float b_sq = dot_v3v3(zsortdata->axis, tmp);
+
+ if (a_sq < b_sq) return 1;
+ else if (a_sq > b_sq) return -1;
+ else {
+ /* If there is a depth prepass put it before */
+ if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ return -1;
+ }
+ else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ return 1;
+ }
+ else return 0;
+ }
+}
+
+/* ------------------ Shading group sorting --------------------- */
+
+#define SORT_IMPL_LINKTYPE DRWShadingGroup
+
+#define SORT_IMPL_USE_THUNK
+#define SORT_IMPL_FUNC shgroup_sort_fn_r
+#include "../../blenlib/intern/list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+#undef SORT_IMPL_USE_THUNK
+
+#undef SORT_IMPL_LINKTYPE
+
+/**
+ * Sort Shading groups by decreasing Z of their first draw call.
+ * This is usefull for order dependant effect such as transparency.
+ **/
+void DRW_pass_sort_shgroup_z(DRWPass *pass)
+{
+ float (*viewinv)[4];
+ viewinv = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
+
+ ZSortData zsortdata = {viewinv[2], viewinv[3]};
+
+ if (pass->shgroups.first && pass->shgroups.first->next) {
+ pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
+
+ /* Find the next last */
+ DRWShadingGroup *last = pass->shgroups.first;
+ while ((last = last->next)) {
+ /* Do nothing */
+ }
+ pass->shgroups.last = last;
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
new file mode 100644
index 00000000000..e90c1f63ecd
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -0,0 +1,1076 @@
+/*
+ * 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_manager_exec.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#include "BLI_mempool.h"
+
+#include "BIF_glutil.h"
+
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+
+#ifdef USE_GPU_SELECT
+# include "ED_view3d.h"
+# include "ED_armature.h"
+# include "GPU_select.h"
+#endif
+
+#ifdef USE_GPU_SELECT
+void DRW_select_load_id(unsigned int id)
+{
+ BLI_assert(G.f & G_PICKSEL);
+ DST.select_id = id;
+}
+#endif
+
+struct GPUUniformBuffer *view_ubo;
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw State (DRW_state)
+ * \{ */
+
+void drw_state_set(DRWState state)
+{
+ if (DST.state == state) {
+ return;
+ }
+
+#define CHANGED_TO(f) \
+ ((DST.state_lock & (f)) ? 0 : \
+ (((DST.state & (f)) ? \
+ ((state & (f)) ? 0 : -1) : \
+ ((state & (f)) ? 1 : 0))))
+
+#define CHANGED_ANY(f) \
+ (((DST.state & (f)) != (state & (f))) && \
+ ((DST.state_lock & (f)) == 0))
+
+#define CHANGED_ANY_STORE_VAR(f, enabled) \
+ (((DST.state & (f)) != (enabled = (state & (f)))) && \
+ (((DST.state_lock & (f)) == 0)))
+
+ /* Depth Write */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) {
+ if (test == 1) {
+ glDepthMask(GL_TRUE);
+ }
+ else {
+ glDepthMask(GL_FALSE);
+ }
+ }
+ }
+
+ /* Color Write */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) {
+ if (test == 1) {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+ else {
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ }
+ }
+ }
+
+ /* Cull */
+ {
+ DRWState test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT,
+ test))
+ {
+ if (test) {
+ glEnable(GL_CULL_FACE);
+
+ if ((state & DRW_STATE_CULL_BACK) != 0) {
+ glCullFace(GL_BACK);
+ }
+ else if ((state & DRW_STATE_CULL_FRONT) != 0) {
+ glCullFace(GL_FRONT);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_CULL_FACE);
+ }
+ }
+ }
+
+ /* Depth Test */
+ {
+ DRWState test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER | DRW_STATE_DEPTH_ALWAYS,
+ test))
+ {
+ if (test) {
+ glEnable(GL_DEPTH_TEST);
+
+ if (state & DRW_STATE_DEPTH_LESS) {
+ glDepthFunc(GL_LEQUAL);
+ }
+ else if (state & DRW_STATE_DEPTH_EQUAL) {
+ glDepthFunc(GL_EQUAL);
+ }
+ else if (state & DRW_STATE_DEPTH_GREATER) {
+ glDepthFunc(GL_GREATER);
+ }
+ else if (state & DRW_STATE_DEPTH_ALWAYS) {
+ glDepthFunc(GL_ALWAYS);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ }
+ }
+
+ /* Wire Width */
+ {
+ if (CHANGED_ANY(DRW_STATE_WIRE)) {
+ if ((state & DRW_STATE_WIRE) != 0) {
+ glLineWidth(1.0f);
+ }
+ else {
+ /* do nothing */
+ }
+ }
+ }
+
+ /* Points Size */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_POINT))) {
+ if (test == 1) {
+ GPU_enable_program_point_size();
+ glPointSize(5.0f);
+ }
+ else {
+ GPU_disable_program_point_size();
+ }
+ }
+ }
+
+ /* Blending (all buffer) */
+ {
+ int test;
+ if (CHANGED_ANY_STORE_VAR(
+ 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) {
+ 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);
+ }
+ else if ((state & DRW_STATE_TRANSMISSION) != 0) {
+ glBlendFunc(GL_ONE, GL_SRC_ALPHA);
+ }
+ else if ((state & DRW_STATE_ADDITIVE) != 0) {
+ /* 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);
+ }
+ }
+ else {
+ glDisable(GL_BLEND);
+ }
+ }
+ }
+
+ /* Clip Planes */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) {
+ if (test == 1) {
+ for (int i = 0; i < DST.num_clip_planes; ++i) {
+ glEnable(GL_CLIP_DISTANCE0 + i);
+ }
+ }
+ else {
+ for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
+ glDisable(GL_CLIP_DISTANCE0 + i);
+ }
+ }
+ }
+ }
+
+ /* Line Stipple */
+ {
+ int test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4,
+ test))
+ {
+ if (test) {
+ if ((state & DRW_STATE_STIPPLE_2) != 0) {
+ setlinestyle(2);
+ }
+ else if ((state & DRW_STATE_STIPPLE_3) != 0) {
+ setlinestyle(3);
+ }
+ else if ((state & DRW_STATE_STIPPLE_4) != 0) {
+ setlinestyle(4);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ setlinestyle(0);
+ }
+ }
+ }
+
+ /* Stencil */
+ {
+ DRWState test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_WRITE_STENCIL |
+ DRW_STATE_STENCIL_EQUAL,
+ test))
+ {
+ if (test) {
+ glEnable(GL_STENCIL_TEST);
+
+ /* Stencil Write */
+ if ((state & DRW_STATE_WRITE_STENCIL) != 0) {
+ glStencilMask(0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ }
+ /* Stencil Test */
+ else if ((state & DRW_STATE_STENCIL_EQUAL) != 0) {
+ glStencilMask(0x00); /* disable write */
+ DST.stencil_mask = 0;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ /* disable write & test */
+ DST.stencil_mask = 0;
+ glStencilMask(0x00);
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glDisable(GL_STENCIL_TEST);
+ }
+ }
+ }
+
+#undef CHANGED_TO
+#undef CHANGED_ANY
+#undef CHANGED_ANY_STORE_VAR
+
+ DST.state = state;
+}
+
+static void drw_stencil_set(unsigned int mask)
+{
+ if (DST.stencil_mask != mask) {
+ /* Stencil Write */
+ if ((DST.state & DRW_STATE_WRITE_STENCIL) != 0) {
+ glStencilFunc(GL_ALWAYS, mask, 0xFF);
+ DST.stencil_mask = mask;
+ }
+ /* Stencil Test */
+ else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) {
+ glStencilFunc(GL_EQUAL, mask, 0xFF);
+ DST.stencil_mask = mask;
+ }
+ }
+}
+
+/* Reset state to not interfer with other UI drawcall */
+void DRW_state_reset_ex(DRWState state)
+{
+ DST.state = ~state;
+ drw_state_set(state);
+}
+
+/**
+ * Use with care, intended so selection code can override passes depth settings,
+ * which is important for selection to work properly.
+ *
+ * Should be set in main draw loop, cleared afterwards
+ */
+void DRW_state_lock(DRWState state)
+{
+ DST.state_lock = state;
+}
+
+void DRW_state_reset(void)
+{
+ /* Reset blending function */
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ DRW_state_reset_ex(DRW_STATE_DEFAULT);
+}
+
+/* NOTE : Make sure to reset after use! */
+void DRW_state_invert_facing(void)
+{
+ SWAP(GLenum, DST.backface, DST.frontface);
+ glFrontFace(DST.frontface);
+}
+
+/**
+ * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
+ * and if the shaders have support for it (see usage of gl_ClipDistance).
+ * Be sure to call DRW_state_clip_planes_reset() after you finish drawing.
+ **/
+void DRW_state_clip_planes_count_set(unsigned int plane_ct)
+{
+ BLI_assert(plane_ct <= MAX_CLIP_PLANES);
+ DST.num_clip_planes = plane_ct;
+}
+
+void DRW_state_clip_planes_reset(void)
+{
+ DST.num_clip_planes = 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Clipping (DRW_clipping)
+ * \{ */
+
+static void draw_clipping_setup_from_view(void)
+{
+ if (DST.clipping.updated)
+ return;
+
+ float (*viewinv)[4] = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
+ float (*projmat)[4] = DST.view_data.matstate.mat[DRW_MAT_WIN];
+ float (*projinv)[4] = DST.view_data.matstate.mat[DRW_MAT_WININV];
+ BoundSphere *bsphere = &DST.clipping.frustum_bsphere;
+
+ /* Extract Clipping Planes */
+ BoundBox bbox;
+ BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f});
+
+ /* Extract the 8 corners (world space). */
+ for (int i = 0; i < 8; i++) {
+ /* Use separate matrix mul for more precision. */
+ mul_project_m4_v3(projinv, bbox.vec[i]);
+ mul_m4_v3(viewinv, bbox.vec[i]);
+ }
+
+ /* Compute clip planes using the world space frustum corners. */
+ for (int p = 0; p < 6; p++) {
+ int q, r;
+ switch (p) {
+ case 0: q=1; r=2; break;
+ case 1: q=0; r=5; break;
+ case 2: q=1; r=5; break;
+ case 3: q=2; r=6; break;
+ case 4: q=0; r=3; break;
+ default: q=4; r=7; break;
+ }
+ if (DST.frontface == GL_CW) {
+ SWAP(int, q, r);
+ }
+
+ normal_tri_v3(DST.clipping.frustum_planes[p], bbox.vec[p], bbox.vec[q], bbox.vec[r]);
+ DST.clipping.frustum_planes[p][3] = -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[p]);
+ }
+
+ /* Extract Bounding Sphere */
+ if (projmat[3][3] != 0.0f) {
+ /* Orthographic */
+ /* The most extreme points on the near and far plane. (normalized device coords). */
+ float *nearpoint = bbox.vec[0];
+ float *farpoint = bbox.vec[6];
+
+ mul_project_m4_v3(projinv, nearpoint);
+ mul_project_m4_v3(projinv, farpoint);
+
+ /* just use median point */
+ mid_v3_v3v3(bsphere->center, farpoint, nearpoint);
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
+ }
+ else if (projmat[2][0] == 0.0f && projmat[2][1] == 0.0f) {
+ /* Perspective with symmetrical frustum. */
+
+ /* We obtain the center and radius of the circumscribed circle of the
+ * isosceles trapezoid composed by the diagonals of the near and far clipping plane */
+
+ /* center of each clipping plane */
+ float mid_min[3], mid_max[3];
+ mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]);
+ mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]);
+
+ /* square length of the diagonals of each clipping plane */
+ float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]);
+ float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]);
+
+ /* distance squared between clipping planes */
+ float h_sq = len_squared_v3v3(mid_min, mid_max);
+
+ float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq);
+ BLI_assert(fac >= 0.0f);
+
+ /* The goal is to get the smallest sphere,
+ * not the sphere that passes through each corner */
+ CLAMP(fac, 0.0f, 1.0f);
+
+ interp_v3_v3v3(bsphere->center, mid_min, mid_max, fac);
+
+ /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */
+ bsphere->radius = len_v3v3(bsphere->center, bbox.vec[1]);
+ }
+ else {
+ /* Perspective with asymmetrical frustum. */
+
+ /* We put the sphere center on the line that goes from origin
+ * to the center of the far clipping plane. */
+
+ /* Detect which of the corner of the far clipping plane is the farthest to the origin */
+ float nfar[4]; /* most extreme far point in NDC space */
+ float farxy[2]; /* farpoint projection onto the near plane */
+ float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */
+ float nearpoint[3]; /* most extreme near point in camera coordinate */
+ float farcenter[3] = {0.0f}; /* center of far cliping plane in camera coordinate */
+ float F = -1.0f, N; /* square distance of far and near point to origin */
+ float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */
+ float e, s; /* far and near clipping distance (<0) */
+ float c; /* slope of center line = distance of far clipping center to z axis / far clipping distance */
+ float z; /* projection of sphere center on z axis (<0) */
+
+ /* Find farthest corner and center of far clip plane. */
+ float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */
+ for (int i = 0; i < 4; i++) {
+ float point[3];
+ mul_v3_project_m4_v3(point, projinv, corner);
+ float len = len_squared_v3(point);
+ if (len > F) {
+ copy_v3_v3(nfar, corner);
+ copy_v3_v3(farpoint, point);
+ F = len;
+ }
+ add_v3_v3(farcenter, point);
+ /* rotate by 90 degree to walk through the 4 points of the far clip plane */
+ float tmp = corner[0];
+ corner[0] = -corner[1];
+ corner[1] = tmp;
+ }
+
+ /* the far center is the average of the far clipping points */
+ mul_v3_fl(farcenter, 0.25f);
+ /* the extreme near point is the opposite point on the near clipping plane */
+ copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f);
+ mul_v3_project_m4_v3(nearpoint, projinv, nfar);
+ /* this is a frustum projection */
+ N = len_squared_v3(nearpoint);
+ e = farpoint[2];
+ s = nearpoint[2];
+ /* distance to view Z axis */
+ f = len_v2(farpoint);
+ /* get corresponding point on the near plane */
+ mul_v2_v2fl(farxy, farpoint, s/e);
+ /* this formula preserve the sign of n */
+ sub_v2_v2(nearpoint, farxy);
+ n = f * s / e - len_v2(nearpoint);
+ c = len_v2(farcenter) / e;
+ /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */
+ z = (F-N) / (2.0f * (e-s + c*(f-n)));
+
+ bsphere->center[0] = farcenter[0] * z/e;
+ bsphere->center[1] = farcenter[1] * z/e;
+ bsphere->center[2] = z;
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
+
+ /* Transform to world space. */
+ mul_m4_v3(viewinv, bsphere->center);
+ }
+
+ DST.clipping.updated = true;
+}
+
+/* Return True if the given BoundSphere intersect the current view frustum */
+bool DRW_culling_sphere_test(BoundSphere *bsphere)
+{
+ draw_clipping_setup_from_view();
+
+ /* Bypass test if radius is negative. */
+ if (bsphere->radius < 0.0f)
+ return true;
+
+ /* Do a rough test first: Sphere VS Sphere intersect. */
+ BoundSphere *frustum_bsphere = &DST.clipping.frustum_bsphere;
+ float center_dist = len_squared_v3v3(bsphere->center, frustum_bsphere->center);
+ if (center_dist > SQUARE(bsphere->radius + frustum_bsphere->radius))
+ return false;
+
+ /* Test against the 6 frustum planes. */
+ for (int p = 0; p < 6; p++) {
+ float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bsphere->center);
+ if (dist < -bsphere->radius) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Return True if the given BoundBox intersect the current view frustum.
+ * bbox must be in world space. */
+bool DRW_culling_box_test(BoundBox *bbox)
+{
+ draw_clipping_setup_from_view();
+
+ /* 6 view frustum planes */
+ for (int p = 0; p < 6; p++) {
+ /* 8 box vertices. */
+ for (int v = 0; v < 8 ; v++) {
+ float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bbox->vec[v]);
+ if (dist > 0.0f) {
+ /* At least one point in front of this plane.
+ * Go to next plane. */
+ break;
+ }
+ else if (v == 7) {
+ /* 8 points behind this plane. */
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw (DRW_draw)
+ * \{ */
+
+static void draw_matrices_model_prepare(DRWCallState *st)
+{
+ if (st->cache_id == DST.state_cache_id) {
+ return; /* Values are already updated for this view. */
+ }
+ else {
+ st->cache_id = DST.state_cache_id;
+ }
+
+ if (DRW_culling_sphere_test(&st->bsphere)) {
+ st->flag &= ~DRW_CALL_CULLED;
+ }
+ else {
+ st->flag |= DRW_CALL_CULLED;
+ return; /* No need to go further the call will not be used. */
+ }
+
+ /* Order matters */
+ if (st->matflag & (DRW_CALL_MODELVIEW | DRW_CALL_MODELVIEWINVERSE |
+ DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC))
+ {
+ mul_m4_m4m4(st->modelview, DST.view_data.matstate.mat[DRW_MAT_VIEW], st->model);
+ }
+ if (st->matflag & DRW_CALL_MODELVIEWINVERSE) {
+ invert_m4_m4(st->modelviewinverse, st->modelview);
+ }
+ if (st->matflag & DRW_CALL_MODELVIEWPROJECTION) {
+ mul_m4_m4m4(st->modelviewprojection, DST.view_data.matstate.mat[DRW_MAT_PERS], st->model);
+ }
+ if (st->matflag & (DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC)) {
+ copy_m3_m4(st->normalview, st->modelview);
+ invert_m3(st->normalview);
+ transpose_m3(st->normalview);
+ }
+ if (st->matflag & DRW_CALL_EYEVEC) {
+ /* Used by orthographic wires */
+ float tmp[3][3];
+ copy_v3_fl3(st->eyevec, 0.0f, 0.0f, 1.0f);
+ invert_m3_m3(tmp, st->normalview);
+ /* set eye vector, transformed to object coords */
+ mul_m3_v3(tmp, st->eyevec);
+ }
+ /* Non view dependant */
+ if (st->matflag & DRW_CALL_MODELINVERSE) {
+ invert_m4_m4(st->modelinverse, st->model);
+ st->matflag &= ~DRW_CALL_MODELINVERSE;
+ }
+ if (st->matflag & DRW_CALL_NORMALWORLD) {
+ copy_m3_m4(st->normalworld, st->model);
+ invert_m3(st->normalworld);
+ transpose_m3(st->normalworld);
+ st->matflag &= ~DRW_CALL_NORMALWORLD;
+ }
+}
+
+static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCallState *state)
+{
+ /* step 1 : bind object dependent matrices */
+ if (state != NULL) {
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelview, 16, 1, (float *)state->modelview);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)state->modelviewinverse);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)state->modelviewprojection);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->normalview, 9, 1, (float *)state->normalview);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->normalworld, 9, 1, (float *)state->normalworld);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->eye, 3, 1, (float *)state->eyevec);
+ }
+ else {
+ BLI_assert((shgroup->normalview == -1) && (shgroup->normalworld == -1) && (shgroup->eye == -1));
+ /* For instancing and batching. */
+ float unitmat[4][4];
+ unit_m4(unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelview, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_VIEW]);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_VIEWINV]);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_PERS]);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)shgroup->instance_orcofac);
+ }
+}
+
+static void draw_geometry_execute_ex(
+ DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count, bool draw_instance)
+{
+ /* Special case: empty drawcall, placement is done via shader, don't bind anything. */
+ if (geom == NULL) {
+ BLI_assert(shgroup->type == DRW_SHG_TRIANGLE_BATCH); /* Add other type if needed. */
+ /* Shader is already bound. */
+ GWN_draw_primitive(GWN_PRIM_TRIS, count);
+ return;
+ }
+
+ /* step 2 : bind vertex array & draw */
+ GWN_batch_program_set_no_use(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+ /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */
+ geom->program_in_use = true;
+
+ GWN_batch_draw_range_ex(geom, start, count, draw_instance);
+
+ geom->program_in_use = false; /* XXX hacking gawain */
+}
+
+static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom)
+{
+ draw_geometry_execute_ex(shgroup, geom, 0, 0, false);
+}
+
+enum {
+ BIND_NONE = 0,
+ BIND_TEMP = 1, /* Release slot after this shading group. */
+ BIND_PERSIST = 2, /* Release slot only after the next shader change. */
+};
+
+static void bind_texture(GPUTexture *tex, char bind_type)
+{
+ int index;
+ char *slot_flags = DST.RST.bound_tex_slots;
+ int bind_num = GPU_texture_bound_number(tex);
+ if (bind_num == -1) {
+ for (int i = 0; i < GPU_max_textures(); ++i) {
+ index = DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures();
+ if (slot_flags[index] == BIND_NONE) {
+ if (DST.RST.bound_texs[index] != NULL) {
+ GPU_texture_unbind(DST.RST.bound_texs[index]);
+ }
+ GPU_texture_bind(tex, index);
+ DST.RST.bound_texs[index] = tex;
+ slot_flags[index] = bind_type;
+ // printf("Binds Texture %d %p\n", DST.RST.bind_tex_inc, tex);
+ return;
+ }
+ }
+ printf("Not enough texture slots! Reduce number of textures used by your shader.\n");
+ }
+ slot_flags[bind_num] = bind_type;
+}
+
+static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
+{
+ int index;
+ char *slot_flags = DST.RST.bound_ubo_slots;
+ int bind_num = GPU_uniformbuffer_bindpoint(ubo);
+ if (bind_num == -1) {
+ for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
+ index = DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds();
+ if (slot_flags[index] == BIND_NONE) {
+ if (DST.RST.bound_ubos[index] != NULL) {
+ GPU_uniformbuffer_unbind(DST.RST.bound_ubos[index]);
+ }
+ GPU_uniformbuffer_bind(ubo, index);
+ DST.RST.bound_ubos[index] = ubo;
+ slot_flags[bind_num] = bind_type;
+ return;
+ }
+ }
+ /* printf so user can report bad behaviour */
+ printf("Not enough ubo slots! This should not happen!\n");
+ /* This is not depending on user input.
+ * It is our responsability to make sure there is enough slots. */
+ BLI_assert(0);
+ }
+ slot_flags[bind_num] = bind_type;
+}
+
+static void release_texture_slots(bool with_persist)
+{
+ if (with_persist) {
+ memset(DST.RST.bound_tex_slots, 0x0, sizeof(*DST.RST.bound_tex_slots) * GPU_max_textures());
+ }
+ else {
+ for (int i = 0; i < GPU_max_textures(); ++i) {
+ if (DST.RST.bound_tex_slots[i] != BIND_PERSIST)
+ DST.RST.bound_tex_slots[i] = BIND_NONE;
+ }
+ }
+}
+
+static void release_ubo_slots(bool with_persist)
+{
+ if (with_persist) {
+ memset(DST.RST.bound_ubo_slots, 0x0, sizeof(*DST.RST.bound_ubo_slots) * GPU_max_ubo_binds());
+ }
+ else {
+ for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
+ if (DST.RST.bound_ubo_slots[i] != BIND_PERSIST)
+ DST.RST.bound_ubo_slots[i] = BIND_NONE;
+ }
+ }
+}
+
+static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
+{
+ BLI_assert(shgroup->shader);
+
+ GPUTexture *tex;
+ GPUUniformBuffer *ubo;
+ int val;
+ float fval;
+ const bool shader_changed = (DST.shader != shgroup->shader);
+
+ if (shader_changed) {
+ if (DST.shader) GPU_shader_unbind();
+ GPU_shader_bind(shgroup->shader);
+ DST.shader = shgroup->shader;
+ }
+
+ release_ubo_slots(shader_changed);
+ release_texture_slots(shader_changed);
+
+ drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
+ drw_stencil_set(shgroup->stencil_mask);
+
+ /* Binding Uniform */
+ /* Don't check anything, Interface should already contain the least uniform as possible */
+ for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) {
+ switch (uni->type) {
+ case DRW_UNIFORM_SHORT_TO_INT:
+ val = (int)*((short *)uni->value);
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)&val);
+ break;
+ case DRW_UNIFORM_SHORT_TO_FLOAT:
+ fval = (float)*((short *)uni->value);
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval);
+ break;
+ case DRW_UNIFORM_BOOL:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value);
+ break;
+ case DRW_UNIFORM_FLOAT:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->value;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->value;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BUFFER:
+ if (!DRW_state_is_fbo()) {
+ break;
+ }
+ tex = *((GPUTexture **)uni->value);
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ ubo = (GPUUniformBuffer *)uni->value;
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->value;
+ bind_ubo(ubo, BIND_PERSIST);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ }
+ }
+
+#ifdef USE_GPU_SELECT
+# define GPU_SELECT_LOAD_IF_PICKSEL(_select_id) \
+ if (G.f & G_PICKSEL) { \
+ GPU_select_load_id(_select_id); \
+ } ((void)0)
+
+# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(_call) \
+ if ((G.f & G_PICKSEL) && (_call)) { \
+ GPU_select_load_id((_call)->select_id); \
+ } ((void)0)
+
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \
+ _start = 0; \
+ _count = _shgroup->instance_count; \
+ int *select_id = NULL; \
+ if (G.f & G_PICKSEL) { \
+ if (_shgroup->override_selectid == -1) { \
+ select_id = DRW_instance_data_get(_shgroup->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->override_selectid); \
+ } \
+ } \
+ while (_start < _shgroup->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(select_id)
+# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(call)
+# 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 */
+ if (!ELEM(shgroup->type, DRW_SHG_NORMAL)) {
+ /* Replacing multiple calls with only one */
+ if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) {
+ if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) {
+ if (shgroup->instance_geom != NULL) {
+ GPU_SELECT_LOAD_IF_PICKSEL(shgroup->override_selectid);
+ draw_geometry_prepare(shgroup, NULL);
+ draw_geometry_execute_ex(shgroup, shgroup->instance_geom, 0, 0, true);
+ }
+ }
+ else {
+ if (shgroup->instance_count > 0) {
+ unsigned int count, start;
+ draw_geometry_prepare(shgroup, NULL);
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count)
+ {
+ draw_geometry_execute_ex(shgroup, shgroup->instance_geom, start, count, true);
+ }
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+ }
+ }
+ }
+ else { /* DRW_SHG_***_BATCH */
+ /* Some dynamic batch can have no geom (no call to aggregate) */
+ if (shgroup->instance_count > 0) {
+ unsigned int count, start;
+ draw_geometry_prepare(shgroup, NULL);
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count)
+ {
+ draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count, false);
+ }
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+ }
+ }
+ }
+ else {
+ bool prev_neg_scale = false;
+ for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
+
+ /* OPTI/IDEA(clem): Do this preparation in another thread. */
+ draw_matrices_model_prepare(call->state);
+
+ if ((call->state->flag & DRW_CALL_CULLED) != 0)
+ continue;
+
+ /* Negative scale objects */
+ bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE;
+ if (neg_scale != prev_neg_scale) {
+ glFrontFace((neg_scale) ? DST.backface : DST.frontface);
+ prev_neg_scale = neg_scale;
+ }
+
+ GPU_SELECT_LOAD_IF_PICKSEL_CALL(call);
+ draw_geometry_prepare(shgroup, call->state);
+
+ switch (call->type) {
+ case DRW_CALL_SINGLE:
+ draw_geometry_execute(shgroup, call->single.geometry);
+ break;
+ case DRW_CALL_INSTANCES:
+ draw_geometry_execute_ex(shgroup, call->instances.geometry, 0, *call->instances.count, true);
+ break;
+ case DRW_CALL_GENERATE:
+ call->generate.geometry_fn(shgroup, draw_geometry_execute, call->generate.user_data);
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ /* Reset state */
+ glFrontFace(DST.frontface);
+ }
+
+ /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */
+ DRW_state_reset();
+}
+
+static void drw_update_view(void)
+{
+ if (DST.dirty_mat) {
+ DST.state_cache_id++;
+ DST.dirty_mat = false;
+
+ DRW_uniformbuffer_update(view_ubo, &DST.view_data);
+
+ /* Catch integer wrap around. */
+ if (UNLIKELY(DST.state_cache_id == 0)) {
+ DST.state_cache_id = 1;
+ /* We must reset all CallStates to ensure that not
+ * a single one stayed with cache_id equal to 1. */
+ BLI_mempool_iter iter;
+ DRWCallState *state;
+ BLI_mempool_iternew(DST.vmempool->states, &iter);
+ while ((state = BLI_mempool_iterstep(&iter))) {
+ state->cache_id = 0;
+ }
+ }
+
+ /* TODO dispatch threads to compute matrices/culling */
+ }
+
+ draw_clipping_setup_from_view();
+}
+
+static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
+{
+ DST.shader = NULL;
+
+ BLI_assert(DST.buffer_finish_called && "DRW_render_instance_buffer_finish had not been called before drawing");
+
+ drw_update_view();
+
+ drw_state_set(pass->state);
+
+ DRW_stats_query_start(pass->name);
+
+ for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) {
+ draw_shgroup(shgroup, pass->state);
+ /* break if upper limit */
+ if (shgroup == end_group) {
+ break;
+ }
+ }
+
+ /* Clear Bound textures */
+ for (int i = 0; i < GPU_max_textures(); i++) {
+ if (DST.RST.bound_texs[i] != NULL) {
+ GPU_texture_unbind(DST.RST.bound_texs[i]);
+ DST.RST.bound_texs[i] = NULL;
+ }
+ }
+
+ /* Clear Bound Ubos */
+ for (int i = 0; i < GPU_max_ubo_binds(); i++) {
+ if (DST.RST.bound_ubos[i] != NULL) {
+ GPU_uniformbuffer_unbind(DST.RST.bound_ubos[i]);
+ DST.RST.bound_ubos[i] = NULL;
+ }
+ }
+
+ if (DST.shader) {
+ GPU_shader_unbind();
+ DST.shader = NULL;
+ }
+
+ DRW_stats_query_end();
+}
+
+void DRW_draw_pass(DRWPass *pass)
+{
+ drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last);
+}
+
+/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
+void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
+{
+ drw_draw_pass_ex(pass, start_group, end_group);
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager_framebuffer.c b/source/blender/draw/intern/draw_manager_framebuffer.c
new file mode 100644
index 00000000000..a76b1c42a53
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_framebuffer.c
@@ -0,0 +1,189 @@
+/*
+ * 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_manager_framebuffer.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+GPUFrameBuffer *DRW_framebuffer_create(void)
+{
+ return GPU_framebuffer_create();
+}
+
+void DRW_framebuffer_init(
+ 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;
+
+ if (!*fb) {
+ *fb = GPU_framebuffer_create();
+ create_fb = true;
+ }
+
+ for (int i = 0; i < textures_len; ++i) {
+ int channels;
+ bool is_depth;
+ bool create_tex = false;
+ GPUTextureFormat gpu_format;
+
+ DRWFboTexture fbotex = textures[i];
+ bool is_temp = (fbotex.flag & DRW_TEX_TEMP) != 0;
+
+ drw_texture_get_format(fbotex.format, true, &gpu_format, &channels, &is_depth);
+
+ if (!*fbotex.tex || is_temp) {
+ /* Temp textures need to be queried each frame, others not. */
+ if (is_temp) {
+ *fbotex.tex = GPU_viewport_texture_pool_query(
+ DST.viewport, engine_type, width, height, channels, gpu_format);
+ }
+ else {
+ *fbotex.tex = GPU_texture_create_2D_custom(
+ width, height, channels, gpu_format, NULL, NULL);
+ create_tex = true;
+ }
+ }
+
+ 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);
+ }
+ }
+
+ if (create_fb && (textures_len > 0)) {
+ if (!GPU_framebuffer_check_valid(*fb, NULL)) {
+ printf("Error invalid framebuffer\n");
+ }
+
+ /* Detach temp textures */
+ for (int i = 0; i < textures_len; ++i) {
+ DRWFboTexture fbotex = textures[i];
+
+ if ((fbotex.flag & DRW_TEX_TEMP) != 0) {
+ GPU_framebuffer_texture_detach(*fbotex.tex);
+ }
+ }
+
+ if (DST.default_framebuffer != NULL) {
+ GPU_framebuffer_bind(DST.default_framebuffer);
+ }
+ }
+}
+
+void DRW_framebuffer_free(GPUFrameBuffer *fb)
+{
+ GPU_framebuffer_free(fb);
+}
+
+void DRW_framebuffer_bind(GPUFrameBuffer *fb)
+{
+ GPU_framebuffer_bind(fb);
+}
+
+void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth)
+{
+ if (color) {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
+ }
+ if (depth) {
+ glDepthMask(GL_TRUE);
+ glClearDepth(clear_depth);
+ }
+ if (stencil) {
+ glStencilMask(0xFF);
+ }
+ glClear(((color) ? GL_COLOR_BUFFER_BIT : 0) |
+ ((depth) ? GL_DEPTH_BUFFER_BIT : 0) |
+ ((stencil) ? GL_STENCIL_BUFFER_BIT : 0));
+}
+
+void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data)
+{
+ GLenum type;
+ switch (channels) {
+ case 1: type = GL_RED; break;
+ case 2: type = GL_RG; break;
+ case 3: type = GL_RGB; break;
+ case 4: type = GL_RGBA; break;
+ default:
+ BLI_assert(false && "wrong number of read channels");
+ return;
+ }
+ glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
+ 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(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
+{
+ GPU_framebuffer_texture_attach(fb, tex, slot, mip);
+}
+
+void DRW_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
+{
+ GPU_framebuffer_texture_layer_attach(fb, tex, slot, layer, mip);
+}
+
+void DRW_framebuffer_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
+{
+ GPU_framebuffer_texture_cubeface_attach(fb, tex, slot, face, mip);
+}
+
+void DRW_framebuffer_texture_detach(GPUTexture *tex)
+{
+ GPU_framebuffer_texture_detach(tex);
+}
+
+void DRW_framebuffer_blit(GPUFrameBuffer *fb_read, GPUFrameBuffer *fb_write, bool depth, bool stencil)
+{
+ GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth, stencil);
+}
+
+void DRW_framebuffer_recursive_downsample(
+ GPUFrameBuffer *fb, GPUTexture *tex, int num_iter,
+ void (*callback)(void *userData, int level), void *userData)
+{
+ GPU_framebuffer_recursive_downsample(fb, tex, num_iter, callback, userData);
+}
+
+void DRW_framebuffer_viewport_size(GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h)
+{
+ glViewport(x, y, w, h);
+}
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index f9fbbac2e2e..47769b1fb18 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -32,7 +32,12 @@
#include "MEM_guardedalloc.h"
+#include "draw_manager.h"
+
#include "GPU_glew.h"
+#include "GPU_texture.h"
+
+#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -198,14 +203,121 @@ void DRW_stats_reset(void)
}
}
+static void draw_stat_5row(rcti *rect, int u, int v, const char *txt, const int size)
+{
+ BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit,
+ rect->ymax - (3 + v) * U.widget_unit, 0.0f,
+ txt, size);
+}
+
+static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size)
+{
+ BLF_draw_default_ascii(rect->xmin + (1 + u) * U.widget_unit,
+ rect->ymax - (3 + v) * U.widget_unit, 0.0f,
+ txt, size);
+}
+
void DRW_stats_draw(rcti *rect)
{
char stat_string[64];
int lvl_index[MAX_NESTED_TIMER];
- int v = 0;
+ int v = 0, u = 0;
+
+ double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
+
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+
+ /* ------------------------------------------ */
+ /* ---------------- CPU stats --------------- */
+ /* ------------------------------------------ */
+ /* Label row */
+ char col_label[32];
+ sprintf(col_label, "Engine");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Init");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Background");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Render");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Total (w/o cache)");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ v++;
+
+ /* Engines rows */
+ char time_to_txt[16];
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ u = 0;
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname));
+
+ init_tot_time += data->init_time;
+ sprintf(time_to_txt, "%.2fms", data->init_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ background_tot_time += data->background_time;
+ sprintf(time_to_txt, "%.2fms", data->background_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ render_tot_time += data->render_time;
+ sprintf(time_to_txt, "%.2fms", data->render_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ tot_time += data->init_time + data->background_time + data->render_time;
+ sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v++;
+ }
- BLI_snprintf(stat_string, sizeof(stat_string), "GPU Render Stats");
- BLF_draw_default_ascii(rect->xmin + 1 * U.widget_unit, rect->ymax - v++ * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ /* Totals row */
+ u = 0;
+ sprintf(col_label, "Sub Total");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(time_to_txt, "%.2fms", init_tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", background_tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", render_tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v += 2;
+
+ u = 0;
+ double *cache_time = GPU_viewport_cache_time_get(DST.viewport);
+ sprintf(col_label, "Cache Time");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(time_to_txt, "%.2fms", *cache_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v += 2;
+
+ /* ------------------------------------------ */
+ /* ---------------- GPU stats --------------- */
+ /* ------------------------------------------ */
+
+ /* Memory Stats */
+ unsigned int tex_mem = GPU_texture_memory_usage_get();
+ unsigned int vbo_mem = GWN_vertbuf_get_memory_usage();
+
+ sprintf(stat_string, "GPU Memory");
+ draw_stat(rect, 0, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (double)(tex_mem + vbo_mem) / 1000000.0);
+ draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "Textures");
+ draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (double)tex_mem / 1000000.0);
+ draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "Meshes");
+ draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (double)vbo_mem / 1000000.0);
+ draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
+ v += 1;
+
+ /* GPU Timings */
+ BLI_snprintf(stat_string, sizeof(stat_string), "GPU Render Timings");
+ draw_stat(rect, 0, v++, stat_string, sizeof(stat_string));
for (int i = 0; i < DTP.timer_increment; ++i) {
double time_ms, time_percent;
@@ -232,11 +344,11 @@ void DRW_stats_draw(rcti *rect)
time_percent = MIN2(time_percent, 100.0);
BLI_snprintf(stat_string, sizeof(stat_string), "%s", timer->name);
- BLF_draw_default_ascii(rect->xmin + (1 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ draw_stat(rect, 0 + timer->lvl, v, stat_string, sizeof(stat_string));
BLI_snprintf(stat_string, sizeof(stat_string), "%.2fms", time_ms);
- BLF_draw_default_ascii(rect->xmin + (13 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ draw_stat(rect, 12 + timer->lvl, v, stat_string, sizeof(stat_string));
BLI_snprintf(stat_string, sizeof(stat_string), "%.0f", time_percent);
- BLF_draw_default_ascii(rect->xmin + (17 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ draw_stat(rect, 16 + timer->lvl, v, stat_string, sizeof(stat_string));
v++;
}
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
new file mode 100644
index 00000000000..d150bcc8d56
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -0,0 +1,377 @@
+/*
+ * 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_manager_shader.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#include "DNA_world_types.h"
+#include "DNA_material_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLI_task.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "GPU_shader.h"
+#include "GPU_material.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+extern char datatoc_gpu_shader_2D_vert_glsl[];
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Deferred Compilation (DRW_deferred)
+ *
+ * Since compiling shader can take a long time, we do it in a non blocking
+ * manner in another thread.
+ *
+ * \{ */
+
+typedef struct DRWDeferredShader {
+ struct DRWDeferredShader *prev, *next;
+
+ GPUMaterial *mat;
+ char *vert, *geom, *frag, *defs;
+} DRWDeferredShader;
+
+typedef struct DRWShaderCompiler {
+ ListBase queue; /* DRWDeferredShader */
+ SpinLock list_lock;
+
+ DRWDeferredShader *mat_compiling;
+ ThreadMutex compilation_lock;
+
+ void *ogl_context;
+
+ int shaders_done; /* To compute progress. */
+} DRWShaderCompiler;
+
+static void drw_deferred_shader_free(DRWDeferredShader *dsh)
+{
+ /* Make sure it is not queued before freeing. */
+ MEM_SAFE_FREE(dsh->vert);
+ MEM_SAFE_FREE(dsh->geom);
+ MEM_SAFE_FREE(dsh->frag);
+ MEM_SAFE_FREE(dsh->defs);
+
+ MEM_freeN(dsh);
+}
+
+static void drw_deferred_shader_queue_free(ListBase *queue)
+{
+ DRWDeferredShader *dsh;
+ while((dsh = BLI_pophead(queue))) {
+ drw_deferred_shader_free(dsh);
+ }
+}
+
+static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop, short *do_update, float *progress)
+{
+ DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
+
+ WM_opengl_context_activate(comp->ogl_context);
+
+ while (true) {
+ BLI_spin_lock(&comp->list_lock);
+
+ if (*stop != 0) {
+ /* We don't want user to be able to cancel the compilation
+ * but wm can kill the task if we are closing blender. */
+ BLI_spin_unlock(&comp->list_lock);
+ break;
+ }
+
+ /* Pop tail because it will be less likely to lock the main thread
+ * if all GPUMaterials are to be freed (see DRW_deferred_shader_remove()). */
+ comp->mat_compiling = BLI_poptail(&comp->queue);
+ if (comp->mat_compiling == NULL) {
+ /* No more Shader to compile. */
+ BLI_spin_unlock(&comp->list_lock);
+ break;
+ }
+
+ comp->shaders_done++;
+ int total = BLI_listbase_count(&comp->queue) + comp->shaders_done;
+
+ BLI_mutex_lock(&comp->compilation_lock);
+ BLI_spin_unlock(&comp->list_lock);
+
+ /* Do the compilation. */
+ GPU_material_generate_pass(
+ comp->mat_compiling->mat,
+ comp->mat_compiling->vert,
+ comp->mat_compiling->geom,
+ comp->mat_compiling->frag,
+ comp->mat_compiling->defs);
+
+ *progress = (float)comp->shaders_done / (float)total;
+ *do_update = true;
+
+ BLI_mutex_unlock(&comp->compilation_lock);
+
+ drw_deferred_shader_free(comp->mat_compiling);
+ }
+
+ WM_opengl_context_release(comp->ogl_context);
+}
+
+static void drw_deferred_shader_compilation_free(void *custom_data)
+{
+ DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
+
+ drw_deferred_shader_queue_free(&comp->queue);
+
+ BLI_spin_end(&comp->list_lock);
+ BLI_mutex_end(&comp->compilation_lock);
+
+ WM_opengl_context_dispose(comp->ogl_context);
+
+ MEM_freeN(comp);
+}
+
+static void drw_deferred_shader_add(
+ GPUMaterial *mat, const char *vert, const char *geom, const char *frag_lib, const char *defines)
+{
+ /* Do not deferre the compilation if we are rendering for image. */
+ if (DRW_state_is_image_render()) {
+ /* Double checking that this GPUMaterial is not going to be
+ * compiled by another thread. */
+ DRW_deferred_shader_remove(mat);
+ GPU_material_generate_pass(mat, vert, geom, frag_lib, defines);
+ return;
+ }
+
+ DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader");
+
+ dsh->mat = mat;
+ if (vert) dsh->vert = BLI_strdup(vert);
+ if (geom) dsh->geom = BLI_strdup(geom);
+ if (frag_lib) dsh->frag = BLI_strdup(frag_lib);
+ if (defines) dsh->defs = BLI_strdup(defines);
+
+ BLI_assert(DST.draw_ctx.evil_C);
+ wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C);
+ wmWindow *win = CTX_wm_window(DST.draw_ctx.evil_C);
+ Scene *scene = DST.draw_ctx.scene;
+
+ /* Get the running job or a new one if none is running. Can only have one job per type & owner. */
+ wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation",
+ WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION);
+
+ DRWShaderCompiler *old_comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job);
+
+ DRWShaderCompiler *comp = MEM_callocN(sizeof(DRWShaderCompiler), "DRWShaderCompiler");
+ BLI_spin_init(&comp->list_lock);
+ BLI_mutex_init(&comp->compilation_lock);
+
+ if (old_comp) {
+ BLI_spin_lock(&old_comp->list_lock);
+ BLI_movelisttolist(&comp->queue, &old_comp->queue);
+ BLI_spin_unlock(&old_comp->list_lock);
+ }
+
+ BLI_addtail(&comp->queue, dsh);
+
+ /* Create one context per task. */
+ comp->ogl_context = WM_opengl_context_create();
+ WM_opengl_context_activate(DST.ogl_context);
+
+ WM_jobs_customdata_set(wm_job, comp, drw_deferred_shader_compilation_free);
+ WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0);
+ WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL);
+ WM_jobs_start(wm, wm_job);
+}
+
+void DRW_deferred_shader_remove(GPUMaterial *mat)
+{
+ Scene *scene = GPU_material_scene(mat);
+
+ for (wmWindowManager *wm = G.main->wm.first; wm; wm = wm->id.next) {
+ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_SHADER_COMPILATION) == false) {
+ /* No job running, do not create a new one by calling WM_jobs_get. */
+ continue;
+ }
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation",
+ WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION);
+
+ DRWShaderCompiler *comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job);
+ if (comp != NULL) {
+ BLI_spin_lock(&comp->list_lock);
+ DRWDeferredShader *dsh;
+ dsh = (DRWDeferredShader *)BLI_findptr(&comp->queue, mat, offsetof(DRWDeferredShader, mat));
+ if (dsh) {
+ BLI_remlink(&comp->queue, dsh);
+ }
+
+ /* Wait for compilation to finish */
+ if (comp->mat_compiling != NULL) {
+ if (comp->mat_compiling->mat == mat) {
+ BLI_mutex_lock(&comp->compilation_lock);
+ BLI_mutex_unlock(&comp->compilation_lock);
+ }
+ }
+ BLI_spin_unlock(&comp->list_lock);
+
+ if (dsh) {
+ drw_deferred_shader_free(dsh);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines)
+{
+ return GPU_shader_create(vert, frag, geom, NULL, defines);
+}
+
+GPUShader *DRW_shader_create_with_lib(
+ const char *vert, const char *geom, const char *frag, const char *lib, const char *defines)
+{
+ GPUShader *sh;
+ char *vert_with_lib = NULL;
+ char *frag_with_lib = NULL;
+ char *geom_with_lib = NULL;
+
+ vert_with_lib = BLI_string_joinN(lib, vert);
+ frag_with_lib = BLI_string_joinN(lib, frag);
+ if (geom) {
+ geom_with_lib = BLI_string_joinN(lib, geom);
+ }
+
+ sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines);
+
+ MEM_freeN(vert_with_lib);
+ MEM_freeN(frag_with_lib);
+ if (geom) {
+ MEM_freeN(geom_with_lib);
+ }
+
+ return sh;
+}
+
+GPUShader *DRW_shader_create_2D(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines);
+}
+
+GPUShader *DRW_shader_create_3D(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines);
+}
+
+GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, frag, NULL, NULL, defines);
+}
+
+GPUShader *DRW_shader_create_3D_depth_only(void)
+{
+ return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
+}
+
+GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options)
+{
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
+ if (DRW_state_is_image_render()) {
+ if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
+ * with the shader code and we will resume the compilation from there. */
+ return NULL;
+ }
+ }
+ return mat;
+}
+
+GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options)
+{
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
+ if (DRW_state_is_image_render()) {
+ if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
+ * with the shader code and we will resume the compilation from there. */
+ return NULL;
+ }
+ }
+ return mat;
+}
+
+GPUMaterial *DRW_shader_create_from_world(
+ struct Scene *scene, World *wo, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines)
+{
+ GPUMaterial *mat = NULL;
+ if (DRW_state_is_image_render()) {
+ mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
+ }
+
+ if (mat == NULL) {
+ mat = GPU_material_from_nodetree(
+ scene, wo->nodetree, &wo->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines, true);
+ }
+
+ drw_deferred_shader_add(mat, vert, geom, frag_lib, defines);
+
+ return mat;
+}
+
+GPUMaterial *DRW_shader_create_from_material(
+ struct Scene *scene, Material *ma, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines)
+{
+ GPUMaterial *mat = NULL;
+ if (DRW_state_is_image_render()) {
+ mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
+ }
+
+ if (mat == NULL) {
+ mat = GPU_material_from_nodetree(
+ scene, ma->nodetree, &ma->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines, true);
+ }
+
+ drw_deferred_shader_add(mat, vert, geom, frag_lib, defines);
+
+ return mat;
+}
+
+void DRW_shader_free(GPUShader *shader)
+{
+ GPU_shader_free(shader);
+}
diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c
new file mode 100644
index 00000000000..e033a0c506e
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_texture.c
@@ -0,0 +1,215 @@
+/*
+ * 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_manager_texture.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+void drw_texture_get_format(
+ DRWTextureFormat format, bool is_framebuffer,
+ GPUTextureFormat *r_data_type, int *r_channels, bool *r_is_depth)
+{
+ /* Some formats do not work with framebuffers. */
+ if (is_framebuffer) {
+ switch (format) {
+ /* Only add formats that are COMPATIBLE with FB.
+ * Generally they are multiple of 16bit. */
+ case DRW_TEX_R_16:
+ case DRW_TEX_R_16I:
+ case DRW_TEX_R_32:
+ case DRW_TEX_RG_8:
+ case DRW_TEX_RG_16:
+ case DRW_TEX_RG_16I:
+ case DRW_TEX_RG_32:
+ case DRW_TEX_RGBA_8:
+ case DRW_TEX_RGBA_16:
+ case DRW_TEX_RGBA_32:
+ case DRW_TEX_DEPTH_16:
+ case DRW_TEX_DEPTH_24:
+ case DRW_TEX_DEPTH_24_STENCIL_8:
+ case DRW_TEX_DEPTH_32:
+ case DRW_TEX_RGB_11_11_10:
+ break;
+ default:
+ BLI_assert(false && "Texture format unsupported as render target!");
+ *r_channels = 4;
+ *r_data_type = GPU_RGBA8;
+ *r_is_depth = false;
+ return;
+ }
+ }
+
+ switch (format) {
+ case DRW_TEX_RGBA_8: *r_data_type = GPU_RGBA8; break;
+ case DRW_TEX_RGBA_16: *r_data_type = GPU_RGBA16F; break;
+ case DRW_TEX_RGBA_32: *r_data_type = GPU_RGBA32F; break;
+ case DRW_TEX_RGB_16: *r_data_type = GPU_RGB16F; break;
+ 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;
+ case DRW_TEX_R_16I: *r_data_type = GPU_R16I; break;
+ case DRW_TEX_R_32: *r_data_type = GPU_R32F; break;
+#if 0
+ case DRW_TEX_RGB_8: *r_data_type = GPU_RGB8; break;
+ case DRW_TEX_RGB_32: *r_data_type = GPU_RGB32F; break;
+#endif
+ case DRW_TEX_DEPTH_16: *r_data_type = GPU_DEPTH_COMPONENT16; break;
+ case DRW_TEX_DEPTH_24: *r_data_type = GPU_DEPTH_COMPONENT24; break;
+ case DRW_TEX_DEPTH_24_STENCIL_8: *r_data_type = GPU_DEPTH24_STENCIL8; break;
+ case DRW_TEX_DEPTH_32: *r_data_type = GPU_DEPTH_COMPONENT32F; break;
+ default :
+ /* file type not supported you must uncomment it from above */
+ BLI_assert(false);
+ break;
+ }
+
+ switch (format) {
+ case DRW_TEX_RGBA_8:
+ case DRW_TEX_RGBA_16:
+ case DRW_TEX_RGBA_32:
+ *r_channels = 4;
+ break;
+ case DRW_TEX_RGB_8:
+ case DRW_TEX_RGB_16:
+ case DRW_TEX_RGB_32:
+ case DRW_TEX_RGB_11_11_10:
+ *r_channels = 3;
+ 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;
+ default:
+ *r_channels = 1;
+ break;
+ }
+
+ if (r_is_depth) {
+ *r_is_depth = ELEM(format, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24, DRW_TEX_DEPTH_24_STENCIL_8);
+ }
+}
+
+void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags)
+{
+ GPU_texture_bind(tex, 0);
+ if (flags & DRW_TEX_MIPMAP) {
+ GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER);
+ DRW_texture_generate_mipmaps(tex);
+ }
+ else {
+ GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER);
+ }
+ GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP);
+ GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE);
+ GPU_texture_unbind(tex);
+}
+
+GPUTexture *DRW_texture_create_1D(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, false, &data_type, &channels, NULL);
+ tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, false, &data_type, &channels, NULL);
+ tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_2D_array(
+ int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, false, &data_type, &channels, NULL);
+ tex = GPU_texture_create_2D_array_custom(w, h, d, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_3D(
+ int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, false, &data_type, &channels, NULL);
+ tex = GPU_texture_create_3D_custom(w, h, d, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_cube(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, false, &data_type, &channels, NULL);
+ tex = GPU_texture_create_cube_custom(w, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+void DRW_texture_generate_mipmaps(GPUTexture *tex)
+{
+ GPU_texture_bind(tex, 0);
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_unbind(tex);
+}
+
+void DRW_texture_update(GPUTexture *tex, const float *pixels)
+{
+ GPU_texture_update(tex, pixels);
+}
+
+void DRW_texture_free(GPUTexture *tex)
+{
+ GPU_texture_free(tex);
+}
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 4a7a5d25b11..ded2bc68062 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -214,10 +214,19 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *wire_select;
DRWShadingGroup *wire_select_group;
DRWShadingGroup *wire_transform;
+
+ /* Points */
+ DRWShadingGroup *points;
+ DRWShadingGroup *points_active;
+ DRWShadingGroup *points_active_group;
+ DRWShadingGroup *points_select;
+ DRWShadingGroup *points_select_group;
+ DRWShadingGroup *points_transform;
} OBJECT_PrivateData; /* Transient data */
static struct {
/* Instance Data format */
+ struct Gwn_VertFormat *particle_format;
struct Gwn_VertFormat *empty_image_format;
struct Gwn_VertFormat *empty_image_wire_format;
@@ -537,6 +546,7 @@ static void OBJECT_engine_init(void *vedata)
static void OBJECT_engine_free(void)
{
+ MEM_SAFE_FREE(e_data.particle_format);
MEM_SAFE_FREE(e_data.empty_image_format);
MEM_SAFE_FREE(e_data.empty_image_wire_format);
DRW_SHADER_FREE_SAFE(e_data.outline_resolve_sh);
@@ -569,6 +579,15 @@ static DRWShadingGroup *shgroup_wire(DRWPass *pass, const float col[4], GPUShade
return grp;
}
+/* currently same as 'shgroup_outline', new function to avoid confustion */
+static DRWShadingGroup *shgroup_points(DRWPass *pass, const float col[4], GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", col, 1);
+
+ return grp;
+}
+
static DRWShadingGroup *shgroup_theme_id_to_outline_or(
OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
{
@@ -603,6 +622,23 @@ static DRWShadingGroup *shgroup_theme_id_to_wire_or(
}
}
+static DRWShadingGroup *shgroup_theme_id_to_point_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->points_active;
+ case TH_SELECT:
+ return stl->g_data->points_select;
+ case TH_GROUP_ACTIVE:
+ return stl->g_data->points_select_group;
+ case TH_TRANSFORM:
+ return stl->g_data->points_transform;
+ default:
+ return fallback;
+ }
+}
+
static void image_calc_aspect(Image *ima, ImageUser *iuser, float r_image_aspect[2])
{
float ima_x, ima_y;
@@ -979,6 +1015,25 @@ static void OBJECT_cache_init(void *vedata)
stl->g_data->wire_active_group = shgroup_wire(psl->non_meshes, ts.colorGroupActive, sh);
}
+
+ {
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+
+ /* Unselected */
+ stl->g_data->points = shgroup_points(psl->non_meshes, ts.colorWire, sh);
+
+ /* Select */
+ stl->g_data->points_select = shgroup_points(psl->non_meshes, ts.colorSelect, sh);
+ stl->g_data->points_select_group = shgroup_points(psl->non_meshes, ts.colorGroupActive, sh);
+
+ /* Transform */
+ stl->g_data->points_transform = shgroup_points(psl->non_meshes, ts.colorTransform, sh);
+
+ /* Active */
+ stl->g_data->points_active = shgroup_points(psl->non_meshes, ts.colorActive, sh);
+ stl->g_data->points_active_group = shgroup_points(psl->non_meshes, ts.colorGroupActive, sh);
+ }
+
{
/* Metaballs Handles */
struct Gwn_Batch *geom;
@@ -1492,6 +1547,7 @@ typedef struct OBJECT_LightProbeEngineData {
float increment_y[3];
float increment_z[3];
float corner[3];
+ unsigned int cell_count;
} OBJECT_LightProbeEngineData;
static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, ViewLayer *view_layer)
@@ -1545,9 +1601,8 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
mul_m4_v3(ob->obmat, prb_data->increment_z);
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(), NULL);
- DRW_shgroup_set_instance_count(grp, prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z);
+ prb_data->cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.lightprobe_grid_sh, psl->lightprobes);
DRW_shgroup_uniform_vec4(grp, "color", color, 1);
DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
@@ -1555,6 +1610,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
DRW_shgroup_uniform_float(grp, "sphere_size", &prb->data_draw_size, 1);
+ DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, &prb_data->cell_count);
}
else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
prb_data->draw_size = prb->data_draw_size * 0.1f;
@@ -1752,6 +1808,9 @@ static void OBJECT_cache_populate_particles(Object *ob,
static float def_prim_col[3] = {0.5f, 0.5f, 0.5f};
static float def_sec_col[3] = {1.0f, 1.0f, 1.0f};
+ /* Dummy particle format for instancing to work. */
+ DRW_shgroup_instance_format(e_data.particle_format, {{"dummy", DRW_ATTRIB_FLOAT, 1}});
+
Material *ma = give_current_material(ob, part->omat);
switch (draw_as) {
@@ -1766,21 +1825,24 @@ static void OBJECT_cache_populate_particles(Object *ob,
break;
case PART_DRAW_CROSS:
shgrp = DRW_shgroup_instance_create(
- e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CROSS), NULL);
+ e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CROSS),
+ e_data.particle_format);
DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1);
break;
case PART_DRAW_CIRC:
shgrp = DRW_shgroup_instance_create(
- e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CIRC), NULL);
+ e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CIRC),
+ e_data.particle_format);
DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[1], 1);
break;
case PART_DRAW_AXIS:
shgrp = DRW_shgroup_instance_create(
- e_data.part_axis_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_AXIS), NULL);
+ e_data.part_axis_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_AXIS),
+ e_data.particle_format);
DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1);
break;
default:
@@ -1828,7 +1890,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or(stl, theme_id, NULL);
if (shgroup != NULL) {
- DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
}
}
}
@@ -1837,17 +1899,30 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
switch (ob->type) {
case OB_MESH:
{
- Mesh *me = ob->data;
- if (me->totpoly == 0) {
- if (ob != draw_ctx->object_edit) {
- struct Gwn_Batch *geom = DRW_cache_mesh_edges_get(ob);
- if (geom) {
- if (theme_id == TH_UNDEFINED) {
- theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ if (ob != draw_ctx->object_edit) {
+ Mesh *me = ob->data;
+ if (me->totpoly == 0) {
+ if (me->totedge == 0) {
+ struct Gwn_Batch *geom = DRW_cache_mesh_verts_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_point_or(stl, theme_id, stl->g_data->points);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ else {
+ struct Gwn_Batch *geom = DRW_cache_mesh_edges_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
}
-
- DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
- DRW_shgroup_call_add(shgroup, geom, ob->obmat);
}
}
}
@@ -1864,7 +1939,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
}
DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
- DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
}
break;
}
@@ -1877,7 +1952,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
}
DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
- DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
}
break;
}
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
new file mode 100644
index 00000000000..d261d263a6f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -0,0 +1,14 @@
+/* keep in sync with DRWManager.view_data */
+layout(std140) uniform viewBlock {
+ /* Same order as DRWViewportMatrixType */
+ mat4 ViewProjectionMatrix;
+ mat4 ViewProjectionMatrixInverse;
+ mat4 ViewMatrix;
+ mat4 ViewMatrixInverse;
+ mat4 ProjectionMatrix;
+ mat4 ProjectionMatrixInverse;
+
+ vec4 CameraTexCoFactors;
+
+ vec4 clipPlanes[2];
+};
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 841d8278089..1ac8b0ca029 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -29,6 +29,7 @@ if(WITH_BLENDER)
add_subdirectory(gpencil)
add_subdirectory(interface)
add_subdirectory(io)
+ add_subdirectory(lattice)
add_subdirectory(manipulator_library)
add_subdirectory(mask)
add_subdirectory(mesh)
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index d137e5f1c74..2f9d32eadb6 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3090,7 +3090,7 @@ static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool e
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu_inner = (FCurve *)ale->key_data;
- if (fcu_inner) {
+ if (fcu_inner != NULL && fcu_inner->bezt != NULL) {
for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
bezt->f2 = bezt->f1 = bezt->f3 = 0;
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index bc901d7e13f..85bcfb603cd 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -116,7 +116,7 @@ static void animedit_get_yscale_factor(bAnimContext *ac)
/* grab scale factor directly from action editor setting
* NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally
- * since it is a float, and the theem settings methods can only handle chars.
+ * since it is a float, and the theme settings methods can only handle chars.
*/
ac->yscale_fac = btheme->tact.keyframe_scale_fac;
@@ -880,6 +880,7 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE. Differences are applied post-creation */
{
FCurve *fcu = (FCurve *)data;
@@ -1089,13 +1090,14 @@ static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name)
/* (Display-)Name-based F-Curve filtering
* NOTE: when this function returns true, the F-Curve is to be skipped
*/
-static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
+static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id)
{
bAnimListElem ale_dummy = {NULL};
const bAnimChannelType *acf;
- /* create a dummy wrapper for the F-Curve */
- ale_dummy.type = ANIMTYPE_FCURVE;
+ /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */
+ ale_dummy.type = channel_type;
+ ale_dummy.owner = owner;
ale_dummy.id = owner_id;
ale_dummy.data = fcu;
@@ -1158,8 +1160,9 @@ static bool fcurve_has_errors(FCurve *fcu)
}
/* find the next F-Curve that is usable for inclusion */
-static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
+static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, eAnim_ChannelType channel_type, int filter_mode, void *owner, ID *owner_id)
{
+ bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? owner : NULL;
FCurve *fcu = NULL;
/* loop over F-Curves - assume that the caller of this has already checked that these should be included
@@ -1193,7 +1196,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro
if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
/* name based filtering... */
if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) {
- if (skip_fcurve_with_name(ads, fcu, owner_id))
+ if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id))
continue;
}
@@ -1216,7 +1219,10 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro
return NULL;
}
-static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
+static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads,
+ FCurve *first, eAnim_ChannelType fcurve_type,
+ int filter_mode,
+ void *owner, ID *owner_id)
{
FCurve *fcu;
size_t items = 0;
@@ -1230,8 +1236,18 @@ static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads, FCurve *f
* 4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through
* the rest of the F-Curve list without an eternal loop. Back to step 2 :)
*/
- for (fcu = first; ( (fcu = animfilter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu = fcu->next) {
- ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id);
+ for (fcu = first; ( (fcu = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id)) ); fcu = fcu->next) {
+ if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) {
+ /* NLA Control Curve - Basically the same as normal F-Curves, except we need to set some stuff differently */
+ ANIMCHANNEL_NEW_CHANNEL_FULL(fcu, ANIMTYPE_NLACURVE, owner_id, {
+ ale->owner = owner; /* strip */
+ ale->adt = NULL; /* to prevent time mapping from causing problems */
+ });
+ }
+ else {
+ /* Normal FCurve */
+ ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id);
+ }
}
/* return the number of items added to the list */
@@ -1282,10 +1298,10 @@ static size_t animfilter_act_group(bAnimContext *ac, ListBase *anim_data, bDopeS
/* group must be editable for its children to be editable (if we care about this) */
if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
/* get first F-Curve which can be used here */
- FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id);
+ FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id);
/* filter list, starting from this F-Curve */
- tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, agrp, filter_mode, owner_id);
+ tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id);
}
}
}
@@ -1341,7 +1357,7 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee
/* un-grouped F-Curves (only if we're not only considering those channels in the active group) */
if (!(filter_mode & ANIMFILTER_ACTGROUPED)) {
FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first);
- items += animfilter_fcurves(anim_data, ads, firstfcu, NULL, filter_mode, owner_id);
+ items += animfilter_fcurves(anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id);
}
/* return the number of items added to the list */
@@ -1463,36 +1479,8 @@ static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, Anim
/* for now, we only go one level deep - so controls on grouped FCurves are not handled */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
for (strip = nlt->strips.first; strip; strip = strip->next) {
- ListBase strip_curves = {NULL, NULL};
- size_t strip_items = 0;
-
- /* create the raw items */
- strip_items += animfilter_fcurves(&strip_curves, ads, strip->fcurves.first, NULL, filter_mode, owner_id);
-
- /* change their types and add extra data
- * - There is no point making a separate copy of animfilter_fcurves for this now/yet,
- * unless we later get per-element control curves for other stuff too
- */
- if (strip_items) {
- bAnimListElem *ale, *ale_n = NULL;
-
- for (ale = strip_curves.first; ale; ale = ale_n) {
- ale_n = ale->next;
-
- /* change the type to being a FCurve for editing NLA strip controls */
- BLI_assert(ale->type == ANIMTYPE_FCURVE);
-
- ale->type = ANIMTYPE_NLACURVE;
- ale->owner = strip;
-
- ale->adt = NULL; /* XXX: This way, there are no problems with time mapping errors */
- }
- }
-
- /* add strip curves to the set of channels inside the group being collected */
- BLI_movelisttolist(&tmp_data, &strip_curves);
- BLI_assert(BLI_listbase_is_empty(&strip_curves));
- tmp_items += strip_items;
+ /* pass strip as the "owner", so that the name lookups (used while filtering) will resolve */
+ tmp_items += animfilter_fcurves(&tmp_data, ads, strip->fcurves.first, ANIMTYPE_NLACURVE, filter_mode, strip, owner_id);
}
}
}
@@ -1543,7 +1531,7 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
},
{ /* Drivers */
- items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
+ items += animfilter_fcurves(anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, filter_mode, NULL, id);
},
{ /* NLA Control Keyframes */
items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 6df0a1cd302..4ed5c49c1e3 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1358,7 +1358,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
* updated since the last switching to the edit mode will be keyframed correctly
*/
if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) {
- ED_object_toggle_modes(C, OB_MODE_EDIT);
+ ED_object_mode_toggle(C, OB_MODE_EDIT);
ob_edit_mode = true;
}
@@ -1369,7 +1369,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
/* restore the edit mode if necessary */
if (ob_edit_mode) {
- ED_object_toggle_modes(C, OB_MODE_EDIT);
+ ED_object_mode_toggle(C, OB_MODE_EDIT);
}
/* report failure or do updates? */
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 5348298f57e..4301fe6582f 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
editarmature_generate.c
editarmature_retarget.c
editarmature_sketch.c
+ editarmature_undo.c
meshlaplacian.c
pose_edit.c
pose_lib.c
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 368d54fc3ad..48436a979a2 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -472,7 +472,7 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb
return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
}
-static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
+static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
{
bArmature *arm;
EditBone *ebone_iter;
@@ -484,7 +484,9 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0)
return OPERATOR_CANCELLED;
-
+
+ const bool do_flip_names = RNA_boolean_get(op->ptr, "do_flip_names");
+
ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
preEditBoneDuplicate(arm->edbo);
@@ -512,8 +514,20 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
(ebone_iter->flag & BONE_SELECTED))
{
EditBone *ebone;
+ char new_bone_name_buff[MAXBONENAME];
+ char *new_bone_name = ebone_iter->name;
+
+ if (do_flip_names) {
+ BLI_string_flip_side_name(new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
- ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit);
+ /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
+ * (different numbers), better keep default behavior in this case. */
+ if (ED_armature_bone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
+ new_bone_name = new_bone_name_buff;
+ }
+ }
+
+ ebone = duplicateEditBone(ebone_iter, new_bone_name, arm->edbo, obedit);
if (!ebone_first_dupe) {
ebone_first_dupe = ebone;
@@ -590,6 +604,10 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(
+ ot->srna, "do_flip_names", false,
+ "Flip Names", "Try to flip names of the bones, if possible, instead of adding a number extension");
}
/**
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 0d114206c6b..52e9e424a85 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -314,8 +314,9 @@ typedef struct BoneFlipNameData {
*
* \param arm: Armature the bones belong to
* \param bones_names: List of BoneConflict elems.
+ * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
*/
-void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
+void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const bool do_strip_numbers)
{
ListBase bones_names_conflicts = {NULL};
BoneFlipNameData *bfn;
@@ -327,9 +328,9 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
char name_flip[MAXBONENAME];
char *name = link->data;
- /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like
+ /* WARNING: if do_strip_numbers is set, expect completely mismatched names in cases like
* Bone.R, Bone.R.001, Bone.R.002, etc. */
- BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
+ BLI_string_flip_side_name(name_flip, name, do_strip_numbers, sizeof(name_flip));
ED_armature_bone_rename(arm, name, name_flip);
@@ -352,7 +353,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
/* ************************************************** */
/* Bone Renaming - EditMode */
-static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
+static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
@@ -361,6 +362,8 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+ const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
+
arm = ob->data;
ListBase bones_names = {NULL};
@@ -371,7 +374,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
}
CTX_DATA_END;
- ED_armature_bones_flip_names(arm, &bones_names);
+ ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers);
BLI_freelistN(&bones_names);
@@ -401,6 +404,10 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "do_strip_numbers", false, "Strip Numbers",
+ "Try to remove right-most dot-number from flipped names "
+ "(WARNING: may result in incoherent naming in some cases)");
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index f178ad640b6..397691a409b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -174,7 +174,7 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
short hits;
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
// rect.xmin = ... mouseco!
rect.xmin = rect.xmax = xy[0];
@@ -491,7 +491,7 @@ bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool d
int selmask;
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (BIF_sk_selectStroke(C, mval, extend)) {
return true;
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index f27c4fdd96f..23a49d282e1 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -711,11 +711,11 @@ void ED_armature_to_edit(bArmature *arm)
}
/* *************************************************************** */
-/* Undo for Armature EditMode*/
+/* Used by Undo for Armature EditMode*/
/* free's bones and their properties */
-static void ED_armature_ebone_listbase_free(ListBase *lb)
+void ED_armature_ebone_listbase_free(ListBase *lb)
{
EditBone *ebone, *ebone_next;
@@ -733,7 +733,7 @@ static void ED_armature_ebone_listbase_free(ListBase *lb)
BLI_listbase_clear(lb);
}
-static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
+void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
{
EditBone *ebone_src;
EditBone *ebone_dst;
@@ -766,78 +766,6 @@ void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
}
}
-typedef struct UndoArmature {
- EditBone *act_edbone;
- ListBase lb;
-} UndoArmature;
-
-static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
-{
- UndoArmature *uarm = uarmv;
- bArmature *arm = armv;
- EditBone *ebone;
-
- ED_armature_ebone_listbase_free(arm->edbo);
- ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb);
-
- /* active bone */
- if (uarm->act_edbone) {
- ebone = uarm->act_edbone;
- arm->act_edbone = ebone->temp.ebone;
- }
- else {
- arm->act_edbone = NULL;
- }
-
- ED_armature_ebone_listbase_temp_clear(arm->edbo);
-}
-
-static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
-{
- bArmature *arm = armv;
- UndoArmature *uarm;
- EditBone *ebone;
-
- uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
-
- ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo);
-
- /* active bone */
- if (arm->act_edbone) {
- ebone = arm->act_edbone;
- uarm->act_edbone = ebone->temp.ebone;
- }
-
- ED_armature_ebone_listbase_temp_clear(&uarm->lb);
-
- return uarm;
-}
-
-static void free_undoBones(void *uarmv)
-{
- UndoArmature *uarm = uarmv;
-
- ED_armature_ebone_listbase_free(&uarm->lb);
-
- MEM_freeN(uarm);
-}
-
-static void *get_armature_edit(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_ARMATURE) {
- return obedit->data;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_armature(bContext *C, const char *name)
-{
- // XXX solve getdata()
- undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
-}
-
/* *************************************************************** */
/* Low level selection functions which hide connected-parent
* flag behavior which gets tricky to handle in selection operators.
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index c91f92bc70b..dcf4c9a0e9c 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -158,7 +158,7 @@ void BIF_makeListTemplates(const bContext *C)
TEMPLATES_HASH = BLI_ghash_int_new("makeListTemplates gh");
TEMPLATES_CURRENT = 0;
- FOREACH_OBJECT(view_layer, ob)
+ FOREACH_OBJECT_BEGIN(view_layer, ob)
{
if (ob != obedit && ob->type == OB_ARMATURE) {
index++;
@@ -169,7 +169,7 @@ void BIF_makeListTemplates(const bContext *C)
}
}
}
- FOREACH_OBJECT_END
+ FOREACH_OBJECT_END;
}
#if 0 /* UNUSED */
@@ -1932,7 +1932,7 @@ static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], c
short hits;
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
BLI_rcti_init_pt_radius(&rect, mval, 5);
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
new file mode 100644
index 00000000000..36e6ec4ba7f
--- /dev/null
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -0,0 +1,112 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/editarmature_undo.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "ED_armature.h"
+#include "ED_util.h"
+
+typedef struct UndoArmature {
+ EditBone *act_edbone;
+ ListBase lb;
+} UndoArmature;
+
+static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
+{
+ UndoArmature *uarm = uarmv;
+ bArmature *arm = armv;
+ EditBone *ebone;
+
+ ED_armature_ebone_listbase_free(arm->edbo);
+ ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb);
+
+ /* active bone */
+ if (uarm->act_edbone) {
+ ebone = uarm->act_edbone;
+ arm->act_edbone = ebone->temp.ebone;
+ }
+ else {
+ arm->act_edbone = NULL;
+ }
+
+ ED_armature_ebone_listbase_temp_clear(arm->edbo);
+}
+
+static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
+{
+ bArmature *arm = armv;
+ UndoArmature *uarm;
+ EditBone *ebone;
+
+ uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
+
+ ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo);
+
+ /* active bone */
+ if (arm->act_edbone) {
+ ebone = arm->act_edbone;
+ uarm->act_edbone = ebone->temp.ebone;
+ }
+
+ ED_armature_ebone_listbase_temp_clear(&uarm->lb);
+
+ return uarm;
+}
+
+static void free_undoBones(void *uarmv)
+{
+ UndoArmature *uarm = uarmv;
+
+ ED_armature_ebone_listbase_free(&uarm->lb);
+
+ MEM_freeN(uarm);
+}
+
+static void *get_armature_edit(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_ARMATURE) {
+ return obedit->data;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_armature(bContext *C, const char *name)
+{
+ // XXX solve getdata()
+ undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+}
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 119a27cd4a7..3f2cf6f5853 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -109,7 +109,7 @@ void ED_armature_enter_posemode(bContext *C, Base *base)
}
/* XXX: disabled as this would otherwise cause a nasty loop... */
- //ED_object_toggle_modes(C, ob->mode);
+ //ED_object_mode_toggle(C, ob->mode);
}
void ED_armature_exit_posemode(bContext *C, Base *base)
@@ -601,7 +601,7 @@ static void pose_copy_menu(Scene *scene)
/* ********************************************** */
-static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
+static int pose_flip_names_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm;
@@ -610,6 +610,8 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+ const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
+
arm = ob->data;
ListBase bones_names = {NULL};
@@ -620,7 +622,7 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
}
CTX_DATA_END;
- ED_armature_bones_flip_names(arm, &bones_names);
+ ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers);
BLI_freelistN(&bones_names);
@@ -646,6 +648,10 @@ void POSE_OT_flip_names(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "do_strip_numbers", false, "Strip Numbers",
+ "Try to remove right-most dot-number from flipped names "
+ "(WARNING: may result in incoherent naming in some cases)");
}
/* ------------------ */
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index d89b2fcfe84..54c40621a14 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -834,7 +834,6 @@ typedef struct tPoseLib_PreviewData {
bAction *act; /* poselib to use */
TimeMarker *marker; /* 'active' pose */
- int selcount; /* number of selected elements to work on */
int totcount; /* total number of elements to work on */
short state; /* state of main loop */
@@ -867,7 +866,8 @@ enum {
/* defines for tPoseLib_PreviewData->flag values */
enum {
PL_PREVIEW_FIRSTTIME = (1 << 0),
- PL_PREVIEW_SHOWORIGINAL = (1 << 1)
+ PL_PREVIEW_SHOWORIGINAL = (1 << 1),
+ PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2),
};
/* ---------------------------- */
@@ -887,7 +887,20 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
{
bActionGroup *agrp;
bPoseChannel *pchan;
-
+ bool selected = false;
+
+ /* determine whether any bone is selected. */
+ LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) {
+ selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED;
+ if (selected) {
+ pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED;
+ break;
+ }
+ }
+ if (!selected) {
+ pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED;
+ }
+
/* for each posechannel that has an actionchannel in */
for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
/* try to find posechannel */
@@ -909,8 +922,6 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
BLI_addtail(&pld->backups, plb);
/* mark as being affected */
- if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
- pld->selcount++;
pld->totcount++;
}
}
@@ -971,6 +982,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
KeyframeEditData ked = {{NULL}};
KeyframeEditFunc group_ok_cb;
int frame = 1;
+ const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
/* get the frame */
if (pld->marker)
@@ -983,8 +995,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
ked.f1 = ((float)frame) - 0.5f;
ked.f2 = ((float)frame) + 0.5f;
-
-
+
/* start applying - only those channels which have a key at this point in time! */
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
/* check if group has any keyframes */
@@ -996,7 +1007,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
bool ok = 0;
/* check if this bone should get any animation applied */
- if (pld->selcount == 0) {
+ if (!any_bone_selected) {
/* if no bones are selected, then any bone is ok */
ok = 1;
}
@@ -1009,7 +1020,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
ok = 1;
}
}
-
+
if (ok)
animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame);
}
@@ -1028,14 +1039,15 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
ListBase dsources = {NULL, NULL};
bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
-
+ const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
+
/* start tagging/keying */
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
/* only for selected bones unless there aren't any selected, in which case all are included */
pchan = BKE_pose_channel_find_name(pose, agrp->name);
if (pchan) {
- if ((pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
+ if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
if (autokey) {
/* add datasource override for the PoseChannel, to be used later */
ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan);
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index ae5c0a13ced..85daa7e44e5 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editcurve_add.c
editcurve_paint.c
editcurve_select.c
+ editcurve_undo.c
editfont.c
editfont_undo.c
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index bf1e22ae170..020d34f2767 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -35,6 +35,7 @@
/* internal exports only */
struct ListBase;
struct EditNurb;
+struct GHash;
struct Object;
struct wmOperatorType;
struct ViewContext;
@@ -129,6 +130,10 @@ void CURVE_OT_cyclic_toggle(struct wmOperatorType *ot);
void CURVE_OT_match_texture_space(struct wmOperatorType *ot);
+/* exported for editcurve_undo.c */
+struct GHash *ED_curve_keyindex_hash_duplicate(struct GHash *keyindex);
+void ED_curve_keyindex_update_nurb(struct EditNurb *editnurb, struct Nurb *nu, struct Nurb *newnu);
+
bool ED_curve_pick_vert(
struct ViewContext *vc, short sel, const int mval[2],
struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 94b090bff05..1787e559913 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -84,16 +84,6 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* Undo stuff */
-typedef struct {
- ListBase nubase;
- int actvert;
- GHash *undoIndex;
- ListBase fcurves, drivers;
- int actnu;
- int flag;
-} UndoCurve;
-
void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split);
static int curve_delete_segments(Object *obedit, const bool split);
@@ -346,7 +336,7 @@ static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp,
keyIndex_updateCV(editnurb, (char *)bp, (char *)newbp, count, sizeof(BPoint));
}
-static void keyIndex_updateNurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
+void ED_curve_keyindex_update_nurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
{
if (nu->bezt) {
keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu);
@@ -525,7 +515,7 @@ static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
switch_keys_direction(cu, nu);
}
-static GHash *dupli_keyIndexHash(GHash *keyindex)
+GHash *ED_curve_keyindex_hash_duplicate(GHash *keyindex)
{
GHash *gh;
GHashIterator gh_iter;
@@ -4312,7 +4302,7 @@ bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend,
short hand;
view3d_operator_needs_opengl(C);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
location[0] = mval[0];
location[1] = mval[1];
@@ -4988,7 +4978,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewContext vc;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
Curve *cu;
@@ -6202,119 +6192,6 @@ void CURVE_OT_tilt_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/****************** undo for curves ****************/
-
-static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
-{
- Curve *cu = cu_v;
- UndoCurve *undoCurve = ucu;
- ListBase *undobase = &undoCurve->nubase;
- ListBase *editbase = BKE_curve_editNurbs_get(cu);
- Nurb *nu, *newnu;
- EditNurb *editnurb = cu->editnurb;
- AnimData *ad = BKE_animdata_from_id(&cu->id);
-
- BKE_nurbList_free(editbase);
-
- if (undoCurve->undoIndex) {
- BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
- editnurb->keyindex = dupli_keyIndexHash(undoCurve->undoIndex);
- }
-
- if (ad) {
- if (ad->action) {
- free_fcurves(&ad->action->curves);
- copy_fcurves(&ad->action->curves, &undoCurve->fcurves);
- }
-
- free_fcurves(&ad->drivers);
- copy_fcurves(&ad->drivers, &undoCurve->drivers);
- }
-
- /* copy */
- for (nu = undobase->first; nu; nu = nu->next) {
- newnu = BKE_nurb_duplicate(nu);
-
- if (editnurb->keyindex) {
- keyIndex_updateNurb(editnurb, nu, newnu);
- }
-
- BLI_addtail(editbase, newnu);
- }
-
- cu->actvert = undoCurve->actvert;
- cu->actnu = undoCurve->actnu;
- cu->flag = undoCurve->flag;
- ED_curve_updateAnimPaths(cu);
-}
-
-static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v)
-{
- Curve *cu = cu_v;
- ListBase *nubase = BKE_curve_editNurbs_get(cu);
- UndoCurve *undoCurve;
- EditNurb *editnurb = cu->editnurb, tmpEditnurb;
- Nurb *nu, *newnu;
- AnimData *ad = BKE_animdata_from_id(&cu->id);
-
- undoCurve = MEM_callocN(sizeof(UndoCurve), "undoCurve");
-
- if (editnurb->keyindex) {
- undoCurve->undoIndex = dupli_keyIndexHash(editnurb->keyindex);
- tmpEditnurb.keyindex = undoCurve->undoIndex;
- }
-
- if (ad) {
- if (ad->action)
- copy_fcurves(&undoCurve->fcurves, &ad->action->curves);
-
- copy_fcurves(&undoCurve->drivers, &ad->drivers);
- }
-
- /* copy */
- for (nu = nubase->first; nu; nu = nu->next) {
- newnu = BKE_nurb_duplicate(nu);
-
- if (undoCurve->undoIndex) {
- keyIndex_updateNurb(&tmpEditnurb, nu, newnu);
- }
-
- BLI_addtail(&undoCurve->nubase, newnu);
- }
-
- undoCurve->actvert = cu->actvert;
- undoCurve->actnu = cu->actnu;
- undoCurve->flag = cu->flag;
-
- return undoCurve;
-}
-
-static void free_undoCurve(void *ucv)
-{
- UndoCurve *undoCurve = ucv;
-
- BKE_nurbList_free(&undoCurve->nubase);
-
- BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
-
- free_fcurves(&undoCurve->fcurves);
- free_fcurves(&undoCurve->drivers);
-
- MEM_freeN(undoCurve);
-}
-
-static void *get_data(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- return obedit;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_curve(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
-}
-
void ED_curve_beztcpy(EditNurb *editnurb, BezTriple *dst, BezTriple *src, int count)
{
memcpy(dst, src, count * sizeof(BezTriple));
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 169afb140fb..36eb4c6c5bc 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -608,7 +608,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
cdd->depsgraph = CTX_data_depsgraph(C);
if (is_invoke) {
- view3d_set_viewcontext(C, &cdd->vc);
+ ED_view3d_viewcontext_init(C, &cdd->vc);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
MEM_freeN(cdd);
BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 4a4b13d0d1b..673faa37f2a 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -559,7 +559,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent
const bool select = !RNA_boolean_get(op->ptr, "deselect");
view3d_operator_needs_opengl(C);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu, &bezt, &bp, NULL)) {
return OPERATOR_CANCELLED;
@@ -1677,7 +1677,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
}
view3d_operator_needs_opengl(C);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu_dst, &bezt_dst, &bp_dst, NULL)) {
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
new file mode 100644
index 00000000000..f8f96eb3bc9
--- /dev/null
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -0,0 +1,163 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editcurve_undo.c
+ * \ingroup edcurve
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_anim_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
+#include "BKE_library.h"
+#include "BKE_animsys.h"
+
+#include "ED_util.h"
+#include "ED_curve.h"
+
+#include "curve_intern.h"
+
+typedef struct {
+ ListBase nubase;
+ int actvert;
+ GHash *undoIndex;
+ ListBase fcurves, drivers;
+ int actnu;
+ int flag;
+} UndoCurve;
+
+static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
+{
+ Curve *cu = cu_v;
+ UndoCurve *undoCurve = ucu;
+ ListBase *undobase = &undoCurve->nubase;
+ ListBase *editbase = BKE_curve_editNurbs_get(cu);
+ Nurb *nu, *newnu;
+ EditNurb *editnurb = cu->editnurb;
+ AnimData *ad = BKE_animdata_from_id(&cu->id);
+
+ BKE_nurbList_free(editbase);
+
+ if (undoCurve->undoIndex) {
+ BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
+ editnurb->keyindex = ED_curve_keyindex_hash_duplicate(undoCurve->undoIndex);
+ }
+
+ if (ad) {
+ if (ad->action) {
+ free_fcurves(&ad->action->curves);
+ copy_fcurves(&ad->action->curves, &undoCurve->fcurves);
+ }
+
+ free_fcurves(&ad->drivers);
+ copy_fcurves(&ad->drivers, &undoCurve->drivers);
+ }
+
+ /* copy */
+ for (nu = undobase->first; nu; nu = nu->next) {
+ newnu = BKE_nurb_duplicate(nu);
+
+ if (editnurb->keyindex) {
+ ED_curve_keyindex_update_nurb(editnurb, nu, newnu);
+ }
+
+ BLI_addtail(editbase, newnu);
+ }
+
+ cu->actvert = undoCurve->actvert;
+ cu->actnu = undoCurve->actnu;
+ cu->flag = undoCurve->flag;
+ ED_curve_updateAnimPaths(cu);
+}
+
+static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v)
+{
+ Curve *cu = cu_v;
+ ListBase *nubase = BKE_curve_editNurbs_get(cu);
+ UndoCurve *undoCurve;
+ EditNurb *editnurb = cu->editnurb, tmpEditnurb;
+ Nurb *nu, *newnu;
+ AnimData *ad = BKE_animdata_from_id(&cu->id);
+
+ undoCurve = MEM_callocN(sizeof(UndoCurve), "undoCurve");
+
+ if (editnurb->keyindex) {
+ undoCurve->undoIndex = ED_curve_keyindex_hash_duplicate(editnurb->keyindex);
+ tmpEditnurb.keyindex = undoCurve->undoIndex;
+ }
+
+ if (ad) {
+ if (ad->action)
+ copy_fcurves(&undoCurve->fcurves, &ad->action->curves);
+
+ copy_fcurves(&undoCurve->drivers, &ad->drivers);
+ }
+
+ /* copy */
+ for (nu = nubase->first; nu; nu = nu->next) {
+ newnu = BKE_nurb_duplicate(nu);
+
+ if (undoCurve->undoIndex) {
+ ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu);
+ }
+
+ BLI_addtail(&undoCurve->nubase, newnu);
+ }
+
+ undoCurve->actvert = cu->actvert;
+ undoCurve->actnu = cu->actnu;
+ undoCurve->flag = cu->flag;
+
+ return undoCurve;
+}
+
+static void free_undoCurve(void *ucv)
+{
+ UndoCurve *undoCurve = ucv;
+
+ BKE_nurbList_free(&undoCurve->nubase);
+
+ BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
+
+ free_fcurves(&undoCurve->fcurves);
+ free_fcurves(&undoCurve->drivers);
+
+ MEM_freeN(undoCurve);
+}
+
+static void *get_data(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ return obedit;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_curve(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
+}
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index cbb5abf1309..b72ac8c63c8 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1857,7 +1857,7 @@ bool ED_curve_editfont_select_pick(bContext *C, const int mval[2], bool extend,
const float dist = ED_view3d_select_dist_px();
float dist_sq_best = dist * dist;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 18eb442766b..51d8f8edb44 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -137,7 +137,6 @@ void ED_keymap_armature(struct wmKeyConfig *keyconf);
void ED_armature_from_edit(struct bArmature *arm);
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
-void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
void ED_armature_deselect_all(struct Object *obedit);
void ED_armature_deselect_all_visible(struct Object *obedit);
@@ -186,7 +185,7 @@ void create_vgroups_from_armature(
/* if bone is already in list, pass it as param to ignore it */
void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
-void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names);
+void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers);
void undo_push_armature(struct bContext *C, const char *name);
@@ -197,6 +196,11 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select);
void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag);
void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag);
+/* armature_utils.c */
+void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
+void ED_armature_ebone_listbase_free(struct ListBase *lb);
+void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src);
+
/* poseobject.c */
void ED_armature_exit_posemode(struct bContext *C, struct Base *base);
void ED_armature_enter_posemode(struct bContext *C, struct Base *base);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 859d45e9c86..d45e52d4c5a 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -48,7 +48,6 @@ void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
-void undo_push_curve(struct bContext *C, const char *name);
ListBase *object_editcurve_get(struct Object *ob);
void ED_curve_editnurb_load(struct Object *obedit);
@@ -72,6 +71,9 @@ void ED_curve_deselect_all(struct EditNurb *editnurb);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
+/* editcurve_undo.c */
+void undo_push_curve(struct bContext *C, const char *name);
+
/* editfont.c */
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 30d66577770..b652fb4c00b 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -4,7 +4,7 @@
* 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.
+ * 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
@@ -18,7 +18,6 @@
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*
- *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
@@ -31,10 +30,17 @@
#ifndef __ED_LATTICE_H__
#define __ED_LATTICE_H__
-struct Object;
+struct wmKeyConfig;
-void ED_lattice_editlatt_free(struct Object *ob);
-void ED_lattice_editlatt_make(struct Object *obedit);
-void ED_lattice_editlatt_load(struct Object *obedit);
+/* lattice_ops.c */
+void ED_operatortypes_lattice(void);
+void ED_keymap_lattice(struct wmKeyConfig *keyconf);
+
+/* editlattice_select.c */
+void ED_lattice_flags_set(struct Object *obedit, int flag);
+bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+
+/* editlattice_undo.c */
+void undo_push_lattice(struct bContext *C, const char *name);
#endif /* __ED_LATTICE_H__ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 0293f7cd204..4e25284dfa3 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -81,7 +81,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
-void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool add_key_index);
+void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
void EDBM_mesh_free(struct BMEditMesh *em);
void EDBM_mesh_load(struct Object *ob);
struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
@@ -115,7 +115,8 @@ void BM_uv_element_map_free(struct UvElementMap *vmap);
struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l);
bool EDBM_uv_check(struct BMEditMesh *em);
-struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, const bool sloppy, const bool selected);
+struct BMFace *EDBM_uv_active_face_get(
+ struct BMEditMesh *em, const bool sloppy, const bool selected);
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
@@ -264,6 +265,7 @@ void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGrou
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
+
/* mesh_data.c */
// void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 5df46dd26b8..a116cf5e5d0 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -57,6 +57,7 @@ struct PropertyRNA;
struct EnumPropertyItem;
struct EvaluationContext;
struct WorkSpace;
+struct wmWindow;
struct wmWindowManager;
#include "DNA_object_enums.h"
@@ -118,9 +119,6 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, st
void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr);
-bool ED_object_mode_compat_set(struct bContext *C, struct WorkSpace *workspace, eObjectMode mode, struct ReportList *reports);
-void ED_object_toggle_modes(struct bContext *C, eObjectMode mode);
-
/* bitflags for enter/exit editmode */
#define EM_FREEDATA 1
#define EM_FREEUNDO 2
@@ -150,6 +148,11 @@ void ED_object_vpaintmode_exit(struct bContext *C);
void ED_object_wpaintmode_exit_ex(struct WorkSpace *workspace, struct Object *ob);
void ED_object_wpaintmode_exit(struct bContext *C);
+void ED_object_sculptmode_enter_ex(
+ const struct EvaluationContext *eval_ctx,
+ struct WorkSpace *workspace, struct Scene *scene, struct Object *ob,
+ struct ReportList *reports);
+void ED_object_sculptmode_enter(struct bContext *C, struct ReportList *reports);
void ED_object_sculptmode_exit_ex(
const struct EvaluationContext *eval_ctx,
struct WorkSpace *workspace, struct Scene *scene, struct Object *ob);
@@ -200,13 +203,31 @@ void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *o
void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con);
void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con);
-/* object_lattice.c */
-bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-void undo_push_lattice(struct bContext *C, const char *name);
+/* object_modes.c */
+bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
+bool ED_object_mode_compat_set(struct bContext *C, struct WorkSpace *workspace, eObjectMode mode, struct ReportList *reports);
+void ED_object_mode_toggle(struct bContext *C, eObjectMode mode);
-/* object_lattice.c */
+bool ED_object_mode_generic_enter(
+ struct bContext *C,
+ eObjectMode object_mode);
+void ED_object_mode_generic_exit(
+ const struct EvaluationContext *eval_ctx,
+ struct WorkSpace *workspace, struct Scene *scene, struct Object *ob);
+bool ED_object_mode_generic_has_data(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *ob);
+
+bool ED_object_mode_generic_enter_or_other_window(
+ struct bContext *C, const struct wmWindow *win_compare,
+ eObjectMode object_mode);
+void ED_object_mode_generic_exit_or_other_window(
+ const struct EvaluationContext *eval_ctx, struct wmWindowManager *wm,
+ struct WorkSpace *workspace, struct Scene *scene, struct Object *ob);
-void ED_lattice_flags_set(struct Object *obedit, int flag);
+bool ED_object_mode_generic_exists(
+ struct wmWindowManager *wm, struct Object *ob,
+ eObjectMode object_mode);
/* object_modifier.c */
enum {
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index ffa6db18caa..ee60d1c8eef 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -55,7 +55,7 @@ struct ParticleEditSettings *PE_settings(struct Scene *scene);
void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra);
void PE_update_object(
const struct EvaluationContext *eval_ctx, struct Scene *scene,
- struct ViewLayer *view_layer, struct Object *ob, int useflag);
+ struct Object *ob, int useflag);
/* selection tools */
int PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
index 647a8dda1b9..9b48187e541 100644
--- a/source/blender/editors/include/ED_scene.h
+++ b/source/blender/editors/include/ED_scene.h
@@ -31,9 +31,10 @@ enum eSceneCopyMethod;
struct Scene *ED_scene_add(struct Main *bmain, struct bContext *C, struct wmWindow *win, enum eSceneCopyMethod method) ATTR_NONNULL();
bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct wmWindow *win, struct Scene *scene) ATTR_NONNULL();
-void ED_scene_exit(struct bContext *C) ATTR_NONNULL();
-void ED_scene_changed_update(struct Main *bmain, struct bContext *C, struct Scene *scene_new,
- const struct bScreen *active_screen) ATTR_NONNULL();
+void ED_scene_change_update(
+ struct Main *bmain, struct bContext *C,
+ struct wmWindow *win, const struct bScreen *screen,
+ struct Scene *scene_old, struct Scene *scene_new) ATTR_NONNULL();
bool ED_scene_view_layer_delete(
struct Main *bmain, struct Scene *scene, struct ViewLayer *layer,
struct ReportList *reports) ATTR_NONNULL(1, 2, 3);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 6513a55ec2b..dfdc88d4a0e 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -37,6 +37,8 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "DNA_object_enums.h"
+
#include "BLI_compiler_attrs.h"
struct Depsgraph;
@@ -204,6 +206,15 @@ bool ED_workspace_layout_cycle(
struct WorkSpace *workspace, const short direction,
struct bContext *C) ATTR_NONNULL();
+void ED_workspace_object_mode_sync_from_object(
+ struct wmWindowManager *wm, WorkSpace *workspace, struct Object *obact);
+void ED_workspace_object_mode_sync_from_scene(
+ struct wmWindowManager *wm, WorkSpace *workspace, struct Scene *scene);
+
+bool ED_workspace_object_mode_in_other_window(
+ struct wmWindowManager *wm, const struct wmWindow *win_compare, struct Object *obact,
+ eObjectMode *r_object_mode);
+
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Depsgraph *depsgraph);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index e25c34ddb78..15de57da09c 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -50,49 +50,65 @@ struct wmKeyConfig;
void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
-void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
+void ED_uvedit_assign_image(
+ struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
bool ED_uvedit_center(Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode);
void ED_uvedit_select_all(struct BMesh *bm);
-bool ED_object_get_active_image(struct Object *ob, int mat_nr,
- struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
+bool ED_object_get_active_image(
+ struct Object *ob, int mat_nr,
+ struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima);
bool ED_uvedit_test(struct Object *obedit);
/* visibility and selection */
-bool uvedit_face_visible_test(struct Scene *scene, struct Object *obedit, struct Image *ima, struct BMFace *efa);
-bool uvedit_face_select_test(struct Scene *scene, struct BMFace *efa,
- const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(struct Scene *scene, struct BMLoop *l,
- const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(struct Scene *scene, struct BMLoop *l,
- const int cd_loop_uv_offset);
+bool uvedit_face_visible_test(
+ struct Scene *scene, struct Object *obedit, struct Image *ima, struct BMFace *efa);
+bool uvedit_face_select_test(
+ struct Scene *scene, struct BMFace *efa,
+ const int cd_loop_uv_offset);
+bool uvedit_edge_select_test(
+ struct Scene *scene, struct BMLoop *l,
+ const int cd_loop_uv_offset);
+bool uvedit_uv_select_test(
+ struct Scene *scene, struct BMLoop *l,
+ const int cd_loop_uv_offset);
/* uv face */
-bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
- const bool do_history, const int cd_loop_uv_offset);
-bool uvedit_face_select_enable(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
- const bool do_history, const int cd_loop_uv_offset);
-bool uvedit_face_select_disable(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
- const int cd_loop_uv_offset);
+bool uvedit_face_select_set(
+ struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
+ const bool do_history, const int cd_loop_uv_offset);
+bool uvedit_face_select_enable(
+ struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
+ const bool do_history, const int cd_loop_uv_offset);
+bool uvedit_face_select_disable(
+ struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
+ const int cd_loop_uv_offset);
/* uv edge */
-void uvedit_edge_select_set(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
- const bool do_history, const int cd_loop_uv_offset);
-void uvedit_edge_select_enable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
- const bool do_history, const int cd_loop_uv_offset);
-void uvedit_edge_select_disable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
- const int cd_loop_uv_offset);
+void uvedit_edge_select_set(
+ struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
+ const bool do_history, const int cd_loop_uv_offset);
+void uvedit_edge_select_enable(
+ struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+ const bool do_history, const int cd_loop_uv_offset);
+void uvedit_edge_select_disable(
+ struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+ const int cd_loop_uv_offset);
/* uv vert */
-void uvedit_uv_select_set(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
- const bool do_history, const int cd_loop_uv_offset);
-void uvedit_uv_select_enable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
- const bool do_history, const int cd_loop_uv_offset);
-void uvedit_uv_select_disable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
- const int cd_loop_uv_offset);
-
-bool ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima,
- const float co[2], float r_uv[2]);
+void uvedit_uv_select_set(
+ struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
+ const bool do_history, const int cd_loop_uv_offset);
+void uvedit_uv_select_enable(
+ struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+ const bool do_history, const int cd_loop_uv_offset);
+void uvedit_uv_select_disable(
+ struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+ const int cd_loop_uv_offset);
+
+bool ED_uvedit_nearest_uv(
+ struct Scene *scene, struct Object *obedit, struct Image *ima,
+ const float co[2], float r_uv[2]);
void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
@@ -102,7 +118,8 @@ void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
-void ED_uvedit_pack_islands(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
+void ED_uvedit_pack_islands(
+struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
void ED_uvedit_unwrap_cube_project(
struct BMesh *bm, float cube_size, bool use_select, const float center[3]);
@@ -111,7 +128,8 @@ void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel)
/* uvedit_draw.c */
-void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]);
+void ED_image_draw_cursor(
+struct ARegion *ar, const float cursor[2]);
void ED_uvedit_draw_main(
struct SpaceImage *sima, const struct EvaluationContext *eval_ctx,
struct ARegion *ar, struct Scene *scene, struct ViewLayer *view_layer,
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index e3eb4c7ac97..64d749dc7a7 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -351,7 +351,7 @@ int view3d_opengl_select(
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
-void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index bfaa986d1ca..a6d965d52e4 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1221,11 +1221,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
void ui_but_override_flag(uiBut *but)
{
- bool is_overridden;
+ const int override_status = RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex);
- RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex, NULL, &is_overridden, NULL, NULL);
-
- if (is_overridden) {
+ if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) {
but->flag |= UI_BUT_OVERRIDEN;
}
else {
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 9e1697bc39a..7d4f32e00f7 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6860,11 +6860,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
const PropertySubType subtype = RNA_property_subtype(prop);
bool is_anim = RNA_property_animateable(ptr, prop);
bool is_editable = RNA_property_editable(ptr, prop);
- bool is_overridable;
/*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */
bool is_set = RNA_property_is_set(ptr, prop);
- RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL);
+ const int override_status = RNA_property_override_status(ptr, prop, -1);
+ const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
/* second slower test, saved people finding keyframe items in menus when its not possible */
if (is_anim)
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 0a36fbafc39..6f56576a208 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1320,7 +1320,7 @@ int UI_idcode_icon_get(const int idcode)
{
switch (idcode) {
case ID_AC:
- return ICON_ANIM_DATA;
+ return ICON_ACTION;
case ID_AR:
return ICON_ARMATURE_DATA;
case ID_BR:
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 16525dfbc9e..ad4aaf59998 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -482,13 +482,12 @@ static int override_type_set_button_poll(bContext *C)
PointerRNA ptr;
PropertyRNA *prop;
int index;
- bool is_overridable;
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- RNA_property_override_status(&ptr, prop, index, &is_overridable, NULL, NULL, NULL);
+ const int override_status = RNA_property_override_status(&ptr, prop, index);
- return (ptr.data && prop && is_overridable);
+ return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
}
static int override_type_set_button_exec(bContext *C, wmOperator *op)
@@ -572,13 +571,12 @@ static int override_remove_button_poll(bContext *C)
PointerRNA ptr;
PropertyRNA *prop;
int index;
- bool is_overridden;
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- RNA_property_override_status(&ptr, prop, index, NULL, &is_overridden, NULL, NULL);
+ const int override_status = RNA_property_override_status(&ptr, prop, index);
- return (ptr.data && ptr.id.data && prop && is_overridden);
+ return (ptr.data && ptr.id.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
}
static int override_remove_button_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index b3d5c74f77a..37a603d967f 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -214,9 +214,10 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev
return OPERATOR_CANCELLED;
}
- if (mt->poll && mt->poll(C, mt) == 0)
+ if (WM_menutype_poll(C, mt) == false) {
/* cancel but allow event to pass through, just like operators do */
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
layout = UI_pie_menu_layout(pie);
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index a0aecb12b84..d4fe0f5a5ee 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -518,9 +518,10 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
return OPERATOR_CANCELLED;
}
- if (mt->poll && mt->poll(C, mt) == 0)
+ if (WM_menutype_poll(C, mt) == false) {
/* cancel but allow event to pass through, just like operators do */
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE);
layout = UI_popup_menu_layout(pup);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index af7065a81ba..cbd2542b771 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -353,11 +353,11 @@ static void id_search_cb_objects_from_scene(const bContext *C, void *arg_templat
BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false);
- FOREACH_SCENE_OBJECT(scene, ob_iter)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter)
{
ob_iter->id.tag |= LIB_TAG_DOIT;
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
id_search_cb_tagged(C, arg_template, str, items);
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 2c509a949b5..d84e196dd76 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1591,6 +1591,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
rcti temp = *rect;
temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, false);
+ rect->xmax = temp.xmin;
}
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index ca4ab30a08d..b584782e183 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -59,6 +59,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "ED_object.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -543,6 +545,12 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
}
}
+ /* Switch out of edit mode to avoid being stuck in it (T54326). */
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ ED_object_mode_toggle(C, OB_MODE_EDIT);
+ }
+
bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range,
sequence_len, offset, validate_meshes,
as_background_job);
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 1b7fd319da0..a42aeee912b 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -28,7 +28,7 @@
* \ingroup collada
*/
#ifdef WITH_COLLADA
-#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
@@ -39,6 +39,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -92,6 +93,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int include_shapekeys;
int deform_bones_only;
+ int include_animations;
+ int sample_animations;
+ int sampling_rate;
+
int include_material_textures;
int use_texture_copies;
int active_uv_only;
@@ -143,6 +148,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_children = RNA_boolean_get(op->ptr, "include_children");
include_armatures = RNA_boolean_get(op->ptr, "include_armatures");
include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys");
+
+ include_animations = RNA_boolean_get(op->ptr, "include_animations");
+ sample_animations = RNA_boolean_get(op->ptr, "sample_animations");
+ sampling_rate = (sample_animations)? RNA_int_get(op->ptr, "sampling_rate") : 0;
+
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures");
@@ -162,32 +172,42 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
/* get editmode results */
ED_object_editmode_load(CTX_data_edit_object(C));
+ Scene *scene = CTX_data_scene(C);
+ CTX_data_eval_ctx(C, &eval_ctx);
+
+ ExportSettings export_settings;
+
+ export_settings.filepath = filepath;
+
+ export_settings.apply_modifiers = apply_modifiers != 0;
+ export_settings.export_mesh_type = export_mesh_type;
+ export_settings.selected = selected != 0;
+ export_settings.include_children = include_children != 0;
+ export_settings.include_armatures = include_armatures != 0;
+ export_settings.include_shapekeys = include_shapekeys != 0;
+ export_settings.deform_bones_only = deform_bones_only != 0;
+ export_settings.include_animations = include_animations;
+ export_settings.sampling_rate = sampling_rate;
+
+ export_settings.active_uv_only = active_uv_only != 0;
+ export_settings.use_texture_copies = use_texture_copies != 0;
+
+ export_settings.triangulate = triangulate != 0;
+ export_settings.use_object_instantiation = use_object_instantiation != 0;
+ export_settings.use_blender_profile = use_blender_profile != 0;
+ export_settings.sort_by_name = sort_by_name != 0;
+ export_settings.export_transformation_type = export_transformation_type;
+ export_settings.open_sim = open_sim != 0;
+ export_settings.limit_precision = limit_precision != 0;
+ export_settings.keep_bind_info = keep_bind_info != 0;
+
+ int includeFilter = OB_REL_NONE;
+ if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
+ if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE;
export_count = collada_export(&eval_ctx,
- CTX_data_scene(C),
- CTX_data_view_layer(C),
- filepath,
- apply_modifiers,
- export_mesh_type,
- selected,
- include_children,
- include_armatures,
- include_shapekeys,
- deform_bones_only,
-
- active_uv_only,
- include_material_textures,
- use_texture_copies,
-
- triangulate,
- use_object_instantiation,
- use_blender_profile,
- sort_by_name,
- export_transformation_type,
-
- open_sim,
- limit_precision,
- keep_bind_info
+ scene,
+ &export_settings
);
if (export_count == 0) {
@@ -209,6 +229,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayout *box, *row, *col, *split;
+ bool include_animations = RNA_boolean_get(imfptr, "include_animations");
/* Export Options: */
box = uiLayoutBox(layout);
@@ -238,6 +259,16 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "include_animations", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ if (include_animations) {
+ uiItemR(row, imfptr, "sample_animations", 0, NULL, ICON_NONE);
+ row = uiLayoutColumn(box, false);
+ uiItemR(row, imfptr, "sampling_rate", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "sample_animations"));
+ }
+
/* Texture options */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
@@ -260,6 +291,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE);
+
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE);
@@ -279,7 +311,6 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
-
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
@@ -356,20 +387,29 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_enum(func, "export_mesh_type_selection", prop_bc_export_mesh_type, 0,
"Resolution", "Modifier resolution for export");
- RNA_def_boolean(func, "selected", 0, "Selection Only",
+ RNA_def_boolean(func, "selected", false, "Selection Only",
"Export only selected elements");
- RNA_def_boolean(func, "include_children", 0, "Include Children",
+ RNA_def_boolean(func, "include_children", false, "Include Children",
"Export all children of selected objects (even if not selected)");
- RNA_def_boolean(func, "include_armatures", 0, "Include Armatures",
+ RNA_def_boolean(func, "include_armatures", false, "Include Armatures",
"Export related armatures (even if not selected)");
- RNA_def_boolean(func, "include_shapekeys", 1, "Include Shape Keys",
+ RNA_def_boolean(func, "include_shapekeys", false, "Include Shape Keys",
"Export all Shape Keys from Mesh Objects");
- RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only",
- "Only export deforming bones with armatures");
+ RNA_def_boolean(func, "deform_bones_only", false, "Deform Bones only",
+ "Only export deforming bones with armatures");
+
+ RNA_def_boolean(func, "include_animations", true,
+ "Include Animations", "Export Animations if available.\nExporting Animations will enforce the decomposition of node transforms\ninto <translation> <rotation> and <scale> components");
+
+ RNA_def_boolean(func, "sample_animations", 0,
+ "Sample Animations", "Auto-generate keyframes with a frame distance set by 'Sampling Rate'.\nWhen disabled, export only the keyframes defined in the animation f-curves (may be less accurate)");
+
+ RNA_def_int(func, "sampling_rate", 1, 1, INT_MAX,
+ "Sampling Rate", "The distance between 2 keyframes. 1 means: Every frame is keyed", 1, INT_MAX);
RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map",
@@ -423,6 +463,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
int min_chain_length;
int keep_bind_info;
+ ImportSettings import_settings;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -440,14 +481,16 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
RNA_string_get(op->ptr, "filepath", filename);
- if (collada_import(
- C, filename,
- import_units,
- find_chains,
- auto_connect,
- fix_orientation,
- min_chain_length,
- keep_bind_info) )
+
+ import_settings.filepath = filename;
+ import_settings.import_units = import_units != 0;
+ import_settings.auto_connect = auto_connect != 0;
+ import_settings.find_chains = find_chains != 0;
+ import_settings.fix_orientation = fix_orientation != 0;
+ import_settings.min_chain_length = min_chain_length;
+ import_settings.keep_bind_info = keep_bind_info != 0;
+
+ if (collada_import(C, &import_settings) )
{
DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/lattice/CMakeLists.txt b/source/blender/editors/lattice/CMakeLists.txt
new file mode 100644
index 00000000000..eaf837cf978
--- /dev/null
+++ b/source/blender/editors/lattice/CMakeLists.txt
@@ -0,0 +1,46 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../depsgraph
+ ../../makesdna
+ ../../makesrna
+ ../../render/extern/include
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ editlattice_select.c
+ editlattice_tools.c
+ editlattice_undo.c
+ lattice_ops.c
+
+ lattice_intern.h
+)
+
+blender_add_lib(bf_editor_lattice "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/lattice/editlattice_select.c
index b2f9bee27ff..d0d64b85195 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -23,14 +23,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/object/object_lattice.c
- * \ingroup edobj
+/** \file blender/editors/lattice/editlattice_select.c
+ * \ingroup edlattice
*/
-
#include <stdlib.h>
-#include <string.h>
-#include <math.h>
#include "MEM_guardedalloc.h"
@@ -41,7 +38,6 @@
#include "BLI_bitmap.h"
#include "DNA_curve_types.h"
-#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -52,127 +48,21 @@
#include "RNA_enum_types.h"
#include "BKE_context.h"
-#include "BKE_key.h"
#include "BKE_lattice.h"
-#include "BKE_deform.h"
#include "BKE_report.h"
-#include "DEG_depsgraph.h"
-
-#include "ED_lattice.h"
-#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_lattice.h"
#include "ED_view3d.h"
-#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "object_intern.h"
-
-/********************** Load/Make/Free ********************/
-
-void ED_lattice_editlatt_free(Object *ob)
-{
- Lattice *lt = ob->data;
-
- if (lt->editlatt) {
- Lattice *editlt = lt->editlatt->latt;
-
- if (editlt->def)
- MEM_freeN(editlt->def);
- if (editlt->dvert)
- BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
-
- MEM_freeN(editlt);
- MEM_freeN(lt->editlatt);
-
- lt->editlatt = NULL;
- }
-}
-
-void ED_lattice_editlatt_make(Object *obedit)
-{
- Lattice *lt = obedit->data;
- KeyBlock *actkey;
-
- ED_lattice_editlatt_free(obedit);
-
- actkey = BKE_keyblock_from_object(obedit);
- if (actkey)
- BKE_keyblock_convert_to_lattice(actkey, lt);
-
- lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt");
- lt->editlatt->latt = MEM_dupallocN(lt);
- lt->editlatt->latt->def = MEM_dupallocN(lt->def);
-
- if (lt->dvert) {
- int tot = lt->pntsu * lt->pntsv * lt->pntsw;
- lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
- BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot);
- }
-
- if (lt->key) lt->editlatt->shapenr = obedit->shapenr;
-}
-
-void ED_lattice_editlatt_load(Object *obedit)
-{
- Lattice *lt, *editlt;
- KeyBlock *actkey;
- BPoint *bp;
- float *fp;
- int tot;
-
- lt = obedit->data;
- editlt = lt->editlatt->latt;
-
- if (lt->editlatt->shapenr) {
- actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
-
- /* active key: vertices */
- tot = editlt->pntsu * editlt->pntsv * editlt->pntsw;
-
- if (actkey->data) MEM_freeN(actkey->data);
-
- fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data");
- actkey->totelem = tot;
-
- bp = editlt->def;
- while (tot--) {
- copy_v3_v3(fp, bp->vec);
- fp += 3;
- bp++;
- }
- }
- else {
- MEM_freeN(lt->def);
-
- lt->def = MEM_dupallocN(editlt->def);
-
- lt->flag = editlt->flag;
-
- lt->pntsu = editlt->pntsu;
- lt->pntsv = editlt->pntsv;
- lt->pntsw = editlt->pntsw;
-
- lt->typeu = editlt->typeu;
- lt->typev = editlt->typev;
- lt->typew = editlt->typew;
- lt->actbp = editlt->actbp;
- }
-
- if (lt->dvert) {
- BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
- lt->dvert = NULL;
- }
+#include "lattice_intern.h"
- if (editlt->dvert) {
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
-
- lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
- BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot);
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Utility Functions
+ * \{ */
static void bpoint_select_set(BPoint *bp, bool select)
{
@@ -186,7 +76,11 @@ static void bpoint_select_set(BPoint *bp, bool select)
}
}
-/************************** Select Random Operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Random Operator
+ * \{ */
static int lattice_select_random_exec(bContext *C, wmOperator *op)
{
@@ -242,9 +136,11 @@ void LATTICE_OT_select_random(wmOperatorType *ot)
WM_operator_properties_select_random(ot);
}
+/** \} */
/* -------------------------------------------------------------------- */
-/* Select Mirror Operator */
+/** \name Select Mirror Operator
+ * \{ */
static void ed_lattice_select_mirrored(Lattice *lt, const int axis, const bool extend)
{
@@ -323,8 +219,11 @@ void LATTICE_OT_select_mirror(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
+/** \} */
-/************************** Select More/Less Operator *************************/
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operator
+ * \{ */
static bool lattice_test_bitmap_uvw(Lattice *lt, BLI_bitmap *selpoints, int u, int v, int w, const bool selected)
{
@@ -423,16 +322,20 @@ void LATTICE_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/************************** Select All Operator *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select All Operator
+ * \{ */
void ED_lattice_flags_set(Object *obedit, int flag)
{
Lattice *lt = obedit->data;
BPoint *bp;
int a;
-
+
bp = lt->editlatt->latt->def;
-
+
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
lt->editlatt->latt->actbp = LT_ACTBP_NONE;
@@ -501,18 +404,22 @@ void LATTICE_OT_select_all(wmOperatorType *ot)
ot->name = "(De)select All";
ot->description = "Change selection of all UVW control points";
ot->idname = "LATTICE_OT_select_all";
-
+
/* api callbacks */
ot->exec = lattice_select_all_exec;
ot->poll = ED_operator_editlattice;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
-/************************** Select Ungrouped Verts Operator *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Ungrouped Verts Operator
+ * \{ */
static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
{
@@ -564,291 +471,22 @@ void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/************************** Make Regular Operator *************************/
-
-static int make_regular_poll(bContext *C)
-{
- Object *ob;
-
- if (ED_operator_editlattice(C)) return 1;
-
- ob = CTX_data_active_object(C);
- return (ob && ob->type == OB_LATTICE);
-}
-
-static int make_regular_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_edit_object(C);
- Lattice *lt;
-
- if (ob) {
- lt = ob->data;
- BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
- }
- else {
- ob = CTX_data_active_object(C);
- lt = ob->data;
- BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
- }
-
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-void LATTICE_OT_make_regular(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Make Regular";
- ot->description = "Set UVW control points a uniform distance apart";
- ot->idname = "LATTICE_OT_make_regular";
-
- /* api callbacks */
- ot->exec = make_regular_exec;
- ot->poll = make_regular_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/************************** Flip Verts Operator *************************/
-
-/* flipping options */
-typedef enum eLattice_FlipAxes {
- LATTICE_FLIP_U = 0,
- LATTICE_FLIP_V = 1,
- LATTICE_FLIP_W = 2
-} eLattice_FlipAxes;
-
-/* Flip midpoint value so that relative distances between midpoint and neighbor-pair is maintained
- * ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes)
- * - Helper for lattice_flip_exec()
- */
-static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
-{
- BPoint *bp;
- float diff;
-
- /* just the point in the middle (unpaired) */
- bp = &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
-
- /* flip over axis */
- diff = mid - bp->vec[axis];
- bp->vec[axis] = mid + diff;
-}
+/** \} */
-/* Swap pairs of lattice points along a specified axis
- * - Helper for lattice_flip_exec()
- */
-static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
-{
- BPoint *bpA, *bpB;
-
- int numU = lt->pntsu;
- int numV = lt->pntsv;
- int numW = lt->pntsw;
-
- int u0 = u, u1 = u;
- int v0 = v, v1 = v;
- int w0 = w, w1 = w;
-
- /* get pair index by just overriding the relevant pair-value
- * - "-1" else buffer overflow
- */
- switch (axis) {
- case LATTICE_FLIP_U:
- u1 = numU - u - 1;
- break;
- case LATTICE_FLIP_V:
- v1 = numV - v - 1;
- break;
- case LATTICE_FLIP_W:
- w1 = numW - w - 1;
- break;
- }
-
- /* get points to operate on */
- bpA = &lt->def[BKE_lattice_index_from_uvw(lt, u0, v0, w0)];
- bpB = &lt->def[BKE_lattice_index_from_uvw(lt, u1, v1, w1)];
-
- /* Swap all coordinates, so that flipped coordinates belong to
- * the indices on the correct side of the lattice.
- *
- * Coords: (-2 4) |0| (3 4) --> (3 4) |0| (-2 4)
- * Indices: (0,L) (1,R) --> (0,L) (1,R)
- */
- swap_v3_v3(bpA->vec, bpB->vec);
-
- /* However, we need to mirror the coordinate values on the axis we're dealing with,
- * otherwise we'd have effectively only rotated the points around. If we don't do this,
- * we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms
- * such as flipped normals, etc.
- *
- * Coords: (3 4) |0| (-2 4) --\
- * \-> (-3 4) |0| (2 4)
- * Indices: (0,L) (1,R) --> (0,L) (1,R)
- */
- lattice_flip_point_value(lt, u0, v0, w0, mid, axis);
- lattice_flip_point_value(lt, u1, v1, w1, mid, axis);
-}
-
-static int lattice_flip_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt;
-
- eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
- int numU, numV, numW;
- int totP;
-
- float mid = 0.0f;
- short isOdd = 0;
-
- /* get lattice - we need the "edit lattice" from the lattice... confusing... */
- lt = (Lattice *)obedit->data;
- lt = lt->editlatt->latt;
-
- numU = lt->pntsu;
- numV = lt->pntsv;
- numW = lt->pntsw;
- totP = numU * numV * numW;
-
- /* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */
- switch (axis) {
- case LATTICE_FLIP_U:
- isOdd = numU & 1;
- break;
- case LATTICE_FLIP_V:
- isOdd = numV & 1;
- break;
- case LATTICE_FLIP_W:
- isOdd = numW & 1;
- break;
-
- default:
- printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
- return OPERATOR_CANCELLED;
- }
-
- if (isOdd) {
- BPoint *bp;
- float avgInv = 1.0f / (float)totP;
- int i;
-
- /* midpoint calculation - assuming that u/v/w are axis-aligned */
- for (i = 0, bp = lt->def; i < totP; i++, bp++) {
- mid += bp->vec[axis] * avgInv;
- }
- }
-
- /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
- switch (axis) {
- case LATTICE_FLIP_U:
- {
- int u, v, w;
-
- /* v/w strips - front to back, top to bottom */
- for (w = 0; w < numW; w++) {
- for (v = 0; v < numV; v++) {
- /* swap coordinates of pairs of vertices on u */
- for (u = 0; u < (numU / 2); u++) {
- lattice_swap_point_pairs(lt, u, v, w, mid, axis);
- }
-
- /* flip u-coordinate of midpoint (i.e. unpaired point on u) */
- if (isOdd) {
- u = (numU / 2);
- lattice_flip_point_value(lt, u, v, w, mid, axis);
- }
- }
- }
- break;
- }
- case LATTICE_FLIP_V:
- {
- int u, v, w;
-
- /* u/w strips - front to back, left to right */
- for (w = 0; w < numW; w++) {
- for (u = 0; u < numU; u++) {
- /* swap coordinates of pairs of vertices on v */
- for (v = 0; v < (numV / 2); v++) {
- lattice_swap_point_pairs(lt, u, v, w, mid, axis);
- }
-
- /* flip v-coordinate of midpoint (i.e. unpaired point on v) */
- if (isOdd) {
- v = (numV / 2);
- lattice_flip_point_value(lt, u, v, w, mid, axis);
- }
- }
- }
- break;
- }
- case LATTICE_FLIP_W:
- {
- int u, v, w;
-
- for (v = 0; v < numV; v++) {
- for (u = 0; u < numU; u++) {
- /* swap coordinates of pairs of vertices on w */
- for (w = 0; w < (numW / 2); w++) {
- lattice_swap_point_pairs(lt, u, v, w, mid, axis);
- }
-
- /* flip w-coordinate of midpoint (i.e. unpaired point on w) */
- if (isOdd) {
- w = (numW / 2);
- lattice_flip_point_value(lt, u, v, w, mid, axis);
- }
- }
- }
- break;
- }
- default: /* shouldn't happen, but just in case */
- break;
- }
-
- /* updates */
- DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-void LATTICE_OT_flip(wmOperatorType *ot)
-{
- static const EnumPropertyItem flip_items[] = {
- {LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""},
- {LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""},
- {LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name = "Flip (Distortion Free)";
- ot->description = "Mirror all control points without inverting the lattice deform";
- ot->idname = "LATTICE_OT_flip";
-
- /* api callbacks */
- ot->poll = ED_operator_editlattice;
- ot->invoke = WM_menu_invoke;
- ot->exec = lattice_flip_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped");
-}
+/* -------------------------------------------------------------------- */
+/** \name Select Picking API
+ *
+ * Here actual select happens,
+ * Gets called via generic mouse select operator.
+ * \{ */
-/****************************** Mouse Selection *************************/
static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2])
{
struct { BPoint *bp; float dist; int select; float mval_fl[2]; } *data = userData;
float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
-
+
if ((bp->f1 & SELECT) && data->select)
dist_test += 5.0f;
@@ -883,7 +521,7 @@ bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool de
BPoint *bp = NULL;
Lattice *lt;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
bp = findnearestLattvert(&vc, mval, true);
@@ -917,70 +555,4 @@ bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool de
return false;
}
-/******************************** Undo *************************/
-
-typedef struct UndoLattice {
- BPoint *def;
- int pntsu, pntsv, pntsw, actbp;
-} UndoLattice;
-
-static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata))
-{
- UndoLattice *ult = (UndoLattice *)data;
- EditLatt *editlatt = (EditLatt *)edata;
- int a = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw;
-
- memcpy(editlatt->latt->def, ult->def, a * sizeof(BPoint));
- editlatt->latt->actbp = ult->actbp;
-}
-
-static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata))
-{
- UndoLattice *ult = MEM_callocN(sizeof(UndoLattice), "UndoLattice");
- EditLatt *editlatt = (EditLatt *)edata;
-
- ult->def = MEM_dupallocN(editlatt->latt->def);
- ult->pntsu = editlatt->latt->pntsu;
- ult->pntsv = editlatt->latt->pntsv;
- ult->pntsw = editlatt->latt->pntsw;
- ult->actbp = editlatt->latt->actbp;
-
- return ult;
-}
-
-static void free_undoLatt(void *data)
-{
- UndoLattice *ult = (UndoLattice *)data;
-
- if (ult->def) MEM_freeN(ult->def);
- MEM_freeN(ult);
-}
-
-static int validate_undoLatt(void *data, void *edata)
-{
- UndoLattice *ult = (UndoLattice *)data;
- EditLatt *editlatt = (EditLatt *)edata;
-
- return (ult->pntsu == editlatt->latt->pntsu &&
- ult->pntsv == editlatt->latt->pntsv &&
- ult->pntsw == editlatt->latt->pntsw);
-}
-
-static void *get_editlatt(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
-
- if (obedit && obedit->type == OB_LATTICE) {
- Lattice *lt = obedit->data;
- return lt->editlatt;
- }
-
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_lattice(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
-}
-
+/** \} */
diff --git a/source/blender/editors/lattice/editlattice_tools.c b/source/blender/editors/lattice/editlattice_tools.c
new file mode 100644
index 00000000000..bf60c1e7da6
--- /dev/null
+++ b/source/blender/editors/lattice/editlattice_tools.c
@@ -0,0 +1,341 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/lattice/editlattice_tools.c
+ * \ingroup edlattice
+ */
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "BKE_context.h"
+#include "BKE_lattice.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "lattice_intern.h"
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Make Regular Operator
+ * \{ */
+
+static int make_regular_poll(bContext *C)
+{
+ Object *ob;
+
+ if (ED_operator_editlattice(C)) return 1;
+
+ ob = CTX_data_active_object(C);
+ return (ob && ob->type == OB_LATTICE);
+}
+
+static int make_regular_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_edit_object(C);
+ Lattice *lt;
+
+ if (ob) {
+ lt = ob->data;
+ BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
+ }
+ else {
+ ob = CTX_data_active_object(C);
+ lt = ob->data;
+ BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void LATTICE_OT_make_regular(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Regular";
+ ot->description = "Set UVW control points a uniform distance apart";
+ ot->idname = "LATTICE_OT_make_regular";
+
+ /* api callbacks */
+ ot->exec = make_regular_exec;
+ ot->poll = make_regular_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flip Verts Operator
+ * \{ */
+
+/* flipping options */
+typedef enum eLattice_FlipAxes {
+ LATTICE_FLIP_U = 0,
+ LATTICE_FLIP_V = 1,
+ LATTICE_FLIP_W = 2
+} eLattice_FlipAxes;
+
+/**
+ * Flip midpoint value so that relative distances between midpoint and neighbor-pair is maintained
+ * ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes)
+ * - Helper for lattice_flip_exec()
+ */
+static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
+{
+ BPoint *bp;
+ float diff;
+
+ /* just the point in the middle (unpaired) */
+ bp = &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
+
+ /* flip over axis */
+ diff = mid - bp->vec[axis];
+ bp->vec[axis] = mid + diff;
+}
+
+/**
+ * Swap pairs of lattice points along a specified axis
+ * - Helper for lattice_flip_exec()
+ */
+static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
+{
+ BPoint *bpA, *bpB;
+
+ int numU = lt->pntsu;
+ int numV = lt->pntsv;
+ int numW = lt->pntsw;
+
+ int u0 = u, u1 = u;
+ int v0 = v, v1 = v;
+ int w0 = w, w1 = w;
+
+ /* get pair index by just overriding the relevant pair-value
+ * - "-1" else buffer overflow
+ */
+ switch (axis) {
+ case LATTICE_FLIP_U:
+ u1 = numU - u - 1;
+ break;
+ case LATTICE_FLIP_V:
+ v1 = numV - v - 1;
+ break;
+ case LATTICE_FLIP_W:
+ w1 = numW - w - 1;
+ break;
+ }
+
+ /* get points to operate on */
+ bpA = &lt->def[BKE_lattice_index_from_uvw(lt, u0, v0, w0)];
+ bpB = &lt->def[BKE_lattice_index_from_uvw(lt, u1, v1, w1)];
+
+ /* Swap all coordinates, so that flipped coordinates belong to
+ * the indices on the correct side of the lattice.
+ *
+ * Coords: (-2 4) |0| (3 4) --> (3 4) |0| (-2 4)
+ * Indices: (0,L) (1,R) --> (0,L) (1,R)
+ */
+ swap_v3_v3(bpA->vec, bpB->vec);
+
+ /* However, we need to mirror the coordinate values on the axis we're dealing with,
+ * otherwise we'd have effectively only rotated the points around. If we don't do this,
+ * we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms
+ * such as flipped normals, etc.
+ *
+ * Coords: (3 4) |0| (-2 4) --\
+ * \-> (-3 4) |0| (2 4)
+ * Indices: (0,L) (1,R) --> (0,L) (1,R)
+ */
+ lattice_flip_point_value(lt, u0, v0, w0, mid, axis);
+ lattice_flip_point_value(lt, u1, v1, w1, mid, axis);
+}
+
+static int lattice_flip_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Lattice *lt;
+
+ eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
+ int numU, numV, numW;
+ int totP;
+
+ float mid = 0.0f;
+ short isOdd = 0;
+
+ /* get lattice - we need the "edit lattice" from the lattice... confusing... */
+ lt = (Lattice *)obedit->data;
+ lt = lt->editlatt->latt;
+
+ numU = lt->pntsu;
+ numV = lt->pntsv;
+ numW = lt->pntsw;
+ totP = numU * numV * numW;
+
+ /* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */
+ switch (axis) {
+ case LATTICE_FLIP_U:
+ isOdd = numU & 1;
+ break;
+ case LATTICE_FLIP_V:
+ isOdd = numV & 1;
+ break;
+ case LATTICE_FLIP_W:
+ isOdd = numW & 1;
+ break;
+
+ default:
+ printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (isOdd) {
+ BPoint *bp;
+ float avgInv = 1.0f / (float)totP;
+ int i;
+
+ /* midpoint calculation - assuming that u/v/w are axis-aligned */
+ for (i = 0, bp = lt->def; i < totP; i++, bp++) {
+ mid += bp->vec[axis] * avgInv;
+ }
+ }
+
+ /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
+ switch (axis) {
+ case LATTICE_FLIP_U:
+ {
+ int u, v, w;
+
+ /* v/w strips - front to back, top to bottom */
+ for (w = 0; w < numW; w++) {
+ for (v = 0; v < numV; v++) {
+ /* swap coordinates of pairs of vertices on u */
+ for (u = 0; u < (numU / 2); u++) {
+ lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ }
+
+ /* flip u-coordinate of midpoint (i.e. unpaired point on u) */
+ if (isOdd) {
+ u = (numU / 2);
+ lattice_flip_point_value(lt, u, v, w, mid, axis);
+ }
+ }
+ }
+ break;
+ }
+ case LATTICE_FLIP_V:
+ {
+ int u, v, w;
+
+ /* u/w strips - front to back, left to right */
+ for (w = 0; w < numW; w++) {
+ for (u = 0; u < numU; u++) {
+ /* swap coordinates of pairs of vertices on v */
+ for (v = 0; v < (numV / 2); v++) {
+ lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ }
+
+ /* flip v-coordinate of midpoint (i.e. unpaired point on v) */
+ if (isOdd) {
+ v = (numV / 2);
+ lattice_flip_point_value(lt, u, v, w, mid, axis);
+ }
+ }
+ }
+ break;
+ }
+ case LATTICE_FLIP_W:
+ {
+ int u, v, w;
+
+ for (v = 0; v < numV; v++) {
+ for (u = 0; u < numU; u++) {
+ /* swap coordinates of pairs of vertices on w */
+ for (w = 0; w < (numW / 2); w++) {
+ lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ }
+
+ /* flip w-coordinate of midpoint (i.e. unpaired point on w) */
+ if (isOdd) {
+ w = (numW / 2);
+ lattice_flip_point_value(lt, u, v, w, mid, axis);
+ }
+ }
+ }
+ break;
+ }
+ default: /* shouldn't happen, but just in case */
+ break;
+ }
+
+ /* updates */
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void LATTICE_OT_flip(wmOperatorType *ot)
+{
+ static const EnumPropertyItem flip_items[] = {
+ {LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""},
+ {LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""},
+ {LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name = "Flip (Distortion Free)";
+ ot->description = "Mirror all control points without inverting the lattice deform";
+ ot->idname = "LATTICE_OT_flip";
+
+ /* api callbacks */
+ ot->poll = ED_operator_editlattice;
+ ot->invoke = WM_menu_invoke;
+ ot->exec = lattice_flip_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped");
+}
+
+/** \} */
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
new file mode 100644
index 00000000000..aa817928f92
--- /dev/null
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -0,0 +1,113 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/lattice/editlattice_undo.c
+ * \ingroup edlattice
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+
+#include "ED_lattice.h"
+#include "ED_util.h"
+
+#include "lattice_intern.h"
+
+typedef struct UndoLattice {
+ BPoint *def;
+ int pntsu, pntsv, pntsw, actbp;
+} UndoLattice;
+
+static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata))
+{
+ UndoLattice *ult = (UndoLattice *)data;
+ EditLatt *editlatt = (EditLatt *)edata;
+ int a = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw;
+
+ memcpy(editlatt->latt->def, ult->def, a * sizeof(BPoint));
+ editlatt->latt->actbp = ult->actbp;
+}
+
+static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata))
+{
+ UndoLattice *ult = MEM_callocN(sizeof(UndoLattice), "UndoLattice");
+ EditLatt *editlatt = (EditLatt *)edata;
+
+ ult->def = MEM_dupallocN(editlatt->latt->def);
+ ult->pntsu = editlatt->latt->pntsu;
+ ult->pntsv = editlatt->latt->pntsv;
+ ult->pntsw = editlatt->latt->pntsw;
+ ult->actbp = editlatt->latt->actbp;
+
+ return ult;
+}
+
+static void free_undoLatt(void *data)
+{
+ UndoLattice *ult = (UndoLattice *)data;
+
+ if (ult->def) MEM_freeN(ult->def);
+ MEM_freeN(ult);
+}
+
+static int validate_undoLatt(void *data, void *edata)
+{
+ UndoLattice *ult = (UndoLattice *)data;
+ EditLatt *editlatt = (EditLatt *)edata;
+
+ return (ult->pntsu == editlatt->latt->pntsu &&
+ ult->pntsv == editlatt->latt->pntsv &&
+ ult->pntsw == editlatt->latt->pntsw);
+}
+
+static void *get_editlatt(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+
+ if (obedit && obedit->type == OB_LATTICE) {
+ Lattice *lt = obedit->data;
+ return lt->editlatt;
+ }
+
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_lattice(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
+}
diff --git a/source/blender/editors/lattice/lattice_intern.h b/source/blender/editors/lattice/lattice_intern.h
new file mode 100644
index 00000000000..94f528a0457
--- /dev/null
+++ b/source/blender/editors/lattice/lattice_intern.h
@@ -0,0 +1,44 @@
+/*
+ * ***** 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/metaball/lattice_intern.h
+ * \ingroup edlattice
+ */
+
+
+#ifndef __LATTICE_INTERN_H__
+#define __LATTICE_INTERN_H__
+
+/* editlattice_select.c */
+void LATTICE_OT_select_all(struct wmOperatorType *ot);
+void LATTICE_OT_select_more(struct wmOperatorType *ot);
+void LATTICE_OT_select_less(struct wmOperatorType *ot);
+void LATTICE_OT_select_ungrouped(struct wmOperatorType *ot);
+void LATTICE_OT_select_random(struct wmOperatorType *ot);
+void LATTICE_OT_select_mirror(struct wmOperatorType *ot);
+
+/* editlattice_tools.c */
+void LATTICE_OT_make_regular(struct wmOperatorType *ot);
+void LATTICE_OT_flip(struct wmOperatorType *ot);
+
+#endif /* __LATTICE_INTERN_H__ */
diff --git a/source/blender/editors/lattice/lattice_ops.c b/source/blender/editors/lattice/lattice_ops.c
new file mode 100644
index 00000000000..37a10cbe12a
--- /dev/null
+++ b/source/blender/editors/lattice/lattice_ops.c
@@ -0,0 +1,80 @@
+/*
+ * ***** 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.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/metaball/lattice_ops.c
+ * \ingroup edlattice
+ */
+
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_object.h"
+#include "ED_lattice.h"
+
+#include "lattice_intern.h"
+
+void ED_operatortypes_lattice(void)
+{
+ WM_operatortype_append(LATTICE_OT_select_all);
+ WM_operatortype_append(LATTICE_OT_select_more);
+ WM_operatortype_append(LATTICE_OT_select_less);
+ WM_operatortype_append(LATTICE_OT_select_ungrouped);
+ WM_operatortype_append(LATTICE_OT_select_random);
+ WM_operatortype_append(LATTICE_OT_select_mirror);
+ WM_operatortype_append(LATTICE_OT_make_regular);
+ WM_operatortype_append(LATTICE_OT_flip);
+}
+
+void ED_keymap_lattice(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap;
+ wmKeyMapItem *kmi;
+
+ keymap = WM_keymap_find(keyconf, "Lattice", 0, 0);
+ keymap->poll = ED_operator_editlattice;
+
+ kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", AKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
+ kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
+ WM_keymap_add_item(keymap, "LATTICE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "LATTICE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
+
+ WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
+
+ WM_keymap_add_item(keymap, "LATTICE_OT_flip", FKEY, KM_PRESS, KM_CTRL, 0);
+
+ /* menus */
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0);
+
+ ED_keymap_proportional_cycle(keyconf, keymap);
+ ED_keymap_proportional_editmode(keyconf, keymap, false);
+}
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 80e1187609c..3877838ec54 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -60,6 +60,7 @@ set(SRC
editmesh_undo.c
editmesh_utils.c
mesh_data.c
+ mesh_mirror.c
mesh_ops.c
meshtools.c
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 113173c1c03..1b9ee70ccf5 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -24,7 +24,6 @@
* \ingroup edmesh
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
@@ -41,7 +40,6 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_context.h"
-#include "BKE_editmesh.h"
#include "BIF_gl.h"
@@ -609,261 +607,3 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
paintvert_flush_flags(ob);
}
}
-
-/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */
-/* note, this is not the best place for the function to be but moved
- * here for the purpose of syncing with bmesh */
-
-typedef unsigned int MirrTopoHash_t;
-
-typedef struct MirrTopoVert_t {
- MirrTopoHash_t hash;
- int v_index;
-} MirrTopoVert_t;
-
-static int mirrtopo_hash_sort(const void *l1, const void *l2)
-{
- if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
- else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
- return 0;
-}
-
-static int mirrtopo_vert_sort(const void *v1, const void *v2)
-{
- if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
- else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
- return 0;
-}
-
-bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store)
-{
- const bool is_editmode = (me->edit_btmesh != NULL);
- int totvert;
- int totedge;
-
- if (dm) {
- totvert = dm->getNumVerts(dm);
- totedge = dm->getNumEdges(dm);
- }
- else if (me->edit_btmesh) {
- totvert = me->edit_btmesh->bm->totvert;
- totedge = me->edit_btmesh->bm->totedge;
- }
- else {
- totvert = me->totvert;
- totedge = me->totedge;
- }
-
- if ((mesh_topo_store->index_lookup == NULL) ||
- (mesh_topo_store->prev_is_editmode != is_editmode) ||
- (totvert != mesh_topo_store->prev_vert_tot) ||
- (totedge != mesh_topo_store->prev_edge_tot))
- {
- return true;
- }
- else {
- return false;
- }
-
-}
-
-void ED_mesh_mirrtopo_init(
- Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store,
- const bool skip_em_vert_array_init)
-{
- const bool is_editmode = (me->edit_btmesh != NULL);
- MEdge *medge = NULL, *med;
- BMEditMesh *em = dm ? NULL : me->edit_btmesh;
-
- /* editmode*/
- BMEdge *eed;
- BMIter iter;
-
- int a, last;
- int totvert, totedge;
- int tot_unique = -1, tot_unique_prev = -1;
- int tot_unique_edges = 0, tot_unique_edges_prev;
-
- MirrTopoHash_t *topo_hash = NULL;
- MirrTopoHash_t *topo_hash_prev = NULL;
- MirrTopoVert_t *topo_pairs;
- MirrTopoHash_t topo_pass = 1;
-
- intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
-
- /* reallocate if needed */
- ED_mesh_mirrtopo_free(mesh_topo_store);
-
- mesh_topo_store->prev_is_editmode = is_editmode;
-
- if (em) {
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- totvert = em->bm->totvert;
- }
- else {
- totvert = dm ? dm->getNumVerts(dm) : me->totvert;
- }
-
- topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
-
- /* Initialize the vert-edge-user counts used to detect unique topology */
- if (em) {
- totedge = me->edit_btmesh->bm->totedge;
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
- topo_hash[i1]++;
- topo_hash[i2]++;
- }
- }
- else {
- totedge = dm ? dm->getNumEdges(dm) : me->totedge;
- medge = dm ? dm->getEdgeArray(dm) : me->medge;
-
- for (a = 0, med = medge; a < totedge; a++, med++) {
- const unsigned int i1 = med->v1, i2 = med->v2;
- topo_hash[i1]++;
- topo_hash[i2]++;
- }
- }
-
- topo_hash_prev = MEM_dupallocN(topo_hash);
-
- tot_unique_prev = -1;
- tot_unique_edges_prev = -1;
- while (1) {
- /* use the number of edges per vert to give verts unique topology IDs */
-
- tot_unique_edges = 0;
-
- /* This can make really big numbers, wrapping around here is fine */
- if (em) {
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
- topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
- topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
- tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
- }
- }
- else {
- for (a = 0, med = medge; a < totedge; a++, med++) {
- const unsigned int i1 = med->v1, i2 = med->v2;
- topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
- topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
- tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
- }
- }
- memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
-
- /* sort so we can count unique values */
- qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
-
- tot_unique = 1; /* account for skiping the first value */
- for (a = 1; a < totvert; a++) {
- if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
- tot_unique++;
- }
- }
-
- if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
- /* Finish searching for unique values when 1 loop dosnt give a
- * higher number of unique values compared to the previous loop */
- break;
- }
- else {
- tot_unique_prev = tot_unique;
- tot_unique_edges_prev = tot_unique_edges;
- }
- /* Copy the hash calculated this iter, so we can use them next time */
- memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
-
- topo_pass++;
- }
-
- /* Hash/Index pairs are needed for sorting to find index pairs */
- topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
-
- /* since we are looping through verts, initialize these values here too */
- index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
-
- if (em) {
- if (skip_em_vert_array_init == false) {
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- }
- }
-
- for (a = 0; a < totvert; a++) {
- topo_pairs[a].hash = topo_hash[a];
- topo_pairs[a].v_index = a;
-
- /* initialize lookup */
- index_lookup[a] = -1;
- }
-
- qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
-
- last = 0;
-
- /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
- * but you cant ever access the last 'a' index of MirrTopoPairs */
- if (em) {
- BMVert **vtable = em->bm->vtable;
- for (a = 1; a <= totvert; a++) {
- /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
- if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
- const int match_count = a - last;
- if (match_count == 2) {
- const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
- index_lookup[j] = (intptr_t)vtable[k];
- index_lookup[k] = (intptr_t)vtable[j];
- }
- else if (match_count == 1) {
- /* Center vertex. */
- const int j = topo_pairs[a - 1].v_index;
- index_lookup[j] = (intptr_t)vtable[j];
- }
- last = a;
- }
- }
- }
- else {
- /* same as above, for mesh */
- for (a = 1; a <= totvert; a++) {
- if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
- const int match_count = a - last;
- if (match_count == 2) {
- const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
- index_lookup[j] = k;
- index_lookup[k] = j;
- }
- else if (match_count == 1) {
- /* Center vertex. */
- const int j = topo_pairs[a - 1].v_index;
- index_lookup[j] = j;
- }
- last = a;
- }
- }
- }
-
- MEM_freeN(topo_pairs);
- topo_pairs = NULL;
-
- MEM_freeN(topo_hash);
- MEM_freeN(topo_hash_prev);
-
- mesh_topo_store->index_lookup = index_lookup;
- mesh_topo_store->prev_vert_tot = totvert;
- mesh_topo_store->prev_edge_tot = totedge;
-}
-
-void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
-{
- if (mesh_topo_store->index_lookup) {
- MEM_freeN(mesh_topo_store->index_lookup);
- }
- mesh_topo_store->index_lookup = NULL;
- mesh_topo_store->prev_vert_tot = -1;
- mesh_topo_store->prev_edge_tot = -1;
-}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index a21fc2fffde..292b28c772c 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -65,9 +65,10 @@ typedef struct MakePrimitiveData {
bool was_editmode;
} MakePrimitiveData;
-static Object *make_prim_init(bContext *C, const char *idname,
- const float loc[3], const float rot[3], const unsigned int layer,
- MakePrimitiveData *r_creation_data)
+static Object *make_prim_init(
+ bContext *C, const char *idname,
+ const float loc[3], const float rot[3], const unsigned int layer,
+ MakePrimitiveData *r_creation_data)
{
Object *obedit = CTX_data_edit_object(C);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index d4d7d92d5ad..c8d33a9cc60 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -139,6 +139,10 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
return false;
}
+ if (is_modal) {
+ RNA_float_set(op->ptr, "offset", 0.0f);
+ }
+
op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator");
opdata->em = em;
@@ -622,7 +626,6 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8);
RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
"Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 18320ec65f5..aee9785ea83 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -66,6 +66,10 @@
#include "ED_util.h"
#endif
+/* -------------------------------------------------------------------- */
+/** \name Extrude Internal Utilities
+ * \{ */
+
static void edbm_extrude_edge_exclude_mirror(
Object *obedit, BMEditMesh *em,
const char hflag,
@@ -154,7 +158,7 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
BMO_op_exec(em->bm, &bmop);
-
+
BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) {
BM_face_select_set(em->bm, f, true);
@@ -254,7 +258,7 @@ static bool edbm_extrude_ex(
BMOIter siter;
BMOperator extop;
BMElem *ele;
-
+
/* needed to remove the faces left behind */
if (htype & BM_FACE) {
htype |= BM_EDGE;
@@ -276,7 +280,7 @@ static bool edbm_extrude_ex(
BM_SELECT_HISTORY_RESTORE(bm);
BMO_op_exec(bm, &extop);
-
+
BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) {
BM_elem_select_set(bm, ele, true);
}
@@ -286,14 +290,20 @@ static bool edbm_extrude_ex(
return true;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Repeat Operator
+ * \{ */
+
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
+
const int steps = RNA_int_get(op->ptr, "steps");
-
+
const float offs = RNA_float_get(op->ptr, "offset");
float dvec[3], tmat[3][3], bmat[3][3];
short a;
@@ -314,7 +324,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
"translate vec=%v verts=%hv",
dvec, BM_ELEM_SELECT);
}
-
+
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
@@ -328,19 +338,25 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
ot->name = "Extrude Repeat Mesh";
ot->description = "Extrude selected vertices, edges or faces repeatedly";
ot->idname = "MESH_OT_extrude_repeat";
-
+
/* api callbacks */
ot->exec = edbm_extrude_repeat_exec;
ot->poll = ED_operator_editmesh_view3d;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* props */
RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Operator
+ * \{ */
+
/* generic extern called extruder */
static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
{
@@ -377,7 +393,7 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
break;
}
-
+
if (changed) {
return true;
}
@@ -392,7 +408,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
+
edbm_extrude_mesh(obedit, em, op);
/* This normally happens when pushing undo but modal operators
@@ -401,7 +417,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -411,27 +427,33 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
ot->name = "Extrude Region";
ot->idname = "MESH_OT_extrude_region";
ot->description = "Extrude region of faces";
-
+
/* api callbacks */
//ot->invoke = mesh_extrude_region_invoke;
ot->exec = edbm_extrude_region_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Verts Operator
+ * \{ */
+
static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
-
+
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -441,11 +463,11 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
ot->name = "Extrude Only Vertices";
ot->idname = "MESH_OT_extrude_verts_indiv";
ot->description = "Extrude individual vertices only";
-
+
/* api callbacks */
ot->exec = edbm_extrude_verts_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -453,15 +475,21 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Edges Operator
+ * \{ */
+
static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
-
+
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -471,11 +499,11 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
ot->name = "Extrude Only Edges";
ot->idname = "MESH_OT_extrude_edges_indiv";
ot->description = "Extrude individual edges only";
-
+
/* api callbacks */
ot->exec = edbm_extrude_edges_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -483,15 +511,21 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Faces Operator
+ * \{ */
+
static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
-
+
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -501,18 +535,25 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
ot->name = "Extrude Individual Faces";
ot->idname = "MESH_OT_extrude_faces_indiv";
ot->description = "Extrude individual faces only";
-
+
/* api callbacks */
ot->exec = edbm_extrude_faces_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
-/* *************** add-click-mesh (extrude) operator ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dupli-Extrude Operator
+ *
+ * Add-click-mesh (extrude) operator.
+ * \{ */
+
static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewContext vc;
@@ -533,7 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
zero_v3(center);
verts_len = 0;
-
+
BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
add_v3_v3(center, v1->co);
@@ -596,7 +637,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
cross_v3_v3v3(nor, view_vec, cross);
normalize_v3(nor);
}
-
+
/* center */
copy_v3_v3(ofs, center);
@@ -605,7 +646,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
mul_m4_v3(vc.obedit->imat, ofs); // back in object space
sub_v3_v3(ofs, center);
-
+
/* calculate rotation */
unit_m3(mat);
if (done) {
@@ -628,7 +669,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
axis_angle_to_mat3(mat, axis, angle);
}
}
-
+
if (rot_src) {
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
BM_ELEM_SELECT, center, mat);
@@ -653,7 +694,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center); // back in object space
-
+
EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center);
BMO_op_exec(vc.em->bm, &bmop);
@@ -685,17 +726,22 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
ot->name = "Duplicate or Extrude to Cursor";
ot->idname = "MESH_OT_dupli_extrude_cursor";
ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
-
+
/* api callbacks */
ot->invoke = edbm_dupli_extrude_cursor_invoke;
ot->poll = ED_operator_editmesh_region_view3d;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spin Operator
+ * \{ */
static int edbm_spin_exec(bContext *C, wmOperator *op)
{
@@ -815,8 +861,7 @@ void MESH_OT_spin(wmOperatorType *ot)
#ifdef USE_MANIPULATOR
/* -------------------------------------------------------------------- */
-
-/** \name Spin Manipulator
+/** \name Screw Operator
* \{ */
typedef struct ManipulatorSpinGroup {
@@ -1315,3 +1360,5 @@ void MESH_OT_screw(wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f,
"Axis", "Axis in global view space", -1.0f, 1.0f);
}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 6fd4203e085..3833b84b5d2 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -122,6 +122,11 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
return false;
}
+ if (is_modal) {
+ RNA_float_set(op->ptr, "thickness", 0.01f);
+ RNA_float_set(op->ptr, "depth", 0.0f);
+ }
+
op->customdata = opdata = MEM_mallocN(sizeof(InsetData), "inset_operator_data");
opdata->old_thickness = 0.01;
@@ -527,11 +532,9 @@ void MESH_OT_inset(wmOperatorType *ot)
prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f);
RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset");
RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces");
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index d9bbec7082d..cd894502bc4 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1782,7 +1782,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
kcd->linehits = linehits;
- kcd->totlinehit = BLI_array_count(linehits);
+ kcd->totlinehit = BLI_array_len(linehits);
/* find position along screen line, used for sorting */
for (i = 0; i < kcd->totlinehit; i++) {
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 795c7b6aa53..2ae48bee095 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -63,6 +63,10 @@
#include "mesh_intern.h" /* own include */
+/* -------------------------------------------------------------------- */
+/** \name Path Select Struct & Properties
+ * \{ */
+
struct PathSelectParams {
bool track_active; /* ensure the active element is the last selected item (handy for picking) */
bool use_topology_distance;
@@ -102,8 +106,11 @@ struct UserData {
const struct PathSelectParams *op_params;
};
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Vert Path */
+/** \name Vert Path
+ * \{ */
/* callbacks */
static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
@@ -205,10 +212,11 @@ static void mouse_mesh_shortest_path_vert(
EDBM_update_generic(em, false, false);
}
-
+/** \} */
/* -------------------------------------------------------------------- */
-/* Edge Path */
+/** \name Edge Path
+ * \{ */
/* callbacks */
static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
@@ -427,10 +435,11 @@ static void mouse_mesh_shortest_path_edge(
EDBM_update_generic(em, false, false);
}
-
+/** \} */
/* -------------------------------------------------------------------- */
-/* Face Path */
+/** \name Face Path
+ * \{ */
/* callbacks */
static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
@@ -477,7 +486,6 @@ static void mouse_mesh_shortest_path_face(
facetag_filter_cb, &user_data);
}
-
if (f_act != f_dst) {
if (path) {
if (op_params->track_active) {
@@ -538,10 +546,11 @@ static void mouse_mesh_shortest_path_face(
EDBM_update_generic(em, false, false);
}
-
+/** \} */
/* -------------------------------------------------------------------- */
-/* Main Operator for vert/edge/face tag */
+/** \name Main Operator for vert/edge/face tag
+ * \{ */
static bool edbm_shortest_path_pick_ex(
Scene *scene, Object *obedit, const struct PathSelectParams *op_params,
@@ -710,9 +719,11 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
/* -------------------------------------------------------------------- */
-/* Select path between existing selection */
+/** \name Select Path Between Existing Selection
+ * \{ */
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
{
@@ -797,3 +808,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot)
/* properties */
path_select_properties(ot);
}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 7b88b091672..513e939c529 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -75,7 +75,9 @@
/* use bmesh operator flags for a few operators */
#define BMO_ELE_TAG 1
-/* ****************************** MIRROR **************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror
+ * \{ */
void EDBM_select_mirrored(
BMEditMesh *em, const int axis, const bool extend,
@@ -168,21 +170,34 @@ void EDBM_select_mirrored(
*r_totfail = totfail;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Auto-Merge
+ *
+ * Used after transform operations.
+ * \{ */
+
void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
{
bool ok;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- ok = BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
- "automerge verts=%hv dist=%f",
- hflag, scene->toolsettings->doublimit);
+ ok = BMO_op_callf(
+ em->bm, BMO_FLAG_DEFAULTS,
+ "automerge verts=%hv dist=%f",
+ hflag, scene->toolsettings->doublimit);
if (LIKELY(ok) && update) {
EDBM_update_generic(em, true, true);
}
}
-/* ****************************** SELECTION ROUTINES **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Back-Buffer OpenGL Selection
+ * \{ */
unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in drawobject.c ... for colorindices */
@@ -203,21 +218,21 @@ bool EDBM_backbuf_border_init(
struct ImBuf *buf;
unsigned int *dr;
int a;
-
+
if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
return false;
}
-
+
buf = ED_view3d_backbuf_read(eval_ctx, vc, xmin, ymin, xmax, ymax);
if ((buf == NULL) || (bm_vertoffs == 0)) {
return false;
}
dr = buf->rect;
-
+
/* build selection lookup */
selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
-
+
a = (xmax - xmin + 1) * (ymax - ymin + 1);
while (a--) {
if (*dr > 0 && *dr <= bm_vertoffs) {
@@ -267,9 +282,9 @@ static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
/* mcords is a polygon mask
* - grab backbuffer,
- * - draw with black in backbuffer,
+ * - draw with black in backbuffer,
* - grab again and compare
- * returns 'OK'
+ * returns 'OK'
*/
bool EDBM_backbuf_border_mask_init(const struct EvaluationContext *eval_ctx, ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
{
@@ -277,7 +292,7 @@ bool EDBM_backbuf_border_mask_init(const struct EvaluationContext *eval_ctx, Vie
struct ImBuf *buf;
int a;
struct LassoMaskData lasso_mask_data;
-
+
/* method in use for face selecting too */
if (vc->obedit == NULL) {
if (!BKE_paint_select_elem_test(vc->obact, eval_ctx->object_mode)) {
@@ -306,7 +321,7 @@ bool EDBM_backbuf_border_mask_init(const struct EvaluationContext *eval_ctx, Vie
/* build selection lookup */
selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
-
+
a = (xmax - xmin + 1) * (ymax - ymin + 1);
while (a--) {
if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) {
@@ -329,7 +344,7 @@ bool EDBM_backbuf_circle_init(
unsigned int *dr;
short xmin, ymin, xmax, ymax, xc, yc;
int radsq;
-
+
/* method in use for face selecting too */
if (vc->obedit == NULL) {
if (!BKE_paint_select_elem_test(vc->obact, eval_ctx->object_mode)) {
@@ -348,7 +363,7 @@ bool EDBM_backbuf_circle_init(
}
dr = buf->rect;
-
+
/* build selection lookup */
selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
radsq = rads * rads;
@@ -364,12 +379,12 @@ bool EDBM_backbuf_circle_init(
IMB_freeImBuf(buf);
return true;
-
+
}
+/** \} */
/* -------------------------------------------------------------------- */
-
/** \name Find Nearest Vert/Edge/Face
*
* \note Screen-space manhatten distances are used here,
@@ -451,14 +466,14 @@ BMVert *EDBM_vert_find_nearest_ex(
float dist_test;
unsigned int index;
BMVert *eve;
-
+
/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
ED_view3d_backbuf_validate(eval_ctx, vc);
index = ED_view3d_backbuf_sample_rect(
eval_ctx, vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
-
+
if (eve) {
if (dist_test < *r_dist) {
*r_dist = dist_test;
@@ -817,7 +832,7 @@ BMFace *EDBM_face_find_nearest_ex(
index = ED_view3d_backbuf_sample(eval_ctx, vc, vc->mval[0], vc->mval[1]);
efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
-
+
if (r_efa_zbuf) {
*r_efa_zbuf = efa;
}
@@ -895,8 +910,8 @@ BMFace *EDBM_face_find_nearest(const struct EvaluationContext *eval_ctx, ViewCon
#undef FIND_NEAR_CYCLE_THRESHOLD_MIN
-/* best distance based on screen coords.
- * use em->selectmode to define how to use
+/* best distance based on screen coords.
+ * use em->selectmode to define how to use
* selected vertices and edges get disadvantage
* return 1 if found one
*/
@@ -914,7 +929,7 @@ static int unified_findnearest(
float dist = dist_init;
BMFace *efa_zbuf = NULL;
BMEdge *eed_zbuf = NULL;
-
+
BMVert *eve = NULL;
BMEdge *eed = NULL;
BMFace *efa = NULL;
@@ -976,8 +991,10 @@ static int unified_findnearest(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Select Similar (Vert/Edge/Face) Operator
+ * \{ */
-/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
static const EnumPropertyItem prop_similar_compare_types[] = {
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
@@ -1054,7 +1071,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
EDBM_update_generic(em, false, false);
return OPERATOR_FINISHED;
-}
+}
/* ***************************************************** */
@@ -1160,8 +1177,9 @@ static int edbm_select_similar_exec(bContext *C, wmOperator *op)
else return similar_face_select_exec(C, op);
}
-static const EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *select_similar_type_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
Object *obedit;
@@ -1213,15 +1231,15 @@ void MESH_OT_select_similar(wmOperatorType *ot)
ot->name = "Select Similar";
ot->idname = "MESH_OT_select_similar";
ot->description = "Select similar vertices, edges or faces by property types";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = edbm_select_similar_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
RNA_def_enum_funcs(prop, select_similar_type_itemf);
@@ -1231,9 +1249,11 @@ void MESH_OT_select_similar(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
+/** \} */
/* -------------------------------------------------------------------- */
-/* Select Similar Regions */
+/** \name Select Similar Region Operator
+ * \{ */
static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
{
@@ -1254,9 +1274,10 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
}
groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
- group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index,
- NULL, NULL,
- BM_ELEM_SELECT, BM_VERT);
+ group_tot = BM_mesh_calc_face_groups(
+ bm, groups_array, &group_index,
+ NULL, NULL,
+ BM_ELEM_SELECT, BM_VERT);
BM_mesh_elem_table_ensure(bm, BM_FACE);
@@ -1297,7 +1318,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
MEM_freeN(group_index);
if (changed) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
else {
BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
@@ -1321,8 +1342,11 @@ void MESH_OT_select_similar_region(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
-/* **************** Mode Select *************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Mode Vert/Edge/Face Operator
+ * \{ */
static int edbm_select_mode_exec(bContext *C, wmOperator *op)
{
@@ -1393,12 +1417,15 @@ void MESH_OT_select_mode(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
}
-/* ***************************************************** */
+/** \} */
-/* **************** LOOP SELECTS *************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Loop (Non Modal) Operator
+ * \{ */
-static void walker_select_count(BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix,
- int *r_totsel, int *r_totunsel)
+static void walker_select_count(
+ BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix,
+ int *r_totsel, int *r_totunsel)
{
BMesh *bm = em->bm;
BMElem *ele;
@@ -1453,7 +1480,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
BMEdge **edarray;
int edindex;
const bool is_ring = RNA_boolean_get(op->ptr, "ring");
-
+
BMIter iter;
int totedgesel = 0;
@@ -1462,17 +1489,17 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
totedgesel++;
}
}
-
+
edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
edindex = 0;
-
+
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
edarray[edindex] = eed;
edindex++;
}
}
-
+
if (is_ring) {
for (edindex = 0; edindex < totedgesel; edindex += 1) {
eed = edarray[edindex];
@@ -1489,8 +1516,8 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
}
MEM_freeN(edarray);
// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -1501,23 +1528,23 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot)
ot->name = "Multi Select Loops";
ot->idname = "MESH_OT_loop_multi_select";
ot->description = "Select a loop of connected edges by connection type";
-
+
/* api callbacks */
ot->exec = edbm_loop_multiselect_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
}
-
-/* ***************** MAIN MOUSE SELECTION ************** */
-
+/** \} */
-/* ***************** loop select (non modal) ************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Loop (Cursor Pick) Operator
+ * \{ */
static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
{
@@ -1572,7 +1599,6 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
}
}
-
static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
{
EvaluationContext eval_ctx;
@@ -1651,11 +1677,15 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
/* We can't be sure this has already been set... */
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
- if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_object(
+ vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
length_1 = len_squared_v2v2(mvalf, v1_co);
}
- if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_object(
+ vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
length_2 = len_squared_v2v2(mvalf, v2_co);
}
#if 0
@@ -1682,7 +1712,9 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
float co[2], tdist;
BM_face_calc_center_mean(f, cent);
- if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_object(
+ vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
tdist = len_squared_v2v2(mvalf, co);
if (tdist < best_dist) {
/* printf("Best face: %p (%f)\n", f, tdist);*/
@@ -1699,21 +1731,22 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
}
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
return true;
}
static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
-
+
view3d_operator_needs_opengl(C);
-
- if (mouse_mesh_loop(C, event->mval,
- RNA_boolean_get(op->ptr, "extend"),
- RNA_boolean_get(op->ptr, "deselect"),
- RNA_boolean_get(op->ptr, "toggle"),
- RNA_boolean_get(op->ptr, "ring")))
+
+ if (mouse_mesh_loop(
+ C, event->mval,
+ RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "deselect"),
+ RNA_boolean_get(op->ptr, "toggle"),
+ RNA_boolean_get(op->ptr, "ring")))
{
return OPERATOR_FINISHED;
}
@@ -1728,14 +1761,14 @@ void MESH_OT_loop_select(wmOperatorType *ot)
ot->name = "Loop Select";
ot->idname = "MESH_OT_loop_select";
ot->description = "Select a loop of connected edges";
-
+
/* api callbacks */
ot->invoke = edbm_select_loop_invoke;
ot->poll = ED_operator_editmesh_region_view3d;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
@@ -1749,11 +1782,11 @@ void MESH_OT_edgering_select(wmOperatorType *ot)
ot->name = "Edge Ring Select";
ot->idname = "MESH_OT_edgering_select";
ot->description = "Select an edge ring";
-
+
/* callbacks */
ot->invoke = edbm_select_loop_invoke;
ot->poll = ED_operator_editmesh_region_view3d;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -1763,7 +1796,12 @@ void MESH_OT_edgering_select(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
}
-/* ******************** (de)select all operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
+
static int edbm_select_all_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -1786,7 +1824,7 @@ static int edbm_select_all_exec(bContext *C, wmOperator *op)
break;
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -1808,13 +1846,19 @@ void MESH_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Interior Faces Operator
+ * \{ */
+
static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (EDBM_select_interior_faces(em)) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -1839,10 +1883,15 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Picking API
+ *
+ * Here actual select happens,
+ * Gets called via generic mouse select operator.
+ * \{ */
-/* ************************************************** */
-/* here actual select happens */
-/* gets called via generic mouse select operator */
bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
EvaluationContext eval_ctx;
@@ -1971,13 +2020,19 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
return true;
}
return false;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mode Utilities
+ * \{ */
+
static void edbm_strip_selections(BMEditMesh *em)
{
BMEditSelection *ese, *nextese;
@@ -2016,11 +2071,11 @@ void EDBM_selectmode_set(BMEditMesh *em)
BMEdge *eed;
BMFace *efa;
BMIter iter;
-
+
em->bm->selectmode = em->selectmode;
edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */
-
+
if (em->bm->totvertsel == 0 &&
em->bm->totedgesel == 0 &&
em->bm->totfacesel == 0)
@@ -2183,8 +2238,9 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s
}
/* user facing function, does notification */
-bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
- const int action, const bool use_extend, const bool use_expand)
+bool EDBM_selectmode_toggle(
+ bContext *C, const short selectmode_new,
+ const int action, const bool use_extend, const bool use_expand)
{
ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
@@ -2280,9 +2336,10 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
*
* \return true if the mode is changed.
*/
-bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em,
- const short selectmode_disable,
- const short selectmode_fallback)
+bool EDBM_selectmode_disable(
+ Scene *scene, BMEditMesh *em,
+ const short selectmode_disable,
+ const short selectmode_fallback)
{
/* note essential, but switch out of vertex mode since the
* selected regions wont be nicely isolated after flushing */
@@ -2305,6 +2362,12 @@ bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Toggle
+ * \{ */
+
void EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
{
BMIter iter;
@@ -2333,7 +2396,7 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
BMVert *eve;
BMEdge *eed;
BMFace *efa;
-
+
if (em->bm->selectmode & SCE_SELECT_VERTEX) {
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
@@ -2356,9 +2419,17 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
}
}
-// if (EM_texFaceCheck())
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Interior Faces
+ *
+ * \note This algorithm is limited to single faces and could be improved, see:
+ * https://blender.stackexchange.com/questions/18916
+ * \{ */
+
bool EDBM_select_interior_faces(BMEditMesh *em)
{
BMesh *bm = em->bm;
@@ -2391,8 +2462,13 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
return changed;
}
+/** \} */
-/************************ Select Linked Operator *************************/
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ *
+ * Support delimiting on different edge properties.
+ * \{ */
/* so we can have last-used default depend on selection mode (rare exception!) */
#define USE_LINKED_SELECT_DEFAULT_HACK
@@ -2452,10 +2528,10 @@ static bool select_linked_delimit_test(
* Gets the default from the operator fallback to own last-used value
* (selected based on mode)
*/
-static int select_linked_delimit_default_from_op(wmOperator *op, BMEditMesh *em)
+static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode)
{
static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
- int delimit_last_index = (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
+ int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
char *delimit_last = &delimit_last_store[delimit_last_index];
PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
int delimit;
@@ -2525,7 +2601,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMWalker walker;
#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em);
+ int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
#else
int delimit = RNA_enum_get(op->ptr, "delimit");
#endif
@@ -2683,7 +2759,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
select_linked_delimit_end(em);
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -2713,6 +2789,12 @@ void MESH_OT_select_linked(wmOperatorType *ot)
#endif
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
@@ -2853,13 +2935,13 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
/* return warning! */
if (unified_findnearest(&eval_ctx, &vc, &eve, &eed, &efa) == 0) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_CANCELLED;
}
#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em);
+ int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
#else
int delimit = RNA_enum_get(op->ptr, "delimit");
#endif
@@ -2874,7 +2956,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
RNA_int_set(op->ptr, "index", index);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -2896,14 +2978,14 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
BMElem *ele = EDBM_elem_from_index_any(em, index);
#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em);
+ int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
#else
int delimit = RNA_enum_get(op->ptr, "delimit");
#endif
edbm_select_linked_pick_ex(em, ele, sel, delimit);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -2916,15 +2998,15 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
ot->name = "Select Linked";
ot->idname = "MESH_OT_select_linked_pick";
ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
-
+
/* api callbacks */
ot->invoke = edbm_select_linked_pick_invoke;
ot->exec = edbm_select_linked_pick_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
"Delimit selected region");
@@ -2937,6 +3019,11 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Face by Sides Operator
+ * \{ */
static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op)
{
@@ -3012,6 +3099,11 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Loose Operator
+ * \{ */
static int edbm_select_loose_exec(bContext *C, wmOperator *op)
{
@@ -3083,6 +3175,11 @@ void MESH_OT_select_loose(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror Operator
+ * \{ */
static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
{
@@ -3131,7 +3228,11 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
}
-/* ******************** **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
static int edbm_select_more_exec(bContext *C, wmOperator *op)
{
@@ -3141,7 +3242,7 @@ static int edbm_select_more_exec(bContext *C, wmOperator *op)
EDBM_select_more(em, use_face_step);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -3155,13 +3256,19 @@ void MESH_OT_select_more(wmOperatorType *ot)
/* api callbacks */
ot->exec = edbm_select_more_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
+
static int edbm_select_less_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -3170,7 +3277,7 @@ static int edbm_select_less_exec(bContext *C, wmOperator *op)
EDBM_select_less(em, use_face_step);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -3184,13 +3291,19 @@ void MESH_OT_select_less(wmOperatorType *ot)
/* api callbacks */
ot->exec = edbm_select_less_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select N'th Operator
+ * \{ */
+
/**
* Check if we're connected to another selected efge.
*/
@@ -3413,13 +3526,18 @@ void MESH_OT_select_nth(wmOperatorType *ot)
void em_setup_viewcontext(bContext *C, ViewContext *vc)
{
- view3d_set_viewcontext(C, vc);
-
+ ED_view3d_viewcontext_init(C, vc);
+
if (vc->obedit) {
vc->em = BKE_editmesh_from_object(vc->obedit);
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Sharp Edges Operator
+ * \{ */
static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
{
@@ -3460,20 +3578,26 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot)
ot->name = "Select Sharp Edges";
ot->description = "Select all sharp-enough edges";
ot->idname = "MESH_OT_edges_select_sharp";
-
+
/* api callbacks */
ot->exec = edbm_select_sharp_edges_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* props */
prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
"Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(30.0f));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Flat Faces Operator
+ * \{ */
+
static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -3541,20 +3665,26 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
ot->name = "Select Linked Flat Faces";
ot->description = "Select linked faces by angle";
ot->idname = "MESH_OT_faces_select_linked_flat";
-
+
/* api callbacks */
ot->exec = edbm_select_linked_flat_faces_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* props */
prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
"Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(1.0f));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Non-Manifold Operator
+ * \{ */
+
static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -3576,12 +3706,12 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
/* Selects isolated verts, and edges that do not have 2 neighboring
* faces
*/
-
+
if (em->selectmode == SCE_SELECT_FACE) {
BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
return OPERATOR_CANCELLED;
}
-
+
if (use_verts) {
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
@@ -3591,7 +3721,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
}
}
}
-
+
if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
@@ -3622,11 +3752,11 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
ot->name = "Select Non Manifold";
ot->description = "Select all non-manifold vertices or edges";
ot->idname = "MESH_OT_select_non_manifold";
-
+
/* api callbacks */
ot->exec = edbm_select_non_manifold_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -3646,6 +3776,12 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
"Vertices connecting multiple face regions");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Random Operator
+ * \{ */
+
static int edbm_select_random_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -3692,9 +3828,9 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op)
else {
EDBM_deselect_flush(em);
}
-
+
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
+
return OPERATOR_FINISHED;
}
@@ -3711,11 +3847,17 @@ void MESH_OT_select_random(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* props */
WM_operator_properties_select_random(ot);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Ungrouped Operator
+ * \{ */
+
static int edbm_select_ungrouped_poll(bContext *C)
{
if (ED_operator_editmesh(C)) {
@@ -3782,6 +3924,11 @@ void MESH_OT_select_ungrouped(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Axis Operator
+ * \{ */
/* BMESH_TODO - some way to select on an arbitrary axis */
static int edbm_select_axis_exec(bContext *C, wmOperator *op)
@@ -3868,6 +4015,12 @@ void MESH_OT_select_axis(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Region to Loop Operator
+ * \{ */
+
static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
@@ -3881,22 +4034,22 @@ static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l1, *l2;
BMIter liter1, liter2;
-
+
BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
int tot = 0, totsel = 0;
-
+
BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
tot++;
totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
}
-
+
if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
}
}
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
+
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
BM_edge_select_set(em->bm, e, true);
@@ -3931,29 +4084,36 @@ void MESH_OT_region_to_loop(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int loop_find_region(BMLoop *l, int flag,
- GSet *visit_face_set, BMFace ***region_out)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Loop to Region Operator
+ * \{ */
+
+static int loop_find_region(
+ BMLoop *l, int flag,
+ GSet *visit_face_set, BMFace ***region_out)
{
BMFace **region = NULL;
BMFace **stack = NULL;
BLI_array_declare(region);
BLI_array_declare(stack);
BMFace *f;
-
+
BLI_array_append(stack, l->f);
BLI_gset_insert(visit_face_set, l->f);
-
- while (BLI_array_count(stack) > 0) {
+
+ while (BLI_array_len(stack) > 0) {
BMIter liter1, liter2;
BMLoop *l1, *l2;
-
+
f = BLI_array_pop(stack);
BLI_array_append(region, f);
-
+
BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l1->e, flag))
continue;
-
+
BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
/* avoids finding same region twice
* (otherwise) the logic works fine without */
@@ -3967,11 +4127,11 @@ static int loop_find_region(BMLoop *l, int flag,
}
}
}
-
+
BLI_array_free(stack);
-
+
*region_out = region;
- return BLI_array_count(region);
+ return BLI_array_len(region);
}
static int verg_radial(const void *va, const void *vb)
@@ -3979,10 +4139,9 @@ static int verg_radial(const void *va, const void *vb)
const BMEdge *e_a = *((const BMEdge **)va);
const BMEdge *e_b = *((const BMEdge **)vb);
- int a, b;
- a = BM_edge_face_count(e_a);
- b = BM_edge_face_count(e_b);
-
+ const int a = BM_edge_face_count(e_a);
+ const int b = BM_edge_face_count(e_b);
+
if (a > b) return -1;
if (a < b) return 1;
return 0;
@@ -4001,7 +4160,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
const int edges_len = em->bm->totedgesel;
BMEdge *e, **edges;
int count = 0, i;
-
+
visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len);
edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
@@ -4015,21 +4174,21 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
BM_elem_flag_disable(e, BM_ELEM_TAG);
}
}
-
+
/* sort edges by radial cycle length */
qsort(edges, edges_len, sizeof(*edges), verg_radial);
-
+
for (i = 0; i < edges_len; i++) {
BMIter liter;
BMLoop *l;
BMFace **region = NULL, **region_out;
int c, tot = 0;
-
+
e = edges[i];
-
+
if (!BM_elem_flag_test(e, BM_ELEM_TAG))
continue;
-
+
BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
if (BLI_gset_haskey(visit_face_set, l->f))
continue;
@@ -4051,26 +4210,26 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
MEM_freeN(region_out);
}
}
-
+
if (region) {
int j;
-
+
for (j = 0; j < tot; j++) {
BM_elem_flag_enable(region[j], BM_ELEM_TAG);
BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) {
BM_elem_flag_disable(l->e, BM_ELEM_TAG);
}
}
-
+
count += tot;
-
+
MEM_freeN(region);
}
}
-
+
MEM_freeN(edges);
BLI_gset_free(visit_face_set, NULL);
-
+
return count;
}
@@ -4081,25 +4240,23 @@ static int edbm_loop_to_region_exec(bContext *C, wmOperator *op)
BMIter iter;
BMFace *f;
const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger");
- int a, b;
-
/* find the set of regions with smallest number of total faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- a = loop_find_regions(em, select_bigger);
- b = loop_find_regions(em, !select_bigger);
+ const int a = loop_find_regions(em, select_bigger);
+ const int b = loop_find_regions(em, !select_bigger);
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
-
+
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
+
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BM_face_select_set(em->bm, f, true);
}
}
-
+
EDBM_selectmode_flush(em);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -4119,9 +4276,8 @@ void MESH_OT_loop_to_region(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");
}
-
-/************************ Select Path Operator *************************/
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index b2371ef1ad3..e9d6a98c96d 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -87,6 +87,10 @@
#define USE_FACE_CREATE_SEL_EXTEND
+/* -------------------------------------------------------------------- */
+/** \name Subdivide Operator
+ * \{ */
+
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -96,19 +100,20 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
- if (RNA_boolean_get(op->ptr, "quadtri") &&
+ if (RNA_boolean_get(op->ptr, "quadtri") &&
RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT)
{
RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
}
-
- BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_LIN, false,
- fractal, along_normal,
- cuts,
- SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
- RNA_boolean_get(op->ptr, "quadtri"), true, false,
- RNA_int_get(op->ptr, "seed"));
+
+ BM_mesh_esubdivide(
+ em->bm, BM_ELEM_SELECT,
+ smooth, SUBD_FALLOFF_LIN, false,
+ fractal, along_normal,
+ cuts,
+ SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
+ RNA_boolean_get(op->ptr, "quadtri"), true, false,
+ RNA_int_get(op->ptr, "seed"));
EDBM_update_generic(em, true, true);
@@ -159,10 +164,14 @@ void MESH_OT_subdivide(wmOperatorType *ot)
RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Edge Ring Subdiv
- * (bridge code shares props)
- */
+/** \name Edge Ring Subdivide Operator
+ *
+ * Bridge code shares props.
+ *
+ * \{ */
struct EdgeRingOpSubdProps {
int interp_mode;
@@ -224,11 +233,12 @@ static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
mesh_operator_edgering_props_get(op, &op_props);
- if (!EDBM_op_callf(em, op,
- "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
- "profile_shape=%i profile_shape_factor=%f",
- BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
- op_props.profile_shape, op_props.profile_shape_factor))
+ if (!EDBM_op_callf(
+ em, op,
+ "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
+ "profile_shape=%i profile_shape_factor=%f",
+ BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
+ op_props.profile_shape, op_props.profile_shape_factor))
{
return OPERATOR_CANCELLED;
}
@@ -256,6 +266,11 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot)
mesh_operator_edgering_props(ot, 1, 10);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Un-Subdivide Operator
+ * \{ */
static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
{
@@ -337,6 +352,11 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
ED_transform_snap_object_context_destroy(snap_context);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Operator
+ * \{ */
/* Note, these values must match delete_mesh() event values */
enum {
@@ -391,7 +411,7 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -410,13 +430,13 @@ void MESH_OT_delete(wmOperatorType *ot)
ot->name = "Delete";
ot->description = "Delete selected vertices, edges or faces";
ot->idname = "MESH_OT_delete";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = edbm_delete_exec;
-
+
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -425,6 +445,11 @@ void MESH_OT_delete(wmOperatorType *ot)
"Type", "Method used for deleting mesh data");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Loose Operator
+ * \{ */
static bool bm_face_is_loose(BMFace *f)
{
@@ -523,6 +548,11 @@ void MESH_OT_delete_loose(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Collapse Edge Operator
+ * \{ */
static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
{
@@ -552,6 +582,12 @@ void MESH_OT_edge_collapse(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Create Edge/Face Operator
+ * \{ */
+
static bool edbm_add_edge_face__smooth_get(BMesh *bm)
{
BMEdge *e;
@@ -621,8 +657,9 @@ static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
(BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))
)
{
- BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v),
- BM_edge_other_vert(ed_pair[1], v));
+ BMEdge *e_other = BM_edge_exists(
+ BM_edge_other_vert(ed_pair[0], v),
+ BM_edge_other_vert(ed_pair[1], v));
BM_edge_select_set(bm, ed_pair[0], true);
BM_edge_select_set(bm, ed_pair[1], true);
if (e_other) {
@@ -745,13 +782,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
#endif
- if (!EDBM_op_init(em, &bmop, op,
- "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
- BM_ELEM_SELECT, em->mat_nr, use_smooth))
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
+ BM_ELEM_SELECT, em->mat_nr, use_smooth))
{
return OPERATOR_CANCELLED;
}
-
+
BMO_op_exec(em->bm, &bmop);
/* cancel if nothing was done */
@@ -801,16 +839,20 @@ void MESH_OT_edge_face_add(wmOperatorType *ot)
ot->name = "Make Edge/Face";
ot->description = "Add an edge or face to selected";
ot->idname = "MESH_OT_edge_face_add";
-
+
/* api callbacks */
ot->exec = edbm_add_edge_face_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************************* SEAMS AND EDGES **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Edge (Seam) Operator
+ * \{ */
static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
{
@@ -822,7 +864,7 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
BMEdge *eed;
BMIter iter;
const bool clear = RNA_boolean_get(op->ptr, "clear");
-
+
/* auto-enable seams drawing */
if (clear == 0) {
me->drawflag |= ME_DRAWSEAMS;
@@ -832,7 +874,7 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
continue;
-
+
BM_elem_flag_disable(eed, BM_ELEM_SEAM);
}
}
@@ -858,11 +900,11 @@ void MESH_OT_mark_seam(wmOperatorType *ot)
ot->name = "Mark Seam";
ot->idname = "MESH_OT_mark_seam";
ot->description = "(Un)mark selected edges as a seam";
-
+
/* api callbacks */
ot->exec = edbm_mark_seam_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -872,6 +914,12 @@ void MESH_OT_mark_seam(wmOperatorType *ot)
WM_operatortype_props_advanced_begin(ot);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Edge (Sharp) Operator
+ * \{ */
+
static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -914,14 +962,14 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
ot->name = "Mark Sharp";
ot->idname = "MESH_OT_mark_sharp";
ot->description = "(Un)mark selected edges as sharp";
-
+
/* api callbacks */
ot->exec = edbm_mark_sharp_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_verts", false, "Vertices",
@@ -965,17 +1013,19 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
}
if (is_pair) {
- if (!EDBM_op_init(em, &bmop, op,
- "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
- verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
+ verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
{
goto finally;
}
}
else {
- if (!EDBM_op_init(em, &bmop, op,
- "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
- verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
+ verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
{
goto finally;
}
@@ -1012,15 +1062,20 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
ot->name = "Vertex Connect";
ot->idname = "MESH_OT_vert_connect";
ot->description = "Connect selected vertices of faces, splitting the face";
-
+
/* api callbacks */
ot->exec = edbm_vert_connect_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Concave Faces Operator
+ * \{ */
/**
* check that endpoints are verts and only have a single selected edge connected.
@@ -1325,6 +1380,11 @@ void MESH_OT_vert_connect_concave(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Non-Planar Faces Operator
+ * \{ */
static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
{
@@ -1369,6 +1429,12 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Make Planar Faces Operator
+ * \{ */
+
static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -1406,6 +1472,11 @@ void MESH_OT_face_make_planar(wmOperatorType *ot)
RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Edge Operator
+ * \{ */
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
@@ -1420,7 +1491,7 @@ static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
return OPERATOR_CANCELLED;
}
-
+
if (em->selectmode == SCE_SELECT_FACE) {
EDBM_select_flush(em);
}
@@ -1436,16 +1507,20 @@ void MESH_OT_edge_split(wmOperatorType *ot)
ot->name = "Edge Split";
ot->idname = "MESH_OT_edge_split";
ot->description = "Split selected edges so that each neighbor face gets its own copy";
-
+
/* api callbacks */
ot->exec = edbm_edge_split_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/****************** add duplicate operator ***************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Operator
+ * \{ */
static int edbm_duplicate_exec(bContext *C, wmOperator *op)
{
@@ -1476,7 +1551,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
}
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -1485,7 +1560,7 @@ static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
WM_cursor_wait(1);
edbm_duplicate_exec(C, op);
WM_cursor_wait(0);
-
+
return OPERATOR_FINISHED;
}
@@ -1495,29 +1570,34 @@ void MESH_OT_duplicate(wmOperatorType *ot)
ot->name = "Duplicate";
ot->description = "Duplicate selected vertices, edges or faces";
ot->idname = "MESH_OT_duplicate";
-
+
/* api callbacks */
ot->invoke = edbm_duplicate_invoke;
ot->exec = edbm_duplicate_exec;
-
+
ot->poll = ED_operator_editmesh;
-
+
/* to give to transform */
RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flip Normals Operator
+ * \{ */
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
+
if (!EDBM_op_callf(
em, op, "reverse_faces faces=%hf flip_multires=%b",
BM_ELEM_SELECT, true))
{
return OPERATOR_CANCELLED;
}
-
+
EDBM_update_generic(em, true, false);
return OPERATOR_FINISHED;
@@ -1529,15 +1609,21 @@ void MESH_OT_flip_normals(wmOperatorType *ot)
ot->name = "Flip Normals";
ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
ot->idname = "MESH_OT_flip_normals";
-
+
/* api callbacks */
ot->exec = edbm_flip_normals_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rotate Edge Operator
+ * \{ */
+
/**
* Rotate the edges between selected faces, otherwise rotate the selected edges.
*/
@@ -1571,7 +1657,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
}
}
}
-
+
/* ok, we don't have two adjacent faces, but we do have two selected ones.
* that's an error condition.*/
if (tot == 0) {
@@ -1630,12 +1716,17 @@ void MESH_OT_edge_rotate(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
static int edbm_hide_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
+
EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
EDBM_update_generic(em, true, false);
@@ -1649,18 +1740,24 @@ void MESH_OT_hide(wmOperatorType *ot)
ot->name = "Hide Selection";
ot->idname = "MESH_OT_hide";
ot->description = "Hide (un)selected vertices, edges or faces";
-
+
/* api callbacks */
ot->exec = edbm_hide_exec;
ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* props */
RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reveal Operator
+ * \{ */
+
static int edbm_reveal_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -1680,22 +1777,28 @@ void MESH_OT_reveal(wmOperatorType *ot)
ot->name = "Reveal Hidden";
ot->idname = "MESH_OT_reveal";
ot->description = "Reveal all hidden vertices, edges and faces";
-
+
/* api callbacks */
ot->exec = edbm_reveal_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalculate Normals Operator
+ * \{ */
+
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
+
/* doflip has to do with bmesh_rationalize_normals, it's an internal
* thing */
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
@@ -1716,18 +1819,22 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot)
ot->name = "Make Normals Consistent";
ot->description = "Make face and vertex normals point either outside or inside the mesh";
ot->idname = "MESH_OT_normals_make_consistent";
-
+
/* api callbacks */
ot->exec = edbm_normals_make_consistent_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
}
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertex Operator
+ * \{ */
static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
{
@@ -1751,12 +1858,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
}
/* if there is a mirror modifier with clipping, flag the verts that
- * are within tolerance of the plane(s) of reflection
+ * are within tolerance of the plane(s) of reflection
*/
for (md = obedit->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
MirrorModifierData *mmd = (MirrorModifierData *)md;
-
+
if (mmd->flag & MOD_MIR_CLIPPING) {
if (mmd->flag & MOD_MIR_AXIS_X)
mirrx = true;
@@ -1775,10 +1882,11 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
repeat = 1;
for (i = 0; i < repeat; i++) {
- if (!EDBM_op_callf(em, op,
- "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
- "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
- BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
+ if (!EDBM_op_callf(
+ em, op,
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
{
return OPERATOR_CANCELLED;
}
@@ -1793,19 +1901,20 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
EDBM_update_generic(em, true, false);
return OPERATOR_FINISHED;
-}
-
+}
+
+
void MESH_OT_vertices_smooth(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Smooth Vertex";
ot->description = "Flatten angles of selected vertices";
ot->idname = "MESH_OT_vertices_smooth";
-
+
/* api callbacks */
ot->exec = edbm_do_smooth_vertex_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1819,6 +1928,12 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Laplacian Vertex Smooth Operator
+ * \{ */
+
static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -1838,7 +1953,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
if (f->len > 4) {
BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
return OPERATOR_CANCELLED;
- }
+ }
}
}
@@ -1856,11 +1971,12 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
if (!repeat)
repeat = 1;
-
+
for (i = 0; i < repeat; i++) {
- if (!EDBM_op_callf(em, op,
- "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
- BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
+ if (!EDBM_op_callf(
+ em, op,
+ "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
+ BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
{
return OPERATOR_CANCELLED;
}
@@ -1883,11 +1999,11 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
ot->name = "Laplacian Smooth Vertex";
ot->description = "Laplacian smooth of selected vertices";
ot->idname = "MESH_OT_vertices_smooth_laplacian";
-
+
/* api callbacks */
ot->exec = edbm_do_smooth_laplacian_vertex_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1906,7 +2022,11 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth");
}
-/********************** Smooth/Solid Operators *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Faces Smooth Shading Operator
+ * \{ */
static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
{
@@ -1914,7 +2034,7 @@ static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
BMFace *efa;
if (em == NULL) return;
-
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth);
@@ -1949,6 +2069,12 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Faces Flat Shading Operator
+ * \{ */
+
static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
@@ -1976,8 +2102,11 @@ void MESH_OT_faces_shade_flat(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
-/********************** UV/Color Operators *************************/
+/* -------------------------------------------------------------------- */
+/** \name UV/Color Rotate/Reverse Operator
+ * \{ */
static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
{
@@ -2147,6 +2276,11 @@ void MESH_OT_colors_reverse(wmOperatorType *ot)
//RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge Vertices Operator
+ * \{ */
enum {
MESH_MERGE_LAST = 1,
@@ -2183,7 +2317,7 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use
if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT))
return false;
-
+
if (use_uvmerge) {
if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert))
return false;
@@ -2195,8 +2329,9 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use
return true;
}
-static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
- const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
+static bool merge_target(
+ BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
+ const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
{
BMIter iter;
BMVert *v;
@@ -2217,7 +2352,7 @@ static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
add_v3_v3(cent, v->co);
i++;
}
-
+
if (!i)
return false;
@@ -2229,7 +2364,7 @@ static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
if (!vco)
return false;
-
+
if (use_uvmerge) {
if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT))
return false;
@@ -2296,14 +2431,14 @@ static const EnumPropertyItem merge_type_items[] = {
};
static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
+{
Object *obedit;
EnumPropertyItem *item = NULL;
int totitem = 0;
-
+
if (!C) /* needed for docs */
return merge_type_items;
-
+
obedit = CTX_data_edit_object(C);
if (obedit && obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -2333,7 +2468,7 @@ static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(
return item;
}
-
+
return NULL;
}
@@ -2361,6 +2496,11 @@ void MESH_OT_merge(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Doubles Operator
+ * \{ */
static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
{
@@ -2383,9 +2523,10 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
if (use_unselected) {
- EDBM_op_init(em, &bmop, op,
- "automerge verts=%hv dist=%f",
- BM_ELEM_SELECT, threshold);
+ EDBM_op_init(
+ em, &bmop, op,
+ "automerge verts=%hv dist=%f",
+ BM_ELEM_SELECT, threshold);
BMO_op_exec(em->bm, &bmop);
if (!EDBM_op_finish(em, &bmop, op, true)) {
@@ -2393,9 +2534,10 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
}
}
else {
- EDBM_op_init(em, &bmop, op,
- "find_doubles verts=%hv dist=%f",
- BM_ELEM_SELECT, threshold);
+ EDBM_op_init(
+ em, &bmop, op,
+ "find_doubles verts=%hv dist=%f",
+ BM_ELEM_SELECT, threshold);
BMO_op_exec(em->bm, &bmop);
if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
@@ -2407,7 +2549,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
}
-
+
count = totvert_orig - em->bm->totvert;
BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count);
@@ -2439,8 +2581,11 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
}
+/** \} */
-/************************ Shape Operators *************************/
+/* -------------------------------------------------------------------- */
+/** \name Shape Key Propagate Operator
+ * \{ */
/* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
static void shape_propagate(BMEditMesh *em, wmOperator *op)
@@ -2454,7 +2599,7 @@ static void shape_propagate(BMEditMesh *em, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
return;
}
-
+
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
continue;
@@ -2505,6 +2650,12 @@ void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend from Shape Operator
+ * \{ */
+
/* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
{
@@ -2531,23 +2682,23 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
if (key) {
kb = BLI_findlink(&key->block, shape);
}
-
+
/* perform blending on selected vertices*/
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
continue;
-
+
/* get coordinates of shapekey we're blending from */
sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
copy_v3_v3(co, sco);
-
+
if (use_add) {
/* in add mode, we add relative shape key offset */
if (kb) {
const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
sub_v3_v3v3(co, co, rco);
}
-
+
madd_v3_v3fl(eve->co, co, blend);
}
else {
@@ -2562,7 +2713,7 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
}
static const EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
+{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em;
EnumPropertyItem *item = NULL;
@@ -2635,6 +2786,12 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Solidify Mesh Operator
+ * \{ */
+
static int edbm_solidify_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -2689,6 +2846,12 @@ void MESH_OT_solidify(wmOperatorType *ot)
RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Knife Subdivide Operator
+ * \{ */
+
/* ******************************************************************** */
/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
* drawn by user.
@@ -2722,8 +2885,9 @@ static const EnumPropertyItem knife_items[] = {
/* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
-static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
- float (*mouse_path)[2], int len, char mode, int *isected)
+static float bm_edge_seg_isect(
+ const float sco_a[2], const float sco_b[2],
+ float (*mouse_path)[2], int len, char mode, int *isected)
{
#define MAXSLOPE 100000
float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
@@ -2732,17 +2896,17 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
float yi, x1min, x1max, y1max, y1min, perc = 0;
float threshold = 0.0;
int i;
-
+
//threshold = 0.000001; /* tolerance for vertex intersection */
// XXX threshold = scene->toolsettings->select_thresh / 100;
-
+
/* Get screen coords of verts */
x21 = sco_a[0];
y21 = sco_a[1];
-
+
x22 = sco_b[0];
y22 = sco_b[1];
-
+
xdiff2 = (x22 - x21);
if (xdiff2) {
m2 = (y22 - y21) / xdiff2;
@@ -2768,7 +2932,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
}
x12 = mouse_path[i][0];
y12 = mouse_path[i][1];
-
+
/* test e->v1 */
if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
perc = 0;
@@ -2783,7 +2947,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
}
}
}
-
+
/* now check for edge intersect (may produce vertex intersection as well) */
for (i = 0; i < len; i++) {
if (i > 0) {
@@ -2796,14 +2960,14 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
}
x12 = mouse_path[i][0];
y12 = mouse_path[i][1];
-
+
/* Perp. Distance from point to line */
if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2); /* /sqrt(m2 * m2 + 1); Only looking for */
/* change in sign. Skip extra math */
else dist = x22 - x12;
-
+
if (i == 0) lastdist = dist;
-
+
/* if dist changes sign, and intersect point in edge's Bound Box */
if ((lastdist * dist) <= 0) {
xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
@@ -2819,14 +2983,14 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */
y2max = max_ff(y21, y22) + 0.001f;
y2min = min_ff(y21, y22) - 0.001f;
-
+
/* Found an intersect, calc intersect point */
if (m1 == m2) { /* co-incident lines */
/* cut at 50% of overlap area */
x1max = max_ff(x11, x12);
x1min = min_ff(x11, x12);
xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;
-
+
y1max = max_ff(y11, y12);
y1min = min_ff(y11, y12);
yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f;
@@ -2843,7 +3007,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
xi = (b1 - b2) / (m2 - m1);
yi = (b1 * m2 - m1 * b2) / (m2 - m1);
}
-
+
/* Intersect inside bounding box of edge?*/
if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
/* test for vertex intersect that may be 'close enough'*/
@@ -2866,7 +3030,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21);
else perc = (yi - y21) / (y22 - y21); /* lower slope more accurate */
//isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
-
+
break;
}
}
@@ -2895,11 +3059,11 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
/* allocd vars */
float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
-
+
/* edit-object needed for matrix, and ar->regiondata for projections to work */
if (ELEM(NULL, obedit, ar, ar->regiondata))
return OPERATOR_CANCELLED;
-
+
if (bm->totvertsel < 2) {
BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on");
return OPERATOR_CANCELLED;
@@ -2984,7 +3148,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
BMO_slot_float_set(bmop.slots_in, "radius", 0);
-
+
BMO_op_exec(bm, &bmop);
if (!EDBM_op_finish(em, &bmop, op, true)) {
return OPERATOR_CANCELLED;
@@ -3002,13 +3166,13 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
ot->name = "Knife Cut";
ot->description = "Cut selected edges and faces into parts";
ot->idname = "MESH_OT_knife_cut";
-
+
ot->invoke = WM_gesture_lines_invoke;
ot->modal = WM_gesture_lines_modal;
ot->exec = edbm_knife_cut_exec;
-
+
ot->poll = EDBM_view3d_poll;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -3018,13 +3182,16 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
-
+
/* internal */
RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
}
+/** \} */
-/* *************** Operator: separate parts *************/
+/* -------------------------------------------------------------------- */
+/** \name Separate Parts Operator
+ * \{ */
enum {
MESH_SEPARATE_SELECTED = 0,
@@ -3075,7 +3242,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, ViewLayer *view_lay
BM_mesh_free(bm_new);
((Mesh *)base_new->object->data)->edit_btmesh = NULL;
-
+
return base_new;
}
@@ -3304,7 +3471,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
const int type = RNA_enum_get(op->ptr, "type");
int retval = 0;
-
+
if (ED_operator_editmesh(C)) {
Base *base = CTX_data_active_base(C);
BMEditMesh *em = BKE_editmesh_from_object(base->object);
@@ -3417,18 +3584,23 @@ void MESH_OT_separate(wmOperatorType *ot)
ot->name = "Separate";
ot->description = "Separate selected geometry into a new mesh";
ot->idname = "MESH_OT_separate";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = edbm_separate_exec;
ot->poll = ED_operator_scene_editable; /* object and editmode */
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Triangle Fill Operator
+ * \{ */
static int edbm_fill_exec(bContext *C, wmOperator *op)
{
@@ -3450,9 +3622,9 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
{
return OPERATOR_CANCELLED;
}
-
+
BMO_op_exec(em->bm, &bmop);
-
+
if (totface_orig != em->bm->totface) {
/* select new geometry */
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
@@ -3490,9 +3662,11 @@ void MESH_OT_fill(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division");
}
+/** \} */
/* -------------------------------------------------------------------- */
-/* Grid Fill (and helper functions) */
+/** \name Grid Fill Operator
+ * \{ */
static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
{
@@ -3683,10 +3857,11 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
/* end tricky prepare code */
- if (!EDBM_op_init(em, &bmop, op,
- "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
- use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
- em->mat_nr, use_smooth, use_interp_simple))
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
+ use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
+ em->mat_nr, use_smooth, use_interp_simple))
{
return OPERATOR_CANCELLED;
}
@@ -3736,6 +3911,12 @@ void MESH_OT_fill_grid(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hole Fill Operator
+ * \{ */
+
static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -3775,6 +3956,12 @@ void MESH_OT_fill_holes(wmOperatorType *ot)
"Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Beauty Fill Operator
+ * \{ */
+
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -3792,9 +3979,10 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
BMEdge *e;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
- BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
+ BM_elem_flag_set(
+ e, BM_ELEM_TAG,
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+ BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
}
@@ -3810,7 +3998,7 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
}
EDBM_update_generic(em, true, true);
-
+
return OPERATOR_FINISHED;
}
@@ -3836,8 +4024,11 @@ void MESH_OT_beautify_fill(wmOperatorType *ot)
RNA_def_property_float_default(prop, DEG2RADF(180.0f));
}
+/** \} */
-/********************** Poke Face **********************/
+/* -------------------------------------------------------------------- */
+/** \name Poke Face Operator
+ * \{ */
static int edbm_poke_face_exec(bContext *C, wmOperator *op)
{
@@ -3897,7 +4088,11 @@ void MESH_OT_poke(wmOperatorType *ot)
"Poke Center", "Poke Face Center Calculation");
}
-/********************** Quad/Tri Operators *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Triangulate Face Operator
+ * \{ */
static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
{
@@ -3952,6 +4147,12 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
"Polygon Method", "Method for splitting the polygons into triangles");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Convert to Quads Operator
+ * \{ */
+
static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -4042,10 +4243,10 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
join_triangle_props(ot);
}
+/** \} */
/* -------------------------------------------------------------------- */
-
-/** \name Decimate
+/** \name Decimate Operator
*
* \note The function to decimate is intended for use as a modifier,
* while its handy allow access as a tool - this does cause access to be a little awkward
@@ -4231,9 +4432,9 @@ void MESH_OT_decimate(wmOperatorType *ot)
/** \} */
-
/* -------------------------------------------------------------------- */
-/* Dissolve */
+/** \name Dissolve Vertices Operator
+ * \{ */
static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
{
@@ -4265,9 +4466,10 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
- if (!EDBM_op_callf(em, op,
- "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
- BM_ELEM_SELECT, use_face_split, use_boundary_tear))
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_SELECT, use_face_split, use_boundary_tear))
{
return OPERATOR_CANCELLED;
}
@@ -4295,6 +4497,12 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot)
edbm_dissolve_prop__use_boundary_tear(ot);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Edges Operator
+ * \{ */
+
static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -4303,9 +4511,10 @@ static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
- if (!EDBM_op_callf(em, op,
- "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
- BM_ELEM_SELECT, use_verts, use_face_split))
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
+ BM_ELEM_SELECT, use_verts, use_face_split))
{
return OPERATOR_CANCELLED;
}
@@ -4333,6 +4542,12 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot)
edbm_dissolve_prop__use_face_split(ot);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Faces Operator
+ * \{ */
+
static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -4371,6 +4586,11 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot)
edbm_dissolve_prop__use_verts(ot, false, 0);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve (Context Sensitive) Operator
+ * \{ */
static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op)
{
@@ -4416,6 +4636,12 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
edbm_dissolve_prop__use_boundary_tear(ot);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Limited Dissolve Operator
+ * \{ */
+
static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -4493,6 +4719,12 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
"Delimit dissolve operation");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Degenerate Dissolve Operator
+ * \{ */
+
static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -4537,6 +4769,11 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
"Minimum distance between elements to merge", 1e-5f, 10.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Edge-Loop Operator
+ * \{ */
/* internally uses dissolve */
static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
@@ -4563,9 +4800,10 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
}
}
- if (!EDBM_op_callf(em, op,
- "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
- BM_ELEM_SELECT, true, use_face_split))
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
+ BM_ELEM_SELECT, true, use_face_split))
{
return OPERATOR_CANCELLED;
}
@@ -4597,6 +4835,12 @@ void MESH_OT_delete_edgeloop(wmOperatorType *ot)
"Split off face corners to maintain surrounding geometry");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Geometry Operator
+ * \{ */
+
static int edbm_split_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
@@ -4634,16 +4878,21 @@ void MESH_OT_split(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************************************************************************
- * qsort routines.
- * Now unified, for vertices/edges/faces. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sort Geometry Elements Operator
+ *
+ * Unified for vertices/edges/faces.
+ *
+ * \{ */
enum {
SRT_VIEW_ZAXIS = 1, /* Use view Z (deep) axis. */
SRT_VIEW_XAXIS, /* Use view X (left to right) axis. */
SRT_CURSOR_DISTANCE, /* Use distance from element to 3D cursor. */
SRT_MATERIAL, /* Face only: use mat number. */
- SRT_SELECTED, /* Move selected elements in first, without modifying
+ SRT_SELECTED, /* Move selected elements in first, without modifying
* relative order of selected and unselected elements. */
SRT_RANDOMIZE, /* Randomize selected elements. */
SRT_REVERSE, /* Reverse current order of selected elements. */
@@ -4662,10 +4911,11 @@ static int bmelemsort_comp(const void *v1, const void *v2)
}
/* Reorders vertices/edges/faces using a given methods. Loops are not supported. */
-static void sort_bmelem_flag(Scene *scene, Object *ob,
- View3D *v3d, RegionView3D *rv3d,
- const int types, const int flag, const int action,
- const int reverse, const unsigned int seed)
+static void sort_bmelem_flag(
+ Scene *scene, Object *ob,
+ View3D *v3d, RegionView3D *rv3d,
+ const int types, const int flag, const int action,
+ const int reverse, const unsigned int seed)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -5131,8 +5381,9 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
RNA_enum_set(op->ptr, "elements", elem_types);
}
- sort_bmelem_flag(scene, ob, v3d, rv3d,
- elem_types, BM_ELEM_SELECT, action, use_reverse, seed);
+ sort_bmelem_flag(
+ scene, ob, v3d, rv3d,
+ elem_types, BM_ELEM_SELECT, action, use_reverse, seed);
return OPERATOR_FINISHED;
}
@@ -5221,7 +5472,11 @@ void MESH_OT_sort_elements(wmOperatorType *ot)
RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
}
-/****** end of qsort stuff ****/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Noise (Deform Vertices) Operator
+ * \{ */
static int edbm_noise_exec(bContext *C, wmOperator *op)
{
@@ -5254,7 +5509,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
vec[0] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0] + ofs, eve->co[1], eve->co[2]));
vec[1] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1] + ofs, eve->co[2]));
vec[2] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2] + ofs));
-
+
add_v3_v3(eve->co, vec);
}
}
@@ -5295,6 +5550,11 @@ void MESH_OT_noise(wmOperatorType *ot)
RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bridge Operator
+ * \{ */
enum {
MESH_BRIDGELOOP_SINGLE = 0,
@@ -5381,9 +5641,10 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
edge_hflag = BM_ELEM_SELECT;
}
- EDBM_op_init(em, &bmop, op,
- "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
- edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
+ EDBM_op_init(
+ em, &bmop, op,
+ "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
+ edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
if (use_faces && totface_del) {
int i;
@@ -5391,9 +5652,10 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
for (i = 0; i < totface_del; i++) {
BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
}
- BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
- "delete geom=%hf context=%i",
- BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
+ BMO_op_callf(
+ em->bm, BMO_FLAG_DEFAULTS,
+ "delete geom=%hf context=%i",
+ BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
}
BMO_op_exec(em->bm, &bmop);
@@ -5459,11 +5721,11 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
ot->name = "Bridge Edge Loops";
ot->description = "Make faces between two or more edge loops";
ot->idname = "MESH_OT_bridge_edge_loops";
-
+
/* api callbacks */
ot->exec = edbm_bridge_edge_loops_exec;
ot->poll = ED_operator_editmesh;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -5477,6 +5739,12 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
mesh_operator_edgering_props(ot, 0, 0);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Wire-Frame Operator
+ * \{ */
+
static int edbm_wireframe_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -5491,11 +5759,12 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op)
const float thickness = RNA_float_get(op->ptr, "thickness");
const float offset = RNA_float_get(op->ptr, "offset");
- EDBM_op_init(em, &bmop, op,
- "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b "
- "use_crease=%b crease_weight=%f thickness=%f offset=%f",
- BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset,
- use_crease, crease_weight, thickness, offset);
+ EDBM_op_init(
+ em, &bmop, op,
+ "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b "
+ "use_crease=%b crease_weight=%f thickness=%f offset=%f",
+ BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset,
+ use_crease, crease_weight, thickness, offset);
BMO_op_exec(em->bm, &bmop);
@@ -5541,6 +5810,12 @@ void MESH_OT_wireframe(wmOperatorType *ot)
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Offset Edge-Loop Operator
+ * \{ */
+
static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -5595,6 +5870,12 @@ void MESH_OT_offset_edge_loops(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Convex Hull Operator
+ * \{ */
+
#ifdef WITH_BULLET
static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
{
@@ -5602,10 +5883,11 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMOperator bmop;
- EDBM_op_init(em, &bmop, op, "convex_hull input=%hvef "
- "use_existing_faces=%b",
- BM_ELEM_SELECT,
- RNA_boolean_get(op->ptr, "use_existing_faces"));
+ EDBM_op_init(
+ em, &bmop, op, "convex_hull input=%hvef "
+ "use_existing_faces=%b",
+ BM_ELEM_SELECT,
+ RNA_boolean_get(op->ptr, "use_existing_faces"));
BMO_op_exec(em->bm, &bmop);
/* Hull fails if input is coplanar */
@@ -5618,8 +5900,9 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
/* Delete unused vertices, edges, and faces */
if (RNA_boolean_get(op->ptr, "delete_unused")) {
- if (!EDBM_op_callf(em, op, "delete geom=%S context=%i",
- &bmop, "geom_unused.out", DEL_ONLYTAGGED))
+ if (!EDBM_op_callf(
+ em, op, "delete geom=%S context=%i",
+ &bmop, "geom_unused.out", DEL_ONLYTAGGED))
{
EDBM_op_finish(em, &bmop, op, true);
return OPERATOR_CANCELLED;
@@ -5628,8 +5911,9 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
/* Delete hole edges/faces */
if (RNA_boolean_get(op->ptr, "make_holes")) {
- if (!EDBM_op_callf(em, op, "delete geom=%S context=%i",
- &bmop, "geom_holes.out", DEL_ONLYTAGGED))
+ if (!EDBM_op_callf(
+ em, op, "delete geom=%S context=%i",
+ &bmop, "geom_holes.out", DEL_ONLYTAGGED))
{
EDBM_op_finish(em, &bmop, op, true);
return OPERATOR_CANCELLED;
@@ -5697,7 +5981,13 @@ void MESH_OT_convex_hull(wmOperatorType *ot)
join_triangle_props(ot);
}
-#endif
+#endif /* WITH_BULLET */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Symmetrize Operator
+ * \{ */
static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
{
@@ -5707,9 +5997,10 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
const float thresh = RNA_float_get(op->ptr, "threshold");
- EDBM_op_init(em, &bmop, op,
- "symmetrize input=%hvef direction=%i dist=%f",
- BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh);
+ EDBM_op_init(
+ em, &bmop, op,
+ "symmetrize input=%hvef direction=%i dist=%f",
+ BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh);
BMO_op_exec(em->bm, &bmop);
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -5740,12 +6031,19 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items,
- BMO_SYMMETRIZE_NEGATIVE_X,
- "Direction", "Which sides to copy from and to");
+ ot->prop = RNA_def_enum(
+ ot->srna, "direction", rna_enum_symmetrize_direction_items,
+ BMO_SYMMETRIZE_NEGATIVE_X,
+ "Direction", "Which sides to copy from and to");
RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap to Symmetry Operator
+ * \{ */
+
static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
{
const float eps = 0.00001f;
@@ -5864,16 +6162,23 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items,
- BMO_SYMMETRIZE_NEGATIVE_X,
- "Direction", "Which sides to copy from and to");
+ ot->prop = RNA_def_enum(
+ ot->srna, "direction", rna_enum_symmetrize_direction_items,
+ BMO_SYMMETRIZE_NEGATIVE_X,
+ "Direction", "Which sides to copy from and to");
RNA_def_float_distance(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center");
}
+/** \} */
+
#ifdef WITH_FREESTYLE
+/* -------------------------------------------------------------------- */
+/** \name Mark Edge (FreeStyle) Operator
+ * \{ */
+
static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -5939,6 +6244,12 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Face (FreeStyle) Operator
+ * \{ */
+
static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -6003,4 +6314,6 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-#endif
+/** \} */
+
+#endif /* WITH_FREESTYLE */
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 7b727e75b55..312dc000a2b 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -64,8 +64,14 @@
#include "mesh_intern.h" /* own include */
-/* mesh backup implementation. This would greatly benefit from some sort of binary diffing
- * just as the undo stack would. So leaving this as an interface for further work */
+/* -------------------------------------------------------------------- */
+/** \name Redo API
+ * \{ */
+
+/* Mesh backup implementation.
+ * This would greatly benefit from some sort of binary diffing
+ * just as the undo stack would.
+ * So leaving this as an interface for further work */
BMBackup EDBM_redo_state_store(BMEditMesh *em)
{
@@ -77,8 +83,9 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em)
void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
{
BMesh *tmpbm;
- if (!em || !backup.bmcopy)
+ if (!em || !backup.bmcopy) {
return;
+ }
BM_mesh_data_free(em->bm);
tmpbm = BM_mesh_copy(backup.bmcopy);
@@ -86,8 +93,9 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
MEM_freeN(tmpbm);
tmpbm = NULL;
- if (recalctess)
+ if (recalctess) {
BKE_editmesh_tessface_calc(em);
+ }
}
void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
@@ -100,68 +108,21 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
BM_mesh_data_free(backup->bmcopy);
}
- if (backup->bmcopy)
+ if (backup->bmcopy) {
MEM_freeN(backup->bmcopy);
+ }
backup->bmcopy = NULL;
- if (recalctess && em)
+ if (recalctess && em) {
BKE_editmesh_tessface_calc(em);
-}
-
-void EDBM_mesh_normals_update(BMEditMesh *em)
-{
- BM_mesh_normals_update(em->bm);
-}
-
-void EDBM_mesh_clear(BMEditMesh *em)
-{
- /* clear bmesh */
- BM_mesh_clear(em->bm);
-
- /* free derived meshes */
- BKE_editmesh_free_derivedmesh(em);
-
- /* free tessellation data */
- em->tottri = 0;
- if (em->looptris) {
- MEM_freeN(em->looptris);
- em->looptris = NULL;
}
}
-void EDBM_stats_update(BMEditMesh *em)
-{
- const char iter_types[3] = {BM_VERTS_OF_MESH,
- BM_EDGES_OF_MESH,
- BM_FACES_OF_MESH};
-
- BMIter iter;
- BMElem *ele;
- int *tots[3];
- int i;
+/** \} */
- tots[0] = &em->bm->totvertsel;
- tots[1] = &em->bm->totedgesel;
- tots[2] = &em->bm->totfacesel;
-
- em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
-
- for (i = 0; i < 3; i++) {
- ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
- for ( ; ele; ele = BM_iter_step(&iter)) {
- if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
- (*tots[i])++;
- }
- }
- }
-}
-
-DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
-{
- return ((em->derivedFinal != NULL) &&
- (em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
- (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
-}
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator (BMO) API Wrapper
+ * \{ */
bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
{
@@ -175,9 +136,10 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
va_end(list);
return false;
}
-
- if (!em->emcopy)
+
+ if (!em->emcopy) {
em->emcopy = BKE_editmesh_copy(em);
+ }
em->emcopyusers++;
va_end(list);
@@ -185,12 +147,11 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
return true;
}
-
/* returns 0 on error, 1 on success. executes and finishes a bmesh operator */
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
{
const char *errmsg;
-
+
BMO_op_finish(em->bm, bmop);
if (BMO_error_get(em->bm, &errmsg, NULL)) {
@@ -245,8 +206,9 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
return false;
}
- if (!em->emcopy)
+ if (!em->emcopy) {
em->emcopy = BKE_editmesh_copy(em);
+ }
em->emcopyusers++;
BMO_op_exec(bm, &bmop);
@@ -255,9 +217,10 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
return EDBM_op_finish(em, &bmop, op, true);
}
-bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op,
- const char *select_slot_out, const bool select_extend,
- const char *fmt, ...)
+bool EDBM_op_call_and_selectf(
+ BMEditMesh *em, wmOperator *op,
+ const char *select_slot_out, const bool select_extend,
+ const char *fmt, ...)
{
BMOpSlot *slot_select_out;
BMesh *bm = em->bm;
@@ -273,8 +236,9 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op,
return false;
}
- if (!em->emcopy)
+ if (!em->emcopy) {
em->emcopy = BKE_editmesh_copy(em);
+ }
em->emcopyusers++;
BMO_op_exec(bm, &bmop);
@@ -306,8 +270,9 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
return false;
}
- if (!em->emcopy)
+ if (!em->emcopy) {
em->emcopy = BKE_editmesh_copy(em);
+ }
em->emcopyusers++;
BMO_op_exec(bm, &bmop);
@@ -316,22 +281,15 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
return EDBM_op_finish(em, &bmop, NULL, false);
}
-void EDBM_selectmode_to_scene(bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (!em)
- return;
+/** \} */
- scene->toolsettings->selectmode = em->selectmode;
-
- /* Request redraw of header buttons (to show new select mode) */
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
-}
+/* -------------------------------------------------------------------- */
+/** \name Edit BMesh API
+ *
+ * Make/Clear/Free functions.
+ * \{ */
-void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
+void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
{
Mesh *me = ob->data;
BMesh *bm;
@@ -358,7 +316,7 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
me->edit_btmesh = BKE_editmesh_create(bm, false);
#endif
- me->edit_btmesh->selectmode = me->edit_btmesh->bm->selectmode = ts->selectmode;
+ me->edit_btmesh->selectmode = me->edit_btmesh->bm->selectmode = select_mode;
me->edit_btmesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
me->edit_btmesh->ob = ob;
@@ -413,6 +371,22 @@ void EDBM_mesh_load(Object *ob)
#endif
}
+void EDBM_mesh_clear(BMEditMesh *em)
+{
+ /* clear bmesh */
+ BM_mesh_clear(em->bm);
+
+ /* free derived meshes */
+ BKE_editmesh_free_derivedmesh(em);
+
+ /* free tessellation data */
+ em->tottri = 0;
+ if (em->looptris) {
+ MEM_freeN(em->looptris);
+ em->looptris = NULL;
+ }
+}
+
/**
* Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
*/
@@ -427,6 +401,28 @@ void EDBM_mesh_free(BMEditMesh *em)
BKE_editmesh_free(em);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Utilities
+ * \{ */
+
+void EDBM_selectmode_to_scene(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!em) {
+ return;
+ }
+
+ scene->toolsettings->selectmode = em->selectmode;
+
+ /* Request redraw of header buttons (to show new select mode) */
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
+}
+
void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
{
BM_mesh_select_mode_flush_ex(em->bm, selectmode);
@@ -444,7 +440,6 @@ void EDBM_deselect_flush(BMEditMesh *em)
BM_mesh_deselect_flush(em->bm);
}
-
void EDBM_select_flush(BMEditMesh *em)
{
/* function below doesnt use. just do this to keep the values in sync */
@@ -457,9 +452,10 @@ void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
BMOperator bmop;
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
- BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
- "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
- BM_ELEM_SELECT, false, use_faces, use_face_step);
+ BMO_op_initf(
+ em->bm, &bmop, BMO_FLAG_DEFAULTS,
+ "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
+ BM_ELEM_SELECT, false, use_faces, use_face_step);
BMO_op_exec(em->bm, &bmop);
/* don't flush selection in edge/vertex mode */
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
@@ -473,9 +469,10 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
BMOperator bmop;
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
- BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
- "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
- BM_ELEM_SELECT, true, use_faces, use_face_step);
+ BMO_op_initf(
+ em->bm, &bmop, BMO_FLAG_DEFAULTS,
+ "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
+ BM_ELEM_SELECT, true, use_faces, use_face_step);
BMO_op_exec(em->bm, &bmop);
/* don't flush selection in edge/vertex mode */
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
@@ -497,6 +494,12 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Vertex Map API
+ * \{ */
+
/**
* Return a new UVVertMap from the editmesh
*/
@@ -519,7 +522,7 @@ UvVertMap *BM_uv_vert_map_create(
BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
-
+
totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
@@ -549,7 +552,7 @@ UvVertMap *BM_uv_vert_map_create(
BKE_mesh_uv_vert_map_free(vmap);
return NULL;
}
-
+
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
float (*tf_uv)[2];
@@ -562,7 +565,7 @@ UvVertMap *BM_uv_vert_map_create(
buf->tfindex = i;
buf->f = a;
buf->separate = 0;
-
+
buf->next = vmap->vert[BM_elem_index_get(l->v)];
vmap->vert[BM_elem_index_get(l->v)] = buf;
buf++;
@@ -578,7 +581,7 @@ UvVertMap *BM_uv_vert_map_create(
}
}
}
-
+
/* sort individual uvs for each vert */
BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
@@ -592,22 +595,21 @@ UvVertMap *BM_uv_vert_map_create(
newvlist = v;
efa = BM_face_at_index(bm, v->f);
-
+
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
uv = luv->uv;
-
+
lastv = NULL;
iterv = vlist;
while (iterv) {
next = iterv->next;
efa = BM_face_at_index(bm, iterv->f);
-
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
uv2 = luv->uv;
-
+
sub_v2_v2v2(uvdiff, uv2, uv);
if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] &&
@@ -640,13 +642,11 @@ UvVertMap *BM_uv_vert_map_create(
return vmap;
}
-
UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
{
return vmap->vert[v];
}
-
/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(
BMesh *bm,
@@ -904,26 +904,34 @@ void BM_uv_element_map_free(UvElementMap *element_map)
UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
{
- UvElement *element;
-
- element = map->vert[BM_elem_index_get(l->v)];
-
- for (; element; element = element->next)
- if (element->l->f == efa)
+ for (UvElement *element = map->vert[BM_elem_index_get(l->v)];
+ element;
+ element = element->next)
+ {
+ if (element->l->f == efa) {
return element;
+ }
+ }
return NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Layer Checks
+ * \{ */
+
/* last_sel, use em->act_face otherwise get the last selected face in the editselections
* at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */
BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
{
BMFace *efa = NULL;
-
- if (!EDBM_uv_check(em))
+
+ if (!EDBM_uv_check(em)) {
return NULL;
-
+ }
+
efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
if (efa) {
@@ -947,6 +955,12 @@ bool EDBM_vert_color_check(BMEditMesh *em)
return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mirror Cache API
+ * \{ */
+
static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
{
intptr_t eve_i = index_lookup[index];
@@ -981,9 +995,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
* \param maxdist Distance for close point test.
* \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts).
*/
-void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select,
- /* extra args */
- const bool use_topology, float maxdist, int *r_index)
+void EDBM_verts_mirror_cache_begin_ex(
+ BMEditMesh *em, const int axis, const bool use_self, const bool use_select,
+ /* extra args */
+ const bool use_topology, float maxdist, int *r_index)
{
Mesh *me = (Mesh *)em->ob->data;
BMesh *bm = em->bm;
@@ -1007,8 +1022,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
}
- cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT,
- em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
+ cd_vmirr_offset = CustomData_get_n_offset(
+ &bm->vdata, CD_PROP_INT,
+ em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY;
}
@@ -1081,14 +1097,16 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
}
}
-void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis,
- const bool use_self, const bool use_select,
- const bool use_topology)
+void EDBM_verts_mirror_cache_begin(
+ BMEditMesh *em, const int axis,
+ const bool use_self, const bool use_select,
+ const bool use_topology)
{
- EDBM_verts_mirror_cache_begin_ex(em, axis,
- use_self, use_select,
- /* extra args */
- use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
+ EDBM_verts_mirror_cache_begin_ex(
+ em, axis,
+ use_self, use_select,
+ /* extra args */
+ use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
}
BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
@@ -1176,6 +1194,11 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide/Reveal API
+ * \{ */
/* swap is 0 or 1, if 1 it hides not selected */
void EDBM_mesh_hide(BMEditMesh *em, bool swap)
@@ -1210,17 +1233,18 @@ void EDBM_mesh_hide(BMEditMesh *em, bool swap)
*/
}
-
void EDBM_mesh_reveal(BMEditMesh *em, bool select)
{
- const char iter_types[3] = {BM_VERTS_OF_MESH,
- BM_EDGES_OF_MESH,
- BM_FACES_OF_MESH};
+ const char iter_types[3] = {
+ BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH,
+ };
const bool sels[3] = {
- (em->selectmode & SCE_SELECT_VERTEX) != 0,
- (em->selectmode & SCE_SELECT_EDGE) != 0,
- (em->selectmode & SCE_SELECT_FACE) != 0,
+ (em->selectmode & SCE_SELECT_VERTEX) != 0,
+ (em->selectmode & SCE_SELECT_EDGE) != 0,
+ (em->selectmode & SCE_SELECT_FACE) != 0,
};
int i;
@@ -1260,6 +1284,46 @@ void EDBM_mesh_reveal(BMEditMesh *em, bool select)
EDBM_mesh_normals_update(em);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update API
+ * \{ */
+
+void EDBM_mesh_normals_update(BMEditMesh *em)
+{
+ BM_mesh_normals_update(em->bm);
+}
+
+void EDBM_stats_update(BMEditMesh *em)
+{
+ const char iter_types[3] = {
+ BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH,
+ };
+
+ BMIter iter;
+ BMElem *ele;
+ int *tots[3];
+ int i;
+
+ tots[0] = &em->bm->totvertsel;
+ tots[1] = &em->bm->totedgesel;
+ tots[2] = &em->bm->totfacesel;
+
+ em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
+
+ for (i = 0; i < 3; i++) {
+ ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
+ for ( ; ele; ele = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+ (*tots[i])++;
+ }
+ }
+ }
+}
+
/* so many tools call these that we better make it a generic function.
*/
void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive)
@@ -1295,15 +1359,41 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
#endif
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Access
+ * \{ */
+
+DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
+{
+ return ((em->derivedFinal != NULL) &&
+ (em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
+ (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Helpers
+ * \{ */
+
/* poll call for mesh operators requiring a view3d context */
int EDBM_view3d_poll(bContext *C)
{
- if (ED_operator_editmesh(C) && ED_operator_view3d_active(C))
+ if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
return 1;
+ }
return 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Element API
+ * \{ */
+
BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
{
BMElem *ele = NULL;
@@ -1368,22 +1458,19 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index)
return NULL;
}
-/* -------------------------------------------------------------------- */
-/* BMBVH functions */
-// XXX
-#if 0 //BMESH_TODO: not implemented yet
-int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
-{
+/** \} */
-}
-#endif
+/* -------------------------------------------------------------------- */
+/** \name BMesh BVH API
+ * \{ */
static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
{
BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL);
- if (f && BM_edge_in_face(e, f))
+ if (f && BM_edge_in_face(e, f)) {
return NULL;
+ }
return f;
}
@@ -1404,8 +1491,10 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e,
float origin[3], invmat[4][4];
float epsilon = 0.01f;
float end[3];
- const float mval_f[2] = {ar->winx / 2.0f,
- ar->winy / 2.0f};
+ const float mval_f[2] = {
+ ar->winx / 2.0f,
+ ar->winy / 2.0f,
+ };
ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false);
@@ -1441,12 +1530,17 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e,
/* do three samplings: left, middle, right */
f = edge_ray_cast(tree, co1, dir1, NULL, e);
- if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
+ if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) {
return true;
- else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
+ }
+ else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) {
return true;
- else if (!f)
+ }
+ else if (!f) {
return true;
+ }
return false;
}
+
+/** \} */
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index bd3d2f652c0..aca67dc84e9 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -573,7 +573,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
obedit = base->object;
me = obedit->data;
if (me->edit_btmesh == NULL) {
- EDBM_mesh_make(scene->toolsettings, obedit, false);
+ EDBM_mesh_make(obedit, scene->toolsettings->selectmode, false);
exitmode = 1;
}
if (me->edit_btmesh == NULL)
@@ -882,9 +882,38 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
CustomData *data = GET_CD_DATA(me, ldata);
if (me->edit_btmesh) {
+ /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */
+ if (me->flag & ME_AUTOSMOOTH) {
+ BM_edges_sharp_from_angle_set(me->edit_btmesh->bm, me->smoothresh);
+
+ me->drawflag |= ME_DRAWSHARP;
+ }
+
BM_data_layer_add(me->edit_btmesh->bm, data, CD_CUSTOMLOOPNORMAL);
}
else {
+ /* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */
+ if (me->flag & ME_AUTOSMOOTH) {
+ float (*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
+
+ BKE_mesh_calc_normals_poly(
+ me->mvert, NULL, me->totvert,
+ me->mloop, me->mpoly,
+ me->totloop, me->totpoly,
+ polynors, true);
+
+ BKE_edges_sharp_from_angle_set(
+ me->mvert, me->totvert,
+ me->medge, me->totedge,
+ me->mloop, me->totloop,
+ me->mpoly, polynors, me->totpoly,
+ me->smoothresh);
+
+ MEM_freeN(polynors);
+
+ me->drawflag |= ME_DRAWSHARP;
+ }
+
CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
}
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
new file mode 100644
index 00000000000..22bfd8eedea
--- /dev/null
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -0,0 +1,377 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/mesh_mirror.c
+ * \ingroup edmesh
+ *
+ * Mirror calculation for edit-mode and object mode.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_bitmap.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BLI_kdtree.h"
+#include "BKE_editmesh.h"
+
+#include "ED_mesh.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Spatial Mirror API
+ * \{ */
+
+#define KD_THRESH 0.00002f
+
+static struct { void *tree; } MirrKdStore = {NULL};
+
+/* mode is 's' start, or 'e' end, or 'u' use */
+/* if end, ob can be NULL */
+int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
+{
+ if (mode == 'u') { /* use table */
+ if (MirrKdStore.tree == NULL)
+ ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
+
+ if (MirrKdStore.tree) {
+ KDTreeNearest nearest;
+ const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
+
+ if (i != -1) {
+ if (nearest.dist < KD_THRESH) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+ else if (mode == 's') { /* start table */
+ Mesh *me = ob->data;
+ const bool use_em = (!dm && em && me->edit_btmesh == em);
+ const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
+
+ if (MirrKdStore.tree) /* happens when entering this call without ending it */
+ ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
+
+ MirrKdStore.tree = BLI_kdtree_new(totvert);
+
+ if (use_em) {
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ /* this needs to be valid for index lookups later (callers need) */
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
+ }
+ }
+ else {
+ MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
+ int i;
+
+ for (i = 0; i < totvert; i++, mvert++) {
+ BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
+ }
+ }
+
+ BLI_kdtree_balance(MirrKdStore.tree);
+ }
+ else if (mode == 'e') { /* end table */
+ if (MirrKdStore.tree) {
+ BLI_kdtree_free(MirrKdStore.tree);
+ MirrKdStore.tree = NULL;
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Topology Mirror API
+ * \{ */
+
+typedef unsigned int MirrTopoHash_t;
+
+typedef struct MirrTopoVert_t {
+ MirrTopoHash_t hash;
+ int v_index;
+} MirrTopoVert_t;
+
+static int mirrtopo_hash_sort(const void *l1, const void *l2)
+{
+ if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
+ else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
+ return 0;
+}
+
+static int mirrtopo_vert_sort(const void *v1, const void *v2)
+{
+ if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
+ else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
+ return 0;
+}
+
+bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store)
+{
+ const bool is_editmode = (me->edit_btmesh != NULL);
+ int totvert;
+ int totedge;
+
+ if (dm) {
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ }
+ else if (me->edit_btmesh) {
+ totvert = me->edit_btmesh->bm->totvert;
+ totedge = me->edit_btmesh->bm->totedge;
+ }
+ else {
+ totvert = me->totvert;
+ totedge = me->totedge;
+ }
+
+ if ((mesh_topo_store->index_lookup == NULL) ||
+ (mesh_topo_store->prev_is_editmode != is_editmode) ||
+ (totvert != mesh_topo_store->prev_vert_tot) ||
+ (totedge != mesh_topo_store->prev_edge_tot))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+
+}
+
+void ED_mesh_mirrtopo_init(
+ Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store,
+ const bool skip_em_vert_array_init)
+{
+ const bool is_editmode = (me->edit_btmesh != NULL);
+ MEdge *medge = NULL, *med;
+ BMEditMesh *em = dm ? NULL : me->edit_btmesh;
+
+ /* editmode*/
+ BMEdge *eed;
+ BMIter iter;
+
+ int a, last;
+ int totvert, totedge;
+ int tot_unique = -1, tot_unique_prev = -1;
+ int tot_unique_edges = 0, tot_unique_edges_prev;
+
+ MirrTopoHash_t *topo_hash = NULL;
+ MirrTopoHash_t *topo_hash_prev = NULL;
+ MirrTopoVert_t *topo_pairs;
+ MirrTopoHash_t topo_pass = 1;
+
+ intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
+
+ /* reallocate if needed */
+ ED_mesh_mirrtopo_free(mesh_topo_store);
+
+ mesh_topo_store->prev_is_editmode = is_editmode;
+
+ if (em) {
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ totvert = em->bm->totvert;
+ }
+ else {
+ totvert = dm ? dm->getNumVerts(dm) : me->totvert;
+ }
+
+ topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
+
+ /* Initialize the vert-edge-user counts used to detect unique topology */
+ if (em) {
+ totedge = me->edit_btmesh->bm->totedge;
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
+ topo_hash[i1]++;
+ topo_hash[i2]++;
+ }
+ }
+ else {
+ totedge = dm ? dm->getNumEdges(dm) : me->totedge;
+ medge = dm ? dm->getEdgeArray(dm) : me->medge;
+
+ for (a = 0, med = medge; a < totedge; a++, med++) {
+ const unsigned int i1 = med->v1, i2 = med->v2;
+ topo_hash[i1]++;
+ topo_hash[i2]++;
+ }
+ }
+
+ topo_hash_prev = MEM_dupallocN(topo_hash);
+
+ tot_unique_prev = -1;
+ tot_unique_edges_prev = -1;
+ while (1) {
+ /* use the number of edges per vert to give verts unique topology IDs */
+
+ tot_unique_edges = 0;
+
+ /* This can make really big numbers, wrapping around here is fine */
+ if (em) {
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
+ topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
+ topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
+ tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
+ }
+ }
+ else {
+ for (a = 0, med = medge; a < totedge; a++, med++) {
+ const unsigned int i1 = med->v1, i2 = med->v2;
+ topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
+ topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
+ tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
+ }
+ }
+ memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
+
+ /* sort so we can count unique values */
+ qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
+
+ tot_unique = 1; /* account for skiping the first value */
+ for (a = 1; a < totvert; a++) {
+ if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
+ tot_unique++;
+ }
+ }
+
+ if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
+ /* Finish searching for unique values when 1 loop dosnt give a
+ * higher number of unique values compared to the previous loop */
+ break;
+ }
+ else {
+ tot_unique_prev = tot_unique;
+ tot_unique_edges_prev = tot_unique_edges;
+ }
+ /* Copy the hash calculated this iter, so we can use them next time */
+ memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
+
+ topo_pass++;
+ }
+
+ /* Hash/Index pairs are needed for sorting to find index pairs */
+ topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
+
+ /* since we are looping through verts, initialize these values here too */
+ index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
+
+ if (em) {
+ if (skip_em_vert_array_init == false) {
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ }
+ }
+
+ for (a = 0; a < totvert; a++) {
+ topo_pairs[a].hash = topo_hash[a];
+ topo_pairs[a].v_index = a;
+
+ /* initialize lookup */
+ index_lookup[a] = -1;
+ }
+
+ qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
+
+ last = 0;
+
+ /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
+ * but you cant ever access the last 'a' index of MirrTopoPairs */
+ if (em) {
+ BMVert **vtable = em->bm->vtable;
+ for (a = 1; a <= totvert; a++) {
+ /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
+ if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+ const int match_count = a - last;
+ if (match_count == 2) {
+ const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+ index_lookup[j] = (intptr_t)vtable[k];
+ index_lookup[k] = (intptr_t)vtable[j];
+ }
+ else if (match_count == 1) {
+ /* Center vertex. */
+ const int j = topo_pairs[a - 1].v_index;
+ index_lookup[j] = (intptr_t)vtable[j];
+ }
+ last = a;
+ }
+ }
+ }
+ else {
+ /* same as above, for mesh */
+ for (a = 1; a <= totvert; a++) {
+ if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+ const int match_count = a - last;
+ if (match_count == 2) {
+ const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+ index_lookup[j] = k;
+ index_lookup[k] = j;
+ }
+ else if (match_count == 1) {
+ /* Center vertex. */
+ const int j = topo_pairs[a - 1].v_index;
+ index_lookup[j] = j;
+ }
+ last = a;
+ }
+ }
+ }
+
+ MEM_freeN(topo_pairs);
+ topo_pairs = NULL;
+
+ MEM_freeN(topo_hash);
+ MEM_freeN(topo_hash_prev);
+
+ mesh_topo_store->index_lookup = index_lookup;
+ mesh_topo_store->prev_vert_tot = totvert;
+ mesh_topo_store->prev_edge_tot = totedge;
+}
+
+void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
+{
+ if (mesh_topo_store->index_lookup) {
+ MEM_freeN(mesh_topo_store->index_lookup);
+ }
+ mesh_topo_store->index_lookup = NULL;
+ mesh_topo_store->prev_vert_tot = -1;
+ mesh_topo_store->prev_edge_tot = -1;
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 64b6f5b8010..fd5beac9cc6 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -47,8 +47,6 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-
-#include "BLI_kdtree.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
@@ -58,6 +56,7 @@
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_object.h"
+#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_multires.h"
@@ -117,21 +116,12 @@ static void join_mesh_single(
BLI_assert(dvert != NULL);
/* Build src to merged mapping of vgroup indices. */
- bDeformGroup *dg_src;
- int *vgroup_index_map = alloca(sizeof(*vgroup_index_map) * BLI_listbase_count(&ob_src->defbase));
- bool is_vgroup_remap_needed = false;
-
- for (dg_src = ob_src->defbase.first, b = 0; dg_src; dg_src = dg_src->next, b++) {
- vgroup_index_map[b] = defgroup_name_index(ob_dst, dg_src->name);
- is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[b] != b);
- }
-
- if (is_vgroup_remap_needed) {
- for (a = 0; a < me->totvert; a++) {
- for (b = 0; b < dvert[a].totweight; b++) {
- dvert[a].dw[b].def_nr = vgroup_index_map[dvert_src[a].dw[b].def_nr];
- }
- }
+ int *vgroup_index_map;
+ int vgroup_index_map_len;
+ vgroup_index_map = BKE_object_defgroup_index_map_create(ob_src, ob_dst, &vgroup_index_map_len);
+ BKE_object_defgroup_index_map_apply(dvert, me->totvert, vgroup_index_map, vgroup_index_map_len);
+ if (vgroup_index_map != NULL) {
+ MEM_freeN(vgroup_index_map);
}
}
@@ -570,12 +560,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (ma)
id_us_min(&ma->id);
}
- if (ob->mat) MEM_freeN(ob->mat);
- if (ob->matbits) MEM_freeN(ob->matbits);
- if (me->mat) MEM_freeN(me->mat);
- ob->mat = me->mat = NULL;
- ob->matbits = NULL;
-
+ MEM_SAFE_FREE(ob->mat);
+ MEM_SAFE_FREE(ob->matbits);
+ MEM_SAFE_FREE(me->mat);
+
if (totcol) {
me->mat = matar;
ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar");
@@ -690,84 +678,6 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* -------------------------------------------------------------------- */
-/* Mesh Mirror (Spatial) */
-
-/** \name Mesh Spatial Mirror API
- * \{ */
-
-#define KD_THRESH 0.00002f
-
-static struct { void *tree; } MirrKdStore = {NULL};
-
-/* mode is 's' start, or 'e' end, or 'u' use */
-/* if end, ob can be NULL */
-int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
-{
- if (mode == 'u') { /* use table */
- if (MirrKdStore.tree == NULL)
- ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
-
- if (MirrKdStore.tree) {
- KDTreeNearest nearest;
- const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
-
- if (i != -1) {
- if (nearest.dist < KD_THRESH) {
- return i;
- }
- }
- }
- return -1;
- }
- else if (mode == 's') { /* start table */
- Mesh *me = ob->data;
- const bool use_em = (!dm && em && me->edit_btmesh == em);
- const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
-
- if (MirrKdStore.tree) /* happens when entering this call without ending it */
- ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
-
- MirrKdStore.tree = BLI_kdtree_new(totvert);
-
- if (use_em) {
- BMVert *eve;
- BMIter iter;
- int i;
-
- /* this needs to be valid for index lookups later (callers need) */
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
- }
- }
- else {
- MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
- int i;
-
- for (i = 0; i < totvert; i++, mvert++) {
- BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
- }
- }
-
- BLI_kdtree_balance(MirrKdStore.tree);
- }
- else if (mode == 'e') { /* end table */
- if (MirrKdStore.tree) {
- BLI_kdtree_free(MirrKdStore.tree);
- MirrKdStore.tree = NULL;
- }
- }
- else {
- BLI_assert(0);
- }
-
- return 0;
-}
-
-/** \} */
-
/* -------------------------------------------------------------------- */
/* Mesh Mirror (Topology) */
@@ -1110,7 +1020,7 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int
return false;
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (size) {
/* sample rect to increase chances of selecting, so that when clicking
@@ -1281,7 +1191,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
if (!me || me->totvert == 0)
return false;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (use_zbuf) {
if (size > 0) {
diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt
index 89ba942ac36..73f80774716 100644
--- a/source/blender/editors/metaball/CMakeLists.txt
+++ b/source/blender/editors/metaball/CMakeLists.txt
@@ -35,6 +35,7 @@ set(INC_SYS
)
set(SRC
+ editmball_undo.c
mball_edit.c
mball_ops.c
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
new file mode 100644
index 00000000000..974bfb237d3
--- /dev/null
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -0,0 +1,131 @@
+/*
+ * ***** 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/metaball/editmball_undo.c
+ * \ingroup edmeta
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "DNA_defs.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+
+#include "ED_mball.h"
+#include "ED_util.h"
+
+typedef struct UndoMBall {
+ ListBase editelems;
+ int lastelem_index;
+} UndoMBall;
+
+/* free all MetaElems from ListBase */
+static void freeMetaElemlist(ListBase *lb)
+{
+ MetaElem *ml;
+
+ if (lb == NULL) {
+ return;
+ }
+
+ while ((ml = BLI_pophead(lb))) {
+ MEM_freeN(ml);
+ }
+}
+
+static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata))
+{
+ MetaBall *mb = mb_v;
+ UndoMBall *umb = umb_v;
+
+ freeMetaElemlist(mb->editelems);
+ mb->lastelem = NULL;
+
+ /* copy 'undo' MetaElems to 'edit' MetaElems */
+ int index = 0;
+ for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) {
+ MetaElem *ml_edit = MEM_dupallocN(ml_undo);
+ BLI_addtail(mb->editelems, ml_edit);
+ if (index == umb->lastelem_index) {
+ mb->lastelem = ml_edit;
+ }
+ }
+
+}
+
+static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata))
+{
+ MetaBall *mb = mb_v;
+ UndoMBall *umb;
+
+ /* allocate memory for undo ListBase */
+ umb = MEM_callocN(sizeof(UndoMBall), __func__);
+ umb->lastelem_index = -1;
+
+ /* copy contents of current ListBase to the undo ListBase */
+ int index = 0;
+ for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) {
+ MetaElem *ml_undo = MEM_dupallocN(ml_edit);
+ BLI_addtail(&umb->editelems, ml_undo);
+ if (ml_edit == mb->lastelem) {
+ umb->lastelem_index = index;
+ }
+ }
+
+ return umb;
+}
+
+/* free undo ListBase of MetaElems */
+static void free_undoMball(void *umb_v)
+{
+ UndoMBall *umb = umb_v;
+
+ freeMetaElemlist(&umb->editelems);
+ MEM_freeN(umb);
+}
+
+static MetaBall *metaball_get_obdata(Object *ob)
+{
+ if (ob && ob->type == OB_MBALL) {
+ return ob->data;
+ }
+ return NULL;
+}
+
+
+static void *get_data(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ return metaball_get_obdata(obedit);
+}
+
+/* this is undo system for MetaBalls */
+void undo_push_mball(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
+}
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 935f1a5ea4a..6dd16b52387 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -29,7 +29,6 @@
* \ingroup edmeta
*/
-
#include <math.h>
#include <string.h>
@@ -56,7 +55,6 @@
#include "ED_mball.h"
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -598,7 +596,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
rcti rect;
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
BLI_rcti_init_pt_radius(&rect, mval, 12);
@@ -668,94 +666,3 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
}
-/* ************* undo for MetaBalls ************* */
-
-typedef struct UndoMBall {
- ListBase editelems;
- int lastelem_index;
-} UndoMBall;
-
-/* free all MetaElems from ListBase */
-static void freeMetaElemlist(ListBase *lb)
-{
- MetaElem *ml;
-
- if (lb == NULL) return;
-
- while ((ml = BLI_pophead(lb))) {
- MEM_freeN(ml);
- }
-}
-
-
-static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata))
-{
- MetaBall *mb = mb_v;
- UndoMBall *umb = umb_v;
-
- freeMetaElemlist(mb->editelems);
- mb->lastelem = NULL;
-
- /* copy 'undo' MetaElems to 'edit' MetaElems */
- int index = 0;
- for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) {
- MetaElem *ml_edit = MEM_dupallocN(ml_undo);
- BLI_addtail(mb->editelems, ml_edit);
- if (index == umb->lastelem_index) {
- mb->lastelem = ml_edit;
- }
- }
-
-}
-
-static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata))
-{
- MetaBall *mb = mb_v;
- UndoMBall *umb;
-
- /* allocate memory for undo ListBase */
- umb = MEM_callocN(sizeof(UndoMBall), __func__);
- umb->lastelem_index = -1;
-
- /* copy contents of current ListBase to the undo ListBase */
- int index = 0;
- for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) {
- MetaElem *ml_undo = MEM_dupallocN(ml_edit);
- BLI_addtail(&umb->editelems, ml_undo);
- if (ml_edit == mb->lastelem) {
- umb->lastelem_index = index;
- }
- }
-
- return umb;
-}
-
-/* free undo ListBase of MetaElems */
-static void free_undoMball(void *umb_v)
-{
- UndoMBall *umb = umb_v;
-
- freeMetaElemlist(&umb->editelems);
- MEM_freeN(umb);
-}
-
-static MetaBall *metaball_get_obdata(Object *ob)
-{
- if (ob && ob->type == OB_MBALL) {
- return ob->data;
- }
- return NULL;
-}
-
-
-static void *get_data(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- return metaball_get_obdata(obedit);
-}
-
-/* this is undo system for MetaBalls */
-void undo_push_mball(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
-}
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 8050508983b..646b8137b2d 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -50,8 +50,8 @@ set(SRC
object_facemap_ops.c
object_group.c
object_hook.c
- object_lattice.c
object_lod.c
+ object_modes.c
object_modifier.c
object_ops.c
object_random.c
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index c4bad6f76c9..3590b38310f 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1157,8 +1157,8 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
{
/* create new data for NLA hierarchy */
AnimData *adt = BKE_animdata_add_id(&ob->id);
- NlaTrack *nlt = add_nlatrack(adt, NULL);
- NlaStrip *strip = add_nla_soundstrip(scene, ob->data);
+ NlaTrack *nlt = BKE_nlatrack_add(adt, NULL);
+ NlaStrip *strip = BKE_nla_add_soundstrip(scene, ob->data);
strip->start = CFRA;
strip->end += strip->start;
@@ -1719,7 +1719,7 @@ static int convert_exec(bContext *C, wmOperator *op)
/* don't forget multiple users! */
{
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
ob->flag &= ~OB_DONE;
@@ -1739,7 +1739,7 @@ static int convert_exec(bContext *C, wmOperator *op)
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases");
@@ -2009,7 +2009,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!keep_original) {
if (mballConverted) {
- FOREACH_SCENE_OBJECT(scene, ob_mball)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_mball)
{
if (ob_mball->type == OB_MBALL) {
if (ob_mball->flag & OB_DONE) {
@@ -2022,7 +2022,7 @@ static int convert_exec(bContext *C, wmOperator *op)
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
/* delete object should renew depsgraph */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index a13df441c5f..e23329a7a68 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -581,6 +581,7 @@ typedef struct BakeRender {
Render *re;
Main *main;
Scene *scene;
+ ViewLayer *view_layer;
struct Object *actob;
int result, ready;
@@ -630,6 +631,7 @@ static void init_bake_internal(BakeRender *bkr, bContext *C)
bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; /* can be NULL */
bkr->main = CTX_data_main(C);
bkr->scene = scene;
+ bkr->view_layer = view_layer;
bkr->actob = (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT(view_layer) : NULL;
bkr->re = RE_NewRender("_Bake View_");
@@ -735,7 +737,7 @@ static void bake_startjob(void *bkv, short *stop, short *do_update, float *progr
RE_test_break_cb(bkr->re, NULL, thread_break);
G.is_break = false; /* BKE_blender_test_break uses this global */
- RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob);
+ RE_Database_Baking(bkr->re, bmain, scene, bkr->view_layer, scene->lay, scene->r.bake_mode, bkr->actob);
/* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */
bkr->result = RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update, bkr->progress);
@@ -843,7 +845,6 @@ static int bake_image_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 result = OPERATOR_CANCELLED;
if (is_multires_bake(scene)) {
@@ -863,7 +864,8 @@ static int bake_image_exec(bContext *C, wmOperator *op)
RE_test_break_cb(bkr.re, NULL, thread_break);
G.is_break = false; /* BKE_blender_test_break uses this global */
- RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT(view_layer) : NULL);
+ RE_Database_Baking(bkr.re, bmain, scene, bkr.view_layer, scene->lay, scene->r.bake_mode,
+ (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT(bkr.view_layer) : NULL);
/* baking itself is threaded, cannot use test_break in threads */
BLI_threadpool_init(&threads, do_bake_render, 1);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index c8bcc9224e9..acf3f73c9c6 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -56,9 +56,11 @@
#include "BKE_report.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -84,8 +86,8 @@ static void bake_set_props(wmOperator *op, Scene *scene);
typedef struct BakeAPIRender {
Object *ob;
Main *main;
- Depsgraph *depsgraph;
Scene *scene;
+ ViewLayer *view_layer;
ReportList *reports;
ListBase selected_objects;
@@ -634,7 +636,8 @@ static Mesh *bake_mesh_new_from_object(EvaluationContext *eval_ctx, Main *bmain,
}
static int bake(
- Render *re, Main *bmain, Depsgraph *graph, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
+ Render *re, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob_low, ListBase *selected_objects,
+ ReportList *reports,
const eScenePassType pass_type, const int pass_filter, const int margin,
const eBakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage,
@@ -642,6 +645,10 @@ static int bake(
const char *custom_cage, const char *filepath, const int width, const int height,
const char *identifier, ScrArea *sa, const char *uv_layer)
{
+ EvaluationContext *eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new();
+ DEG_evaluation_context_init_from_view_layer_for_render(eval_ctx, depsgraph, scene, view_layer);
+
int op_result = OPERATOR_CANCELLED;
bool ok = false;
@@ -673,7 +680,7 @@ static int bake(
size_t num_pixels;
int tot_materials;
- RE_bake_engine_set_engine_parameters(re, bmain, graph, scene);
+ RE_bake_engine_set_engine_parameters(re, bmain, scene);
if (!RE_bake_has_engine(re)) {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -783,8 +790,16 @@ static int bake(
}
}
+ /* Make sure depsgraph is up to date. */
+ DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
+ BKE_scene_graph_update_tagged(eval_ctx,
+ depsgraph,
+ bmain,
+ scene,
+ view_layer);
+
/* get the mesh as it arrives in the renderer */
- me_low = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_low);
+ me_low = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_low);
/* populate the pixel array with the face data */
if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -799,7 +814,7 @@ static int bake(
/* prepare cage mesh */
if (ob_cage) {
- me_cage = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_cage);
+ me_cage = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_cage);
if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) {
BKE_report(reports, RPT_ERROR,
"Invalid cage object, the cage mesh must have the same number "
@@ -831,7 +846,7 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_cage = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_low);
+ me_cage = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_low);
RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
@@ -857,7 +872,7 @@ static int bake(
tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
- highpoly[i].me = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, highpoly[i].ob);
+ highpoly[i].me = bake_mesh_new_from_object(eval_ctx, bmain, scene, highpoly[i].ob);
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
/* lowpoly to highpoly transformation matrix */
@@ -960,7 +975,7 @@ cage_cleanup:
md->mode &= ~eModifierMode_Render;
}
- me_nores = bake_mesh_new_from_object(RE_GetEvalCtx(re), bmain, scene, ob_low);
+ me_nores = bake_mesh_new_from_object(eval_ctx, bmain, scene, ob_low);
RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
@@ -1121,7 +1136,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->ob = CTX_data_active_object(C);
bkr->main = CTX_data_main(C);
- bkr->depsgraph = CTX_data_depsgraph(C);
+ bkr->view_layer = CTX_data_view_layer(C);
bkr->scene = CTX_data_scene(C);
bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
@@ -1205,7 +1220,7 @@ static int bake_exec(bContext *C, wmOperator *op)
if (bkr.is_selected_to_active) {
result = bake(
- bkr.render, bkr.main, bkr.depsgraph, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
+ bkr.render, bkr.main, bkr.scene, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports,
bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode,
bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage,
bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
@@ -1218,7 +1233,7 @@ static int bake_exec(bContext *C, wmOperator *op)
for (link = bkr.selected_objects.first; link; link = link->next) {
Object *ob_iter = link->ptr.data;
result = bake(
- bkr.render, bkr.main, bkr.depsgraph, bkr.scene, ob_iter, NULL, bkr.reports,
+ bkr.render, bkr.main, bkr.scene, bkr.view_layer, ob_iter, NULL, bkr.reports,
bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode,
is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage,
bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
@@ -1263,7 +1278,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
if (bkr->is_selected_to_active) {
bkr->result = bake(
- bkr->render, bkr->main, bkr->depsgraph, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
+ bkr->render, bkr->main, bkr->scene, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports,
bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage,
bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
@@ -1276,7 +1291,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
for (link = bkr->selected_objects.first; link; link = link->next) {
Object *ob_iter = link->ptr.data;
bkr->result = bake(
- bkr->render, bkr->main, bkr->depsgraph, bkr->scene, ob_iter, NULL, bkr->reports,
+ bkr->render, bkr->main, bkr->scene, bkr->view_layer, ob_iter, NULL, bkr->reports,
bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage,
bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index c6f9ced51a3..3e629c8d7f6 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -77,11 +77,13 @@
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_property.h"
#include "BKE_sca.h"
#include "BKE_softbody.h"
#include "BKE_modifier.h"
+#include "BKE_editlattice.h"
#include "BKE_editmesh.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -235,9 +237,9 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
if (lt->editlatt == NULL) {
return false;
}
- ED_lattice_editlatt_load(obedit);
+ BKE_editlattice_load(obedit);
if (freedata) {
- ED_lattice_editlatt_free(obedit);
+ BKE_editlattice_free(obedit);
}
}
else if (obedit->type == OB_MBALL) {
@@ -298,6 +300,8 @@ void ED_object_editmode_exit_ex(bContext *C, WorkSpace *workspace, Scene *scene,
/* also flush ob recalc, doesn't take much overhead, but used for particles */
DEG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ workspace->object_mode &= ~OB_MODE_EDIT;
if (flag & EM_DO_UNDO)
ED_undo_push(C, "Editmode");
@@ -308,10 +312,10 @@ void ED_object_editmode_exit_ex(bContext *C, WorkSpace *workspace, Scene *scene,
else {
WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
}
-
- workspace->object_mode &= ~OB_MODE_EDIT;
}
+ ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, obedit);
+
if (flag & EM_WAITCURSOR) waitcursor(0);
/* This way we ensure scene's obedit is copied into all CoW scenes. */
@@ -363,7 +367,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
/* note, when switching scenes the object can have editmode data but
* not be scene->obedit: bug 22954, this avoids calling self eternally */
if ((workspace->object_mode_restore & OB_MODE_EDIT) == 0)
- ED_object_toggle_modes(C, workspace->object_mode);
+ ED_object_mode_toggle(C, workspace->object_mode);
workspace->object_mode = OB_MODE_EDIT;
@@ -372,7 +376,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
ok = 1;
const bool use_key_index = mesh_needs_keyindex(ob->data);
- EDBM_mesh_make(scene->toolsettings, ob, use_key_index);
+ EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index);
em = BKE_editmesh_from_object(ob);
if (LIKELY(em)) {
@@ -419,7 +423,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
}
else if (ob->type == OB_LATTICE) {
ok = 1;
- ED_lattice_editlatt_make(ob);
+ BKE_editlattice_make(ob);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene);
}
@@ -440,6 +444,8 @@ void ED_object_editmode_enter(bContext *C, int flag)
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
}
+ ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob);
+
if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode");
if (flag & EM_WAITCURSOR) waitcursor(0);
}
@@ -505,6 +511,7 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
static int posemode_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
WorkSpace *workspace = CTX_wm_workspace(C);
Base *base = CTX_data_active_base(C);
Object *ob = base->object;
@@ -526,7 +533,9 @@ static int posemode_exec(bContext *C, wmOperator *op)
ED_armature_exit_posemode(C, base);
else
ED_armature_enter_posemode(C, base);
-
+
+ ED_workspace_object_mode_sync_from_object(wm, workspace, ob);
+
return OPERATOR_FINISHED;
}
@@ -904,7 +913,7 @@ static void copy_attr(Main *bmain, Scene *scene, ViewLayer *view_layer, short ev
}
else if (event == 26) {
#if 0 // XXX old animation system
- copy_nlastrips(&base->object->nlastrips, &ob->nlastrips);
+ BKE_nlastrip_copy(s(&base->object->nlastrips, &ob->nlastrips);
#endif // XXX old animation system
}
else if (event == 27) { /* autosmooth */
@@ -1483,92 +1492,6 @@ static const EnumPropertyItem *object_mode_set_itemsf(
return item;
}
-static const char *object_mode_op_string(eObjectMode mode)
-{
- if (mode & OB_MODE_EDIT)
- return "OBJECT_OT_editmode_toggle";
- if (mode == OB_MODE_SCULPT)
- return "SCULPT_OT_sculptmode_toggle";
- if (mode == OB_MODE_VERTEX_PAINT)
- return "PAINT_OT_vertex_paint_toggle";
- if (mode == OB_MODE_WEIGHT_PAINT)
- return "PAINT_OT_weight_paint_toggle";
- if (mode == OB_MODE_TEXTURE_PAINT)
- return "PAINT_OT_texture_paint_toggle";
- if (mode == OB_MODE_PARTICLE_EDIT)
- return "PARTICLE_OT_particle_edit_toggle";
- if (mode == OB_MODE_POSE)
- return "OBJECT_OT_posemode_toggle";
- if (mode == OB_MODE_GPENCIL)
- return "GPENCIL_OT_editmode_toggle";
- return NULL;
-}
-
-/* checks the mode to be set is compatible with the object
- * should be made into a generic function
- */
-static bool object_mode_compat_test(Object *ob, eObjectMode mode)
-{
- if (ob) {
- if (mode == OB_MODE_OBJECT)
- return true;
- else if (mode == OB_MODE_GPENCIL)
- return true; /* XXX: assume this is the case for now... */
-
- switch (ob->type) {
- case OB_MESH:
- if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT |
- OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT))
- {
- return true;
- }
- break;
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- case OB_MBALL:
- if (mode & (OB_MODE_EDIT))
- return true;
- break;
- case OB_LATTICE:
- if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT))
- return true;
- break;
- case OB_ARMATURE:
- if (mode & (OB_MODE_EDIT | OB_MODE_POSE))
- return true;
- break;
- }
- }
-
- return false;
-}
-
-/**
- * Sets the mode to a compatible state (use before entering the mode).
- *
- * This is so each mode's exec function can call
- */
-bool ED_object_mode_compat_set(bContext *C, WorkSpace *workspace, eObjectMode mode, ReportList *reports)
-{
- bool ok;
- if (!ELEM(workspace->object_mode, mode, OB_MODE_OBJECT)) {
- const char *opstring = object_mode_op_string(workspace->object_mode);
-
- WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
- ok = ELEM(workspace->object_mode, mode, OB_MODE_OBJECT);
- if (!ok) {
- wmOperatorType *ot = WM_operatortype_find(opstring, false);
- BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name);
- }
- }
- else {
- ok = true;
- }
-
- return ok;
-}
-
static int object_mode_set_poll(bContext *C)
{
/* Since Grease Pencil editmode is also handled here,
@@ -1609,7 +1532,7 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
}
}
- if (!ob || !object_mode_compat_test(ob, mode))
+ if (!ob || !ED_object_mode_compat_test(ob, mode))
return OPERATOR_PASS_THROUGH;
if (workspace->object_mode != mode) {
@@ -1620,7 +1543,7 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
/* Exit current mode if it's not the mode we're setting */
if (mode != OB_MODE_OBJECT && (workspace->object_mode != mode || toggle)) {
/* Enter new mode */
- ED_object_toggle_modes(C, mode);
+ ED_object_mode_toggle(C, mode);
}
if (toggle) {
@@ -1629,14 +1552,14 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
(restore_mode == OB_MODE_OBJECT) &&
(workspace->object_mode_restore != OB_MODE_OBJECT))
{
- ED_object_toggle_modes(C, workspace->object_mode_restore);
+ ED_object_mode_toggle(C, workspace->object_mode_restore);
}
else if (workspace->object_mode == mode) {
/* For toggling, store old mode so we know what to go back to */
workspace->object_mode_restore = restore_mode;
}
else if (!ELEM(workspace->object_mode_restore, mode, OB_MODE_OBJECT)) {
- ED_object_toggle_modes(C, workspace->object_mode_restore);
+ ED_object_mode_toggle(C, workspace->object_mode_restore);
}
}
@@ -1668,17 +1591,6 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-void ED_object_toggle_modes(bContext *C, eObjectMode mode)
-{
- if (mode != OB_MODE_OBJECT) {
- const char *opstring = object_mode_op_string(mode);
-
- if (opstring) {
- WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
- }
- }
-}
-
/************************ Game Properties ***********************/
static int game_property_new_exec(bContext *C, wmOperator *op)
@@ -2066,8 +1978,6 @@ void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* generic utility function */
-
bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3])
{
switch (obedit->type) {
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 93546b1bd5d..3ff794772fa 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -319,7 +319,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
BMEditMesh *em;
EDBM_mesh_load(obedit);
- EDBM_mesh_make(scene->toolsettings, obedit, true);
+ EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true);
DEG_id_tag_update(obedit->data, 0);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 03aacc86ea7..a3bb01b0f24 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -138,16 +138,6 @@ void OBJECT_OT_hook_assign(struct wmOperatorType *ot);
void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
-/* object_lattice.c */
-void LATTICE_OT_select_all(struct wmOperatorType *ot);
-void LATTICE_OT_select_more(struct wmOperatorType *ot);
-void LATTICE_OT_select_less(struct wmOperatorType *ot);
-void LATTICE_OT_select_ungrouped(struct wmOperatorType *ot);
-void LATTICE_OT_select_random(struct wmOperatorType *ot);
-void LATTICE_OT_select_mirror(struct wmOperatorType *ot);
-void LATTICE_OT_make_regular(struct wmOperatorType *ot);
-void LATTICE_OT_flip(struct wmOperatorType *ot);
-
/* object_group.c */
void GROUP_OT_create(struct wmOperatorType *ot);
void GROUP_OT_objects_remove_all(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
new file mode 100644
index 00000000000..33b9ea49ec0
--- /dev/null
+++ b/source/blender/editors/object/object_modes.c
@@ -0,0 +1,318 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation, 2002-2008 full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_modes.c
+ * \ingroup edobj
+ *
+ * General utils to handle mode switching,
+ * actual mode switching logic is per-object type.
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+
+#include "ED_object.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name High Level Mode Operations
+ *
+ * \{ */
+
+static const char *object_mode_op_string(eObjectMode mode)
+{
+ if (mode & OB_MODE_EDIT)
+ return "OBJECT_OT_editmode_toggle";
+ if (mode == OB_MODE_SCULPT)
+ return "SCULPT_OT_sculptmode_toggle";
+ if (mode == OB_MODE_VERTEX_PAINT)
+ return "PAINT_OT_vertex_paint_toggle";
+ if (mode == OB_MODE_WEIGHT_PAINT)
+ return "PAINT_OT_weight_paint_toggle";
+ if (mode == OB_MODE_TEXTURE_PAINT)
+ return "PAINT_OT_texture_paint_toggle";
+ if (mode == OB_MODE_PARTICLE_EDIT)
+ return "PARTICLE_OT_particle_edit_toggle";
+ if (mode == OB_MODE_POSE)
+ return "OBJECT_OT_posemode_toggle";
+ if (mode == OB_MODE_GPENCIL)
+ return "GPENCIL_OT_editmode_toggle";
+ return NULL;
+}
+
+/**
+ * Checks the mode to be set is compatible with the object
+ * should be made into a generic function
+ */
+bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
+{
+ if (ob) {
+ if (mode == OB_MODE_OBJECT)
+ return true;
+ else if (mode == OB_MODE_GPENCIL)
+ return true; /* XXX: assume this is the case for now... */
+
+ switch (ob->type) {
+ case OB_MESH:
+ if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT |
+ OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT))
+ {
+ return true;
+ }
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ case OB_MBALL:
+ if (mode & (OB_MODE_EDIT))
+ return true;
+ break;
+ case OB_LATTICE:
+ if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT))
+ return true;
+ break;
+ case OB_ARMATURE:
+ if (mode & (OB_MODE_EDIT | OB_MODE_POSE))
+ return true;
+ break;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Sets the mode to a compatible state (use before entering the mode).
+ *
+ * This is so each mode's exec function can call
+ */
+bool ED_object_mode_compat_set(bContext *C, WorkSpace *workspace, eObjectMode mode, ReportList *reports)
+{
+ bool ok;
+ if (!ELEM(workspace->object_mode, mode, OB_MODE_OBJECT)) {
+ const char *opstring = object_mode_op_string(workspace->object_mode);
+
+ WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+ ok = ELEM(workspace->object_mode, mode, OB_MODE_OBJECT);
+ if (!ok) {
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
+ BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name);
+ }
+ }
+ else {
+ ok = true;
+ }
+
+ return ok;
+}
+
+void ED_object_mode_toggle(bContext *C, eObjectMode mode)
+{
+ if (mode != OB_MODE_OBJECT) {
+ const char *opstring = object_mode_op_string(mode);
+
+ if (opstring) {
+ WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Mode Enter/Exit
+ *
+ * Supports exiting a mode without it being in the current context.
+ * This could be done for entering modes too if it's needed.
+ *
+ * \{ */
+
+bool ED_object_mode_generic_enter(
+ struct bContext *C, eObjectMode object_mode)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ if (workspace->object_mode == object_mode) {
+ return true;
+ }
+ wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_enum_set(&ptr, "mode", object_mode);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+ return (workspace->object_mode == object_mode);
+}
+
+/**
+ * Use for changing works-paces or changing active object.
+ * Caller can check #OB_MODE_ALL_MODE_DATA to test if this needs to be run.
+ */
+static bool ed_object_mode_generic_exit_ex(
+ const struct EvaluationContext *eval_ctx,
+ struct WorkSpace *workspace, struct Scene *scene, struct Object *ob,
+ bool only_test)
+{
+ if (eval_ctx->object_mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_editmode_exit_ex(NULL, workspace, scene, ob, EM_FREEDATA);
+ }
+ }
+ else if (eval_ctx->object_mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_vpaintmode_exit_ex(workspace, ob);
+ }
+ }
+ else if (eval_ctx->object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_wpaintmode_exit_ex(workspace, ob);
+ }
+ }
+ else if (eval_ctx->object_mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_sculptmode_exit_ex(eval_ctx, workspace, scene, ob);
+ }
+ }
+ else {
+ if (only_test) {
+ return false;
+ }
+ BLI_assert((eval_ctx->object_mode & OB_MODE_ALL_MODE_DATA) == 0);
+ }
+
+ return false;
+}
+
+void ED_object_mode_generic_exit(
+ const struct EvaluationContext *eval_ctx,
+ struct WorkSpace *workspace, struct Scene *scene, struct Object *ob)
+{
+ ed_object_mode_generic_exit_ex(eval_ctx, workspace, scene, ob, false);
+}
+
+bool ED_object_mode_generic_has_data(
+ const struct EvaluationContext *eval_ctx,
+ struct Object *ob)
+{
+ return ed_object_mode_generic_exit_ex(eval_ctx, NULL, NULL, ob, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mode Syncing Utils
+ *
+ * \{ */
+
+/**
+ * A version of #ED_object_mode_generic_enter that checks if the object
+ * has an active mode mode in another window we need to use another window first.
+ */
+bool ED_object_mode_generic_enter_or_other_window(
+ struct bContext *C, const wmWindow *win_compare, eObjectMode object_mode)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *basact = view_layer->basact;
+ if (basact == NULL) {
+ workspace->object_mode = OB_MODE_OBJECT;
+ return (workspace->object_mode == object_mode);
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ eObjectMode object_mode_set = OB_MODE_OBJECT;
+ bool use_object_mode = ED_workspace_object_mode_in_other_window(wm, win_compare, basact->object, &object_mode_set);
+
+ if (use_object_mode) {
+ workspace->object_mode = object_mode_set;
+ return (workspace->object_mode == object_mode);
+ }
+ else {
+ workspace->object_mode = OB_MODE_OBJECT;
+ return ED_object_mode_generic_enter(C, object_mode);
+ }
+}
+
+void ED_object_mode_generic_exit_or_other_window(
+ const struct EvaluationContext *eval_ctx, wmWindowManager *wm,
+ struct WorkSpace *workspace, struct Scene *scene, struct Object *ob)
+{
+ if (ob == NULL) {
+ return;
+ }
+ bool is_active = ED_workspace_object_mode_in_other_window(wm, NULL, ob, NULL);
+ if (is_active == false) {
+ ED_object_mode_generic_exit(eval_ctx, workspace, scene, ob);
+ }
+}
+
+/**
+ * Use to find if we need to create the mode-data.
+ *
+ * When the mode 'exists' it means we have a windowing showing an object with this mode.
+ * So it's data is already created.
+ * Used to check if we need to perform mode switching.
+ */
+bool ED_object_mode_generic_exists(
+ wmWindowManager *wm, struct Object *ob,
+ eObjectMode object_mode)
+{
+ if (ob == NULL) {
+ return false;
+ }
+ eObjectMode object_mode_test;
+ if (ED_workspace_object_mode_in_other_window(wm, NULL, ob, &object_mode_test)) {
+ if (object_mode == object_mode_test) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index ba3541b428a..59ba92eb1bf 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -226,15 +226,6 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_shape_key_mirror);
WM_operatortype_append(OBJECT_OT_shape_key_move);
- WM_operatortype_append(LATTICE_OT_select_all);
- WM_operatortype_append(LATTICE_OT_select_more);
- WM_operatortype_append(LATTICE_OT_select_less);
- WM_operatortype_append(LATTICE_OT_select_ungrouped);
- WM_operatortype_append(LATTICE_OT_select_random);
- WM_operatortype_append(LATTICE_OT_select_mirror);
- WM_operatortype_append(LATTICE_OT_make_regular);
- WM_operatortype_append(LATTICE_OT_flip);
-
WM_operatortype_append(OBJECT_OT_group_add);
WM_operatortype_append(OBJECT_OT_group_link);
WM_operatortype_append(OBJECT_OT_group_remove);
@@ -432,30 +423,6 @@ void ED_keymap_object(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0);
RNA_int_set(kmi->ptr, "level", i);
}
-
- /* ############################################################################ */
- /* ################################ LATTICE ################################### */
- /* ############################################################################ */
-
- keymap = WM_keymap_find(keyconf, "Lattice", 0, 0);
- keymap->poll = ED_operator_editlattice;
-
- kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
- WM_keymap_add_item(keymap, "LATTICE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "LATTICE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "LATTICE_OT_flip", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0);
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, false);
}
void ED_keymap_proportional_cycle(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap)
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 9e6a5778490..d86ad453c9e 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -150,7 +150,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
BMEditMesh *em;
EDBM_mesh_load(obedit);
- EDBM_mesh_make(scene->toolsettings, obedit, true);
+ EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true);
DEG_id_tag_update(obedit->data, 0);
@@ -400,13 +400,13 @@ static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA
return DummyRNA_DEFAULT_items;
/* find the object to affect */
- FOREACH_GROUP_OBJECT(ob->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(ob->dup_group, object)
{
item_tmp.identifier = item_tmp.name = object->id.name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1632,33 +1632,30 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, const bool copy_groups)
{
- if (!ID_IS_LINKED(ob) && ob->id.us > 1) {
- /* base gets copy of object */
- Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
+ /* base gets copy of object */
+ Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
- if (copy_groups) {
- if (ob->flag & OB_FROMGROUP) {
- obn->flag |= OB_FROMGROUP;
- }
- }
- else {
- /* copy already clears */
+ if (copy_groups) {
+ if (ob->flag & OB_FROMGROUP) {
+ obn->flag |= OB_FROMGROUP;
}
- /* remap gpencil parenting */
+ }
+ else {
+ /* copy already clears */
+ }
+ /* remap gpencil parenting */
- if (scene->gpd) {
- bGPdata *gpd = scene->gpd;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->parent == ob) {
- gpl->parent = obn;
- }
+ if (scene->gpd) {
+ bGPdata *gpd = scene->gpd;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent == ob) {
+ gpl->parent = obn;
}
}
-
- id_us_min(&ob->id);
- return obn;
}
- return NULL;
+
+ id_us_min(&ob->id);
+ return obn;
}
static void libblock_relink_scene_collection(SceneCollection *sc)
@@ -1678,7 +1675,9 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen
Object *ob = link->data;
/* an object may be in more than one collection */
if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
- link->data = single_object_users_object(bmain, scene, link->data, copy_groups);
+ if (!ID_IS_LINKED(ob) && ob->id.us > 1) {
+ link->data = single_object_users_object(bmain, scene, link->data, copy_groups);
+ }
}
}
@@ -1710,19 +1709,19 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
if (copy_groups && group->view_layer->object_bases.first) {
bool all_duplicated = true;
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
if (object->id.newid == NULL) {
all_duplicated = false;
break;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
if (all_duplicated) {
groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group));
- FOREACH_GROUP_BASE(groupn, base)
+ FOREACH_GROUP_BASE_BEGIN(groupn, base)
{
base->object = (Object *)base->object->id.newid;
}
@@ -1747,11 +1746,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
* button can be functional.*/
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
- FOREACH_SCENE_OBJECT(scene, ob_iter)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter)
{
ob_iter->flag &= ~OB_DONE;
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
/* tag only the one object */
ob->flag |= OB_DONE;
@@ -1791,7 +1790,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer
ID *id;
int a;
- FOREACH_OBJECT_FLAG(scene, view_layer, flag, ob)
+ FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob)
{
if (!ID_IS_LINKED(ob)) {
id = ob->data;
@@ -1849,7 +1848,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer
printf("ERROR %s: can't copy %s\n", __func__, id->name);
BLI_assert(!"This should never happen.");
- /* We need to end the FOREACH_OBJECT_FLAG iterator to prevent memory leak. */
+ /* We need to end the FOREACH_OBJECT_FLAG_BEGIN iterator to prevent memory leak. */
BKE_scene_objects_iterator_end(&iter_macro);
return;
}
@@ -1865,7 +1864,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer
}
}
}
- FOREACH_OBJECT_FLAG_END
+ FOREACH_OBJECT_FLAG_END;
me = bmain->mesh.first;
while (me) {
@@ -1876,12 +1875,14 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer
static void single_object_action_users(Scene *scene, ViewLayer *view_layer, const int flag)
{
- FOREACH_OBJECT_FLAG(scene, view_layer, flag, ob)
+ FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob)
+ {
if (!ID_IS_LINKED(ob)) {
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
BKE_animdata_copy_id_action(&ob->id, false);
}
- FOREACH_OBJECT_FLAG_END
+ }
+ FOREACH_OBJECT_FLAG_END;
}
static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag, const bool do_textures)
@@ -1890,7 +1891,8 @@ static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, c
Tex *tex;
int a, b;
- FOREACH_OBJECT_FLAG(scene, view_layer, flag, ob)
+ FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob)
+ {
if (!ID_IS_LINKED(ob)) {
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
@@ -1920,7 +1922,8 @@ static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, c
}
}
}
- FOREACH_OBJECT_FLAG_END
+ }
+ FOREACH_OBJECT_FLAG_END;
}
static void do_single_tex_user(Main *bmain, Tex **from)
@@ -2045,13 +2048,13 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
{
IDP_RelinkProperty(scene->id.properties);
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
if (!ID_IS_LINKED(ob)) {
IDP_RelinkProperty(ob->id.properties);
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
if (scene->nodetree) {
IDP_RelinkProperty(scene->nodetree->id.properties);
@@ -2425,7 +2428,7 @@ static int make_override_static_exec(bContext *C, wmOperator *op)
/* 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)
+ FOREACH_GROUP_OBJECT_BEGIN(obgroup->dup_group, ob)
{
make_override_static_tag_object(obact, ob);
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 8a62438dc80..f416f499b6a 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -124,78 +124,49 @@ void ED_object_base_activate(bContext *C, Base *base)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
WorkSpace *workspace = CTX_wm_workspace(C);
- bool reset = true;
- if (base) {
- Object *ob_prev = OBACT(view_layer);
- Object *ob_curr = base->object;
- if (ob_prev != NULL) {
- if (ob_prev->type == ob_curr->type) {
- reset = false;
- }
- }
- }
-
eObjectMode object_mode = workspace->object_mode;
+ eObjectMode object_mode_set = OB_MODE_OBJECT;
+ if (base && ED_workspace_object_mode_in_other_window(
+ wm, win, base->object,
+ &object_mode_set))
{
+ /* Sync existing object mode with workspace. */
+ workspace->object_mode = object_mode_set;
+ view_layer->basact = base;
+ }
+ else {
+ /* Apply the workspaces mode to the object (when possible). */
Scene *scene = CTX_data_scene(C);
+ Object *obact = base ? base->object : NULL;
/* We don't know the previous active object in update.
*
* Not correct because it's possible other work-spaces use these.
* although that's a corner case. */
- if (workspace->object_mode & OB_MODE_EDIT) {
- FOREACH_OBJECT(view_layer, ob) {
- if (ob != base->object) {
- if (BKE_object_is_in_editmode(ob)) {
- ED_object_editmode_exit_ex(NULL, workspace, scene, ob, EM_FREEDATA);
- }
- }
- }
- FOREACH_OBJECT_END;
- }
- else if (workspace->object_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT)) {
+ if (workspace->object_mode & OB_MODE_ALL_MODE_DATA) {
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
- FOREACH_OBJECT(view_layer, ob) {
- if (ob != base->object) {
- if (ob->sculpt) {
- switch (ob->sculpt->mode_type) {
- case OB_MODE_VERTEX_PAINT:
- {
- ED_object_vpaintmode_exit_ex(workspace, ob);
- break;
- }
- case OB_MODE_WEIGHT_PAINT:
- {
- ED_object_wpaintmode_exit_ex(workspace, ob);
- break;
- }
- case OB_MODE_SCULPT:
- {
- ED_object_sculptmode_exit_ex(&eval_ctx, workspace, scene, ob);
- break;
- }
- }
+ FOREACH_OBJECT_BEGIN(view_layer, ob) {
+ if (ob != obact) {
+ if (ED_object_mode_generic_has_data(&eval_ctx, ob) &&
+ ED_workspace_object_mode_in_other_window(wm, win, ob, NULL) == false)
+ {
+ ED_object_mode_generic_exit(&eval_ctx, workspace, scene, ob);
}
}
}
FOREACH_OBJECT_END;
}
- }
- workspace->object_mode = OB_MODE_OBJECT;
+ workspace->object_mode = OB_MODE_OBJECT;
- view_layer->basact = base;
+ view_layer->basact = base;
- if (reset == false) {
- wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_enum_set(&ptr, "mode", object_mode);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ ED_object_mode_generic_enter(C, object_mode);
}
if (base) {
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index b336b560ef2..7ea1a04f31f 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1286,7 +1286,7 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewContext vc;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (!object_is_target_compat(vc.obact)) {
/* Falls back to texture space transform. */
@@ -1343,9 +1343,9 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
CTX_DATA_END;
xfd->object_data = object_data;
- xfd->object_data_len = BLI_array_count(object_data);
+ xfd->object_data_len = BLI_array_len(object_data);
- if (xfd->object_data_len != BLI_array_count(object_data)) {
+ if (xfd->object_data_len != BLI_array_len(object_data)) {
xfd->object_data = MEM_reallocN(xfd->object_data, xfd->object_data_len * sizeof(*xfd->object_data));
}
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 8c6ccb7e8f0..eb04de5feb2 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1192,7 +1192,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
}
/* Append a and b verts to array, if not yet present. */
- k = BLI_array_count(verts);
+ k = BLI_array_len(verts);
/* XXX Maybe a == b is enough? */
while (k-- && !(a == b && a == -1)) {
if (verts[k] == a)
@@ -1214,7 +1214,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
}
/* Do not free the array! */
- *count = BLI_array_count(verts);
+ *count = BLI_array_len(verts);
return verts;
}
@@ -3360,7 +3360,7 @@ static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob_active = ED_object_context(C);
int retval = OPERATOR_CANCELLED;
- FOREACH_SCENE_OBJECT(scene, ob_iter)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter)
{
if (ob_iter->type == ob_active->type) {
if (ob_iter != ob_active && ob_iter->data == ob_active->data) {
@@ -3376,7 +3376,7 @@ static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
return retval;
}
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 3cecdccd758..3705ff9d41a 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -41,6 +41,7 @@ set(SRC
dynamicpaint_ops.c
particle_boids.c
particle_edit.c
+ particle_edit_undo.c
particle_object.c
physics_fluid.c
physics_ops.c
@@ -49,6 +50,7 @@ set(SRC
rigidbody_object.c
rigidbody_world.c
+ particle_edit_utildefines.h
physics_intern.h
)
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 376e4659b92..224790269e2 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -29,7 +29,6 @@
* \ingroup edphys
*/
-
#include <stdlib.h>
#include <math.h>
#include <string.h>
@@ -72,6 +71,7 @@
#include "ED_physics.h"
#include "ED_mesh.h"
#include "ED_particle.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
#include "GPU_immediate.h"
@@ -87,28 +87,7 @@
#include "physics_intern.h"
-void PE_create_particle_edit(
- const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob,
- PointCache *cache, ParticleSystem *psys);
-void PTCacheUndo_clear(PTCacheEdit *edit);
-void recalc_lengths(PTCacheEdit *edit);
-void recalc_emitter_field(Object *ob, ParticleSystem *psys);
-void update_world_cos(Object *ob, PTCacheEdit *edit);
-
-#define KEY_K PTCacheEditKey *key; int k
-#define POINT_P PTCacheEditPoint *point; int p
-#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
-#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
-#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
-#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
-#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
-#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
-#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
-#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
-#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
-#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
-
-#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
+#include "particle_edit_utildefines.h"
/**************************** utilities *******************************/
@@ -372,6 +351,7 @@ typedef struct PEData {
DerivedMesh *dm;
PTCacheEdit *edit;
BVHTreeFromMesh shape_bvh;
+ EvaluationContext eval_ctx;
const int *mval;
rcti *rect;
@@ -404,6 +384,7 @@ static void PE_set_data(bContext *C, PEData *data)
data->scene = CTX_data_scene(C);
data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
+ CTX_data_eval_ctx(C, &data->eval_ctx);
data->edit = PE_get_current(data->scene, data->view_layer, data->ob);
}
@@ -411,17 +392,14 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
{
PE_set_data(C, data);
- view3d_set_viewcontext(C, &data->vc);
+ ED_view3d_viewcontext_init(C, &data->vc);
if (V3D_IS_ZBUF(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
-
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- ED_view3d_backbuf_validate(&eval_ctx, &data->vc);
+ ED_view3d_backbuf_validate(&data->eval_ctx, &data->vc);
/* we may need to force an update here by setting the rv3d as dirty
* for now it seems ok, but take care!:
* rv3d->depths->dirty = 1; */
@@ -1166,15 +1144,12 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys)
BLI_kdtree_balance(edit->emitter_field);
}
-static void PE_update_selection(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int useflag)
+static void PE_update_selection(const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, eval_ctx->view_layer, ob);
HairKey *hkey;
- EvaluationContext eval_ctx;
POINT_P; KEY_K;
- CTX_data_eval_ctx(C, &eval_ctx);
-
/* flag all particles to be updated if not using flag */
if (!useflag)
LOOP_POINTS
@@ -1190,7 +1165,7 @@ static void PE_update_selection(const bContext *C, Scene *scene, ViewLayer *view
}
}
- psys_cache_edit_paths(&eval_ctx, scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(eval_ctx, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
@@ -1276,12 +1251,12 @@ static void update_velocities(PTCacheEdit *edit)
}
}
-void PE_update_object(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, int useflag)
+void PE_update_object(const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int useflag)
{
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset= PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit = PE_get_current(scene, eval_ctx->view_layer, ob);
POINT_P;
if (!edit)
@@ -1418,9 +1393,10 @@ static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, in
static int pe_select_all_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
POINT_P; KEY_K;
int action = RNA_enum_get(op->ptr, "action");
@@ -1443,7 +1419,7 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1501,7 +1477,7 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec
else
for_mouse_hit_keys(&data, toggle_key_select, 1);
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&data.eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1542,7 +1518,7 @@ static int select_roots_exec(bContext *C, wmOperator *op)
data.select_action = action;
foreach_point(&data, select_root);
- PE_update_selection(C, data.scene, data.view_layer, data.ob, 1);
+ PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1607,7 +1583,7 @@ static int select_tips_exec(bContext *C, wmOperator *op)
data.select_action = action;
foreach_point(&data, select_tip);
- PE_update_selection(C, data.scene, data.view_layer, data.ob, 1);
+ PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1646,7 +1622,6 @@ static int select_random_exec(bContext *C, wmOperator *op)
PEData data;
int type;
Scene *scene;
- ViewLayer *view_layer;
Object *ob;
/* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
@@ -1666,9 +1641,8 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
scene = CTX_data_scene(C);
- view_layer = CTX_data_view_layer(C);
ob = CTX_data_active_object(C);
- edit = PE_get_current(scene, view_layer, ob);
+ edit = PE_get_current(scene, data.eval_ctx.view_layer, ob);
rng = BLI_rng_new_srandom(seed);
@@ -1693,7 +1667,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
BLI_rng_free(rng);
- PE_update_selection(C, data.scene, data.view_layer, data.ob, 1);
+ PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1737,7 +1711,7 @@ static int select_linked_exec(bContext *C, wmOperator *op)
data.select= !RNA_boolean_get(op->ptr, "deselect");
for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
- PE_update_selection(C, data.scene, data.view_layer, data.ob, 1);
+ PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1802,7 +1776,7 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
for_mouse_hit_keys(&data, select_key, 0);
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&data.eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1828,7 +1802,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
for_mouse_hit_keys(&data, select_key, 0);
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&data.eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1917,7 +1891,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool
}
}
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&data.eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1929,10 +1903,13 @@ static int hide_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
+
+ PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
POINT_P; KEY_K;
-
+
+
if (RNA_enum_get(op->ptr, "unselected")) {
LOOP_UNSELECTED_POINTS {
point->flag |= PEP_HIDE;
@@ -1952,7 +1929,7 @@ static int hide_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1982,8 +1959,9 @@ static int reveal_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
Scene *scene= CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
+ PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P; KEY_K;
@@ -1998,7 +1976,7 @@ static int reveal_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(C, scene, view_layer, ob, 1);
+ PE_update_selection(&eval_ctx, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -2060,7 +2038,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
PE_set_data(C, &data);
foreach_point(&data, select_less_keys);
- PE_update_selection(C, data.scene, data.view_layer, data.ob, 1);
+ PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -2122,7 +2100,7 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
PE_set_data(C, &data);
foreach_point(&data, select_more_keys);
- PE_update_selection(C, data.scene, data.view_layer, data.ob, 1);
+ PE_update_selection(&data.eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -2225,7 +2203,7 @@ static int rekey_exec(bContext *C, wmOperator *op)
foreach_selected_point(&data, rekey_particle);
recalc_lengths(data.edit);
- PE_update_object(&eval_ctx, data.scene, data.view_layer, data.ob, 1);
+ PE_update_object(&eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -2566,7 +2544,7 @@ static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
foreach_point(&data, subdivide_particle);
recalc_lengths(data.edit);
- PE_update_object(&eval_ctx, data.scene, data.view_layer, data.ob, 1);
+ PE_update_object(&eval_ctx, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -4029,7 +4007,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
- PE_update_object(&eval_ctx, scene, view_layer, ob, 1);
+ PE_update_object(&eval_ctx, scene, ob, 1);
}
}
@@ -4265,9 +4243,6 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
if (!PE_start_edit(edit))
return OPERATOR_CANCELLED;
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
-
/* disable locking temporatily for disconnected hair */
if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
pset->flag &= ~PE_LOCK_FIRST;
@@ -4296,7 +4271,7 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
- PE_update_object(&eval_ctx, scene, view_layer, ob, 1);
+ PE_update_object(&data.eval_ctx, scene, ob, 1);
}
if (edit->psys) {
@@ -4330,293 +4305,6 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
-/*********************** undo ***************************/
-
-static void free_PTCacheUndo(PTCacheUndo *undo)
-{
- PTCacheEditPoint *point;
- int i;
-
- for (i=0, point=undo->points; i<undo->totpoint; i++, point++) {
- if (undo->particles && (undo->particles + i)->hair)
- MEM_freeN((undo->particles + i)->hair);
- if (point->keys)
- MEM_freeN(point->keys);
- }
- if (undo->points)
- MEM_freeN(undo->points);
-
- if (undo->particles)
- MEM_freeN(undo->particles);
-
- BKE_ptcache_free_mem(&undo->mem_cache);
-}
-
-static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
-{
- PTCacheEditPoint *point;
- int i;
-
- undo->totpoint= edit->totpoint;
-
- if (edit->psys) {
- ParticleData *pa;
-
- pa= undo->particles= MEM_dupallocN(edit->psys->particles);
-
- for (i=0; i<edit->totpoint; i++, pa++)
- pa->hair= MEM_dupallocN(pa->hair);
-
- undo->psys_flag = edit->psys->flag;
- }
- else {
- PTCacheMem *pm;
-
- BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
- pm = undo->mem_cache.first;
-
- for (; pm; pm=pm->next) {
- for (i=0; i<BPHYS_TOT_DATA; i++)
- pm->data[i] = MEM_dupallocN(pm->data[i]);
- }
- }
-
- point= undo->points = MEM_dupallocN(edit->points);
- undo->totpoint = edit->totpoint;
-
- for (i=0; i<edit->totpoint; i++, point++) {
- point->keys= MEM_dupallocN(point->keys);
- /* no need to update edit key->co & key->time pointers here */
- }
-}
-
-static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
-{
- ParticleSystem *psys = edit->psys;
- ParticleData *pa;
- HairKey *hkey;
- POINT_P; KEY_K;
-
- LOOP_POINTS {
- if (psys && psys->particles[p].hair)
- MEM_freeN(psys->particles[p].hair);
-
- if (point->keys)
- MEM_freeN(point->keys);
- }
- if (psys && psys->particles)
- MEM_freeN(psys->particles);
- if (edit->points)
- MEM_freeN(edit->points);
- if (edit->mirror_cache) {
- MEM_freeN(edit->mirror_cache);
- edit->mirror_cache= NULL;
- }
-
- edit->points= MEM_dupallocN(undo->points);
- edit->totpoint = undo->totpoint;
-
- LOOP_POINTS {
- point->keys= MEM_dupallocN(point->keys);
- }
-
- if (psys) {
- psys->particles= MEM_dupallocN(undo->particles);
-
- psys->totpart= undo->totpoint;
-
- LOOP_POINTS {
- pa = psys->particles + p;
- hkey= pa->hair = MEM_dupallocN(pa->hair);
-
- LOOP_KEYS {
- key->co= hkey->co;
- key->time= &hkey->time;
- hkey++;
- }
- }
-
- psys->flag = undo->psys_flag;
- }
- else {
- PTCacheMem *pm;
- int i;
-
- BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
-
- BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
-
- pm = edit->pid.cache->mem_cache.first;
-
- for (; pm; pm=pm->next) {
- for (i=0; i<BPHYS_TOT_DATA; i++)
- pm->data[i] = MEM_dupallocN(pm->data[i]);
-
- BKE_ptcache_mem_pointers_init(pm);
-
- LOOP_POINTS {
- LOOP_KEYS {
- if ((int)key->ftime == (int)pm->frame) {
- key->co = pm->cur[BPHYS_DATA_LOCATION];
- key->vel = pm->cur[BPHYS_DATA_VELOCITY];
- key->rot = pm->cur[BPHYS_DATA_ROTATION];
- key->time = &key->ftime;
- }
- }
- BKE_ptcache_mem_pointers_incr(pm);
- }
- }
- }
-}
-
-void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
- PTCacheUndo *undo;
- int nr;
-
- if (!edit) return;
-
- /* remove all undos after (also when curundo==NULL) */
- while (edit->undo.last != edit->curundo) {
- undo= edit->undo.last;
- BLI_remlink(&edit->undo, undo);
- free_PTCacheUndo(undo);
- MEM_freeN(undo);
- }
-
- /* make new */
- edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
- BLI_strncpy(undo->name, str, sizeof(undo->name));
- BLI_addtail(&edit->undo, undo);
-
- /* and limit amount to the maximum */
- nr= 0;
- undo= edit->undo.last;
- while (undo) {
- nr++;
- if (nr==U.undosteps) break;
- undo= undo->prev;
- }
- if (undo) {
- while (edit->undo.first != undo) {
- PTCacheUndo *first= edit->undo.first;
- BLI_remlink(&edit->undo, first);
- free_PTCacheUndo(first);
- MEM_freeN(first);
- }
- }
-
- /* copy */
- make_PTCacheUndo(edit, edit->curundo);
-}
-
-void PE_undo_step(Scene *scene, ViewLayer *view_layer, int step)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-
- if (!edit) return;
-
- if (step==0) {
- get_PTCacheUndo(edit, edit->curundo);
- }
- else if (step==1) {
-
- if (edit->curundo==NULL || edit->curundo->prev==NULL) {
- /* pass */
- }
- else {
- if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name);
- edit->curundo= edit->curundo->prev;
- get_PTCacheUndo(edit, edit->curundo);
- }
- }
- else {
- /* curundo has to remain current situation! */
-
- if (edit->curundo==NULL || edit->curundo->next==NULL) {
- /* pass */
- }
- else {
- get_PTCacheUndo(edit, edit->curundo->next);
- edit->curundo= edit->curundo->next;
- if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name);
- }
- }
-
- DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA);
-}
-
-bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-
- if (edit) {
- return (edit->undo.last != edit->undo.first);
- }
- return 0;
-}
-
-void PTCacheUndo_clear(PTCacheEdit *edit)
-{
- PTCacheUndo *undo;
-
- if (edit==NULL) return;
-
- undo= edit->undo.first;
- while (undo) {
- free_PTCacheUndo(undo);
- undo= undo->next;
- }
- BLI_freelistN(&edit->undo);
- edit->curundo= NULL;
-}
-
-void PE_undo(Scene *scene, ViewLayer *view_layer)
-{
- PE_undo_step(scene, view_layer, 1);
-}
-
-void PE_redo(Scene *scene, ViewLayer *view_layer)
-{
- PE_undo_step(scene, view_layer, -1);
-}
-
-void PE_undo_number(Scene *scene, ViewLayer *view_layer, int nr)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
- PTCacheUndo *undo;
- int a=0;
-
- for (undo= edit->undo.first; undo; undo= undo->next, a++) {
- if (a==nr) break;
- }
- edit->curundo= undo;
- PE_undo_step(scene, view_layer, 0);
-}
-
-
-/* get name of undo item, return null if no item with this index */
-/* if active pointer, set it to 1 if true */
-const char *PE_undo_get_name(Scene *scene, ViewLayer *view_layer, int nr, bool *r_active)
-{
- PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
- PTCacheUndo *undo;
-
- if (r_active) *r_active = false;
-
- if (edit) {
- undo= BLI_findlink(&edit->undo, nr);
- if (undo) {
- if (r_active && (undo == edit->curundo)) {
- *r_active = true;
- }
- return undo->name;
- }
- }
- return NULL;
-}
-
/************************ utilities ******************************/
int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
@@ -4761,7 +4449,7 @@ void PE_create_particle_edit(
recalc_lengths(edit);
if (psys && !cache)
recalc_emitter_field(ob, psys);
- PE_update_object(eval_ctx, scene, view_layer, ob, 1);
+ PE_update_object(eval_ctx, scene, ob, 1);
PTCacheUndo_clear(edit);
PE_undo_push(scene, view_layer, "Original");
@@ -4786,6 +4474,7 @@ static int particle_edit_toggle_poll(bContext *C)
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
struct WorkSpace *workspace = CTX_wm_workspace(C);
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
@@ -4820,6 +4509,8 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
}
+ ED_workspace_object_mode_sync_from_object(wm, workspace, ob);
+
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return OPERATOR_FINISHED;
@@ -4972,8 +4663,10 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
+
+ PTCacheEdit *edit = PE_get_current(scene, eval_ctx.view_layer, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
@@ -4981,10 +4674,8 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
}
scale_points_to_length(edit, average_length);
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
- PE_update_object(&eval_ctx, scene, view_layer, ob, 1);
+ PE_update_object(&eval_ctx, scene, ob, 1);
if (edit->psys) {
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
}
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
new file mode 100644
index 00000000000..45eb5923e57
--- /dev/null
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -0,0 +1,341 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/physics/particle_edit_undo.c
+ * \ingroup edphys
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_particle.h"
+
+#include "particle_edit_utildefines.h"
+
+#include "physics_intern.h"
+
+static void free_PTCacheUndo(PTCacheUndo *undo)
+{
+ PTCacheEditPoint *point;
+ int i;
+
+ for (i=0, point=undo->points; i<undo->totpoint; i++, point++) {
+ if (undo->particles && (undo->particles + i)->hair)
+ MEM_freeN((undo->particles + i)->hair);
+ if (point->keys)
+ MEM_freeN(point->keys);
+ }
+ if (undo->points)
+ MEM_freeN(undo->points);
+
+ if (undo->particles)
+ MEM_freeN(undo->particles);
+
+ BKE_ptcache_free_mem(&undo->mem_cache);
+}
+
+static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
+{
+ PTCacheEditPoint *point;
+ int i;
+
+ undo->totpoint= edit->totpoint;
+
+ if (edit->psys) {
+ ParticleData *pa;
+
+ pa= undo->particles= MEM_dupallocN(edit->psys->particles);
+
+ for (i=0; i<edit->totpoint; i++, pa++)
+ pa->hair= MEM_dupallocN(pa->hair);
+
+ undo->psys_flag = edit->psys->flag;
+ }
+ else {
+ PTCacheMem *pm;
+
+ BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
+ pm = undo->mem_cache.first;
+
+ for (; pm; pm=pm->next) {
+ for (i=0; i<BPHYS_TOT_DATA; i++)
+ pm->data[i] = MEM_dupallocN(pm->data[i]);
+ }
+ }
+
+ point= undo->points = MEM_dupallocN(edit->points);
+ undo->totpoint = edit->totpoint;
+
+ for (i=0; i<edit->totpoint; i++, point++) {
+ point->keys= MEM_dupallocN(point->keys);
+ /* no need to update edit key->co & key->time pointers here */
+ }
+}
+
+static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
+{
+ ParticleSystem *psys = edit->psys;
+ ParticleData *pa;
+ HairKey *hkey;
+ POINT_P; KEY_K;
+
+ LOOP_POINTS {
+ if (psys && psys->particles[p].hair)
+ MEM_freeN(psys->particles[p].hair);
+
+ if (point->keys)
+ MEM_freeN(point->keys);
+ }
+ if (psys && psys->particles)
+ MEM_freeN(psys->particles);
+ if (edit->points)
+ MEM_freeN(edit->points);
+ if (edit->mirror_cache) {
+ MEM_freeN(edit->mirror_cache);
+ edit->mirror_cache= NULL;
+ }
+
+ edit->points= MEM_dupallocN(undo->points);
+ edit->totpoint = undo->totpoint;
+
+ LOOP_POINTS {
+ point->keys= MEM_dupallocN(point->keys);
+ }
+
+ if (psys) {
+ psys->particles= MEM_dupallocN(undo->particles);
+
+ psys->totpart= undo->totpoint;
+
+ LOOP_POINTS {
+ pa = psys->particles + p;
+ hkey= pa->hair = MEM_dupallocN(pa->hair);
+
+ LOOP_KEYS {
+ key->co= hkey->co;
+ key->time= &hkey->time;
+ hkey++;
+ }
+ }
+
+ psys->flag = undo->psys_flag;
+ }
+ else {
+ PTCacheMem *pm;
+ int i;
+
+ BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
+
+ BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
+
+ pm = edit->pid.cache->mem_cache.first;
+
+ for (; pm; pm=pm->next) {
+ for (i=0; i<BPHYS_TOT_DATA; i++)
+ pm->data[i] = MEM_dupallocN(pm->data[i]);
+
+ BKE_ptcache_mem_pointers_init(pm);
+
+ LOOP_POINTS {
+ LOOP_KEYS {
+ if ((int)key->ftime == (int)pm->frame) {
+ key->co = pm->cur[BPHYS_DATA_LOCATION];
+ key->vel = pm->cur[BPHYS_DATA_VELOCITY];
+ key->rot = pm->cur[BPHYS_DATA_ROTATION];
+ key->time = &key->ftime;
+ }
+ }
+ BKE_ptcache_mem_pointers_incr(pm);
+ }
+ }
+ }
+}
+
+void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str)
+{
+ PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+ PTCacheUndo *undo;
+ int nr;
+
+ if (!edit) return;
+
+ /* remove all undos after (also when curundo==NULL) */
+ while (edit->undo.last != edit->curundo) {
+ undo= edit->undo.last;
+ BLI_remlink(&edit->undo, undo);
+ free_PTCacheUndo(undo);
+ MEM_freeN(undo);
+ }
+
+ /* make new */
+ edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
+ BLI_strncpy(undo->name, str, sizeof(undo->name));
+ BLI_addtail(&edit->undo, undo);
+
+ /* and limit amount to the maximum */
+ nr= 0;
+ undo= edit->undo.last;
+ while (undo) {
+ nr++;
+ if (nr==U.undosteps) break;
+ undo= undo->prev;
+ }
+ if (undo) {
+ while (edit->undo.first != undo) {
+ PTCacheUndo *first= edit->undo.first;
+ BLI_remlink(&edit->undo, first);
+ free_PTCacheUndo(first);
+ MEM_freeN(first);
+ }
+ }
+
+ /* copy */
+ make_PTCacheUndo(edit, edit->curundo);
+}
+
+void PE_undo_step(Scene *scene, ViewLayer *view_layer, int step)
+{
+ PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+
+ if (!edit) return;
+
+ if (step==0) {
+ get_PTCacheUndo(edit, edit->curundo);
+ }
+ else if (step==1) {
+
+ if (edit->curundo==NULL || edit->curundo->prev==NULL) {
+ /* pass */
+ }
+ else {
+ if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name);
+ edit->curundo= edit->curundo->prev;
+ get_PTCacheUndo(edit, edit->curundo);
+ }
+ }
+ else {
+ /* curundo has to remain current situation! */
+
+ if (edit->curundo==NULL || edit->curundo->next==NULL) {
+ /* pass */
+ }
+ else {
+ get_PTCacheUndo(edit, edit->curundo->next);
+ edit->curundo= edit->curundo->next;
+ if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name);
+ }
+ }
+
+ DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA);
+}
+
+bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer)
+{
+ PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+
+ if (edit) {
+ return (edit->undo.last != edit->undo.first);
+ }
+ return 0;
+}
+
+void PTCacheUndo_clear(PTCacheEdit *edit)
+{
+ PTCacheUndo *undo;
+
+ if (edit==NULL) return;
+
+ undo= edit->undo.first;
+ while (undo) {
+ free_PTCacheUndo(undo);
+ undo= undo->next;
+ }
+ BLI_freelistN(&edit->undo);
+ edit->curundo= NULL;
+}
+
+void PE_undo(Scene *scene, ViewLayer *view_layer)
+{
+ PE_undo_step(scene, view_layer, 1);
+}
+
+void PE_redo(Scene *scene, ViewLayer *view_layer)
+{
+ PE_undo_step(scene, view_layer, -1);
+}
+
+void PE_undo_number(Scene *scene, ViewLayer *view_layer, int nr)
+{
+ PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+ PTCacheUndo *undo;
+ int a=0;
+
+ for (undo= edit->undo.first; undo; undo= undo->next, a++) {
+ if (a==nr) break;
+ }
+ edit->curundo= undo;
+ PE_undo_step(scene, view_layer, 0);
+}
+
+
+/* get name of undo item, return null if no item with this index */
+/* if active pointer, set it to 1 if true */
+const char *PE_undo_get_name(Scene *scene, ViewLayer *view_layer, int nr, bool *r_active)
+{
+ PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+ PTCacheUndo *undo;
+
+ if (r_active) *r_active = false;
+
+ if (edit) {
+ undo= BLI_findlink(&edit->undo, nr);
+ if (undo) {
+ if (r_active && (undo == edit->curundo)) {
+ *r_active = true;
+ }
+ return undo->name;
+ }
+ }
+ return NULL;
+}
diff --git a/source/blender/editors/physics/particle_edit_utildefines.h b/source/blender/editors/physics/particle_edit_utildefines.h
new file mode 100644
index 00000000000..7608b885459
--- /dev/null
+++ b/source/blender/editors/physics/particle_edit_utildefines.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/physics/particle_edit_utildefines.h
+ * \ingroup edphys
+ */
+
+#ifndef __PARTICLE_EDIT_UTILDEFNIES_H__
+#define __PARTICLE_EDIT_UTILDEFNIES_H__
+
+#define KEY_K PTCacheEditKey *key; int k
+#define POINT_P PTCacheEditPoint *point; int p
+#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
+#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
+#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
+#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
+#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
+#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
+#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
+#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
+#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
+#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
+
+#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
+
+#endif /* __PARTICLE_EDIT_UTILDEFNIES_H__ */
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 7a22a0d81d9..cbdb6e4592c 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -69,32 +69,9 @@
#include "UI_resources.h"
-#include "physics_intern.h"
+#include "particle_edit_utildefines.h"
-extern void PE_create_particle_edit(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, PointCache *cache, ParticleSystem *psys);
-extern void PTCacheUndo_clear(PTCacheEdit *edit);
-extern void recalc_lengths(PTCacheEdit *edit);
-extern void recalc_emitter_field(Object *ob, ParticleSystem *psys);
-extern void update_world_cos(Object *ob, PTCacheEdit *edit);
-
-#define KEY_K PTCacheEditKey *key; int k
-#define POINT_P PTCacheEditPoint *point; int p
-#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
-#if 0
-#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
-#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
-#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
-#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
-#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
-#endif
-#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
-#if 0
-#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
-#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
-#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
-
-#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
-#endif
+#include "physics_intern.h"
static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}};
@@ -618,7 +595,7 @@ static void disconnect_hair(
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF))
pset->brushtype = PE_BRUSH_NONE;
- PE_update_object(eval_ctx, scene, view_layer, ob, 0);
+ PE_update_object(eval_ctx, scene, ob, 0);
}
static int disconnect_hair_exec(bContext *C, wmOperator *op)
@@ -855,7 +832,7 @@ static bool remap_hair_emitter(
psys_free_path_cache(target_psys, target_edit);
- PE_update_object(eval_ctx, scene, view_layer, target_ob, 0);
+ PE_update_object(eval_ctx, scene, target_ob, 0);
return true;
}
@@ -987,7 +964,7 @@ static void copy_particle_edit(
recalc_lengths(edit);
recalc_emitter_field(ob, psys);
- PE_update_object(eval_ctx, scene, view_layer, ob, true);
+ PE_update_object(eval_ctx, scene, ob, true);
PTCacheUndo_clear(edit);
PE_undo_push(scene, view_layer, "Original");
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 6b6df15e987..8888589b5d7 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -33,6 +33,13 @@
#ifndef __PHYSICS_INTERN_H__
#define __PHYSICS_INTERN_H__
+struct EvaluationContext;
+struct Object;
+struct PTCacheEdit;
+struct ParticleSystem;
+struct PointCache;
+struct Scene;
+struct ViewLayer;
struct wmOperatorType;
/* particle_edit.c */
@@ -63,6 +70,14 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
+void PTCacheUndo_clear(struct PTCacheEdit *edit);
+void PE_create_particle_edit(
+ const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ViewLayer *view_layer,
+ struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
+void recalc_lengths(struct PTCacheEdit *edit);
+void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys);
+void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
+
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index a859f664dc8..b1d870a43ae 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -260,7 +260,7 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
PTCacheID *pid;
ListBase pidlist;
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
@@ -272,7 +272,7 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 0130b93babf..33ca6ea7495 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -297,7 +297,6 @@ 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;
Image *ima;
View3D *v3d = CTX_wm_view3d(C);
@@ -321,7 +320,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
}
re = RE_NewSceneRender(scene);
- RE_SetDepsgraph(re, CTX_data_depsgraph(C));
lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0;
G.is_break = false;
@@ -349,7 +347,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_SetReports(re, NULL);
// no redraw needed, we leave state as we entered it
- ED_update_for_newframe(mainp, scene, view_layer, depsgraph);
+ ED_update_for_newframe(mainp, scene, view_layer, CTX_data_depsgraph(C));
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
@@ -538,10 +536,8 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
int layer = BLI_findstringindex(&main_rr->layers,
(char *)rr->renlay->name,
offsetof(RenderLayer, name));
- if (layer != rj->last_layer) {
- sima->iuser.layer = layer;
- rj->last_layer = layer;
- }
+ sima->iuser.layer = layer;
+ rj->last_layer = layer;
}
iuser->pass = sima->iuser.pass;
@@ -639,7 +635,21 @@ static void render_image_restore_layer(RenderJob *rj)
if (sa == rj->sa) {
if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
- sima->iuser.layer = rj->orig_layer;
+
+ if (RE_HasSingleLayer(rj->re)) {
+ /* For single layer renders keep the active layer
+ * visible, or show the compositing result. */
+ RenderResult *rr = RE_AcquireResultRead(rj->re);
+ if(RE_HasCombinedLayer(rr)) {
+ sima->iuser.layer = 0;
+ }
+ RE_ReleaseResult(rj->re);
+ }
+ else {
+ /* For multiple layer render, set back the layer
+ * that was set at the start of rendering. */
+ sima->iuser.layer = rj->orig_layer;
+ }
}
return;
}
@@ -869,15 +879,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
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)) {
- /* ensure at least 1 area shows result */
- render_view_open(C, event->x, event->y, op->reports);
- 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))
return OPERATOR_CANCELLED;
@@ -1017,7 +1018,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
RE_current_scene_update_cb(re, rj, current_scene_update);
RE_stats_draw_cb(re, rj, image_renderinfo_cb);
RE_progress_cb(re, rj, render_progress_update);
- RE_SetDepsgraph(re, CTX_data_depsgraph(C));
rj->re = re;
G.is_break = false;
@@ -1088,6 +1088,7 @@ typedef struct RenderPreview {
wmJob *job;
Scene *scene;
+ EvaluationContext *eval_ctx;
Depsgraph *depsgraph;
ScrArea *sa;
ARegion *ar;
@@ -1336,7 +1337,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
WM_job_main_thread_lock_release(rp->job);
/* do preprocessing like building raytree, shadows, volumes, SSS */
- RE_Database_Preprocess(re);
+ RE_Database_Preprocess(rp->eval_ctx, re);
/* conversion not completed, need to do it again */
if (!rstats->convertdone) {
@@ -1402,6 +1403,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
static void render_view3d_free(void *customdata)
{
RenderPreview *rp = customdata;
+ DEG_evaluation_context_free(rp->eval_ctx);
MEM_freeN(rp);
}
@@ -1517,6 +1519,8 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
/* customdata for preview thread */
rp->scene = scene;
rp->depsgraph = depsgraph;
+ rp->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_PREVIEW);
+ CTX_data_eval_ctx(C, rp->eval_ctx);
rp->engine = engine;
rp->sa = CTX_wm_area(C);
rp->ar = CTX_wm_region(C);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 8eb9283790b..1f9894b3b9f 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -57,6 +57,8 @@
#include "DEG_depsgraph.h"
+#include "DRW_engine.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -323,6 +325,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
unsigned char *gp_rect;
unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
+ DRW_opengl_context_enable();
GPU_offscreen_bind(oglrender->ofs, true);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -342,6 +345,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
}
GPU_offscreen_unbind(oglrender->ofs, true);
+ DRW_opengl_context_disable();
MEM_freeN(gp_rect);
}
@@ -652,7 +656,9 @@ 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 */
+ DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */
ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, true, err_out);
+ DRW_opengl_context_disable();
if (!ofs) {
BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
@@ -841,7 +847,9 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
if (oglrender->fx)
GPU_fx_compositor_destroy(oglrender->fx);
+ DRW_opengl_context_enable();
GPU_offscreen_free(oglrender->ofs);
+ DRW_opengl_context_disable();
if (oglrender->is_sequencer) {
MEM_freeN(oglrender->seq_data.ibufs_arr);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index c76a6aa175a..79562ae386b 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -1376,7 +1376,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
sp->bmain = CTX_data_main(C);
sp->view_render = view_render;
- /* hardcoded preview .blend for cycles/internal, this should be solved
+ /* hardcoded preview .blend for Eevee + cycles/internal, this should be solved
* once with custom preview .blend path for external engines */
if ((method != PR_NODE_RENDER) && id_type != ID_TE && use_new_shading) {
sp->pr_main = G_pr_main_cycles;
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index d0077df73e4..da720272f67 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -42,6 +42,7 @@
#include "BLT_translation.h"
+#include "DNA_object_types.h"
#include "DNA_workspace_types.h"
#include "ED_object.h"
@@ -113,30 +114,51 @@ bool ED_scene_delete(bContext *C, Main *bmain, wmWindow *win, Scene *scene)
return true;
}
-void ED_scene_exit(bContext *C)
-{
- ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
-}
-
static ViewLayer *scene_change_get_new_view_layer(const WorkSpace *workspace, const Scene *scene_new)
{
ViewLayer *layer_new = BKE_workspace_view_layer_get(workspace, scene_new);
return layer_new ? layer_new : BKE_view_layer_from_scene_get(scene_new);
}
-void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const bScreen *active_screen)
+void ED_scene_change_update(
+ Main *bmain, bContext *C,
+ wmWindow *win, const bScreen *screen, Scene *scene_old, Scene *scene_new)
{
WorkSpace *workspace = CTX_wm_workspace(C);
ViewLayer *layer_new = scene_change_get_new_view_layer(workspace, scene_new);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene_new, layer_new, true);
+ Object *obact_new = OBACT(layer_new);
+
+ /* mode syncing */
+ EvaluationContext eval_ctx_old;
+ CTX_data_eval_ctx(C, &eval_ctx_old);
+ eObjectMode object_mode_old = workspace->object_mode;
+ ViewLayer *layer_old = BKE_view_layer_from_workspace_get(scene_old, workspace);
+ Object *obact_old = OBACT(layer_old);
+ bool obact_new_mode_exists = ED_object_mode_generic_exists(bmain->wm.first, obact_new, workspace->object_mode);
+
+ win->scene = scene_new;
CTX_data_scene_set(C, scene_new);
BKE_workspace_view_layer_set(workspace, layer_new, scene_new);
BKE_scene_set_background(bmain, scene_new);
DEG_graph_relations_update(depsgraph, bmain, scene_new, layer_new);
DEG_on_visible_update(bmain, false);
- ED_screen_update_after_scene_change(active_screen, scene_new, layer_new);
+ if (obact_new == obact_old) {
+ /* pass */
+ }
+ else {
+ ED_object_mode_generic_exit_or_other_window(&eval_ctx_old, bmain->wm.first, workspace, scene_old, obact_old);
+ if (obact_new_mode_exists) {
+ workspace->object_mode = object_mode_old;
+ }
+ else {
+ ED_object_mode_generic_enter_or_other_window(C, win, object_mode_old);
+ }
+ }
+
+ ED_screen_update_after_scene_change(screen, scene_new, layer_new);
ED_render_engine_changed(bmain);
ED_update_for_newframe(bmain, scene_new, layer_new, depsgraph);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 397090388ff..0443b145082 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -41,10 +41,10 @@
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
#include "RNA_types.h"
@@ -1879,6 +1879,7 @@ static ThemeColorID region_background_color_id(const bContext *C, const ARegion
void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical)
{
+ const WorkSpace *workspace = CTX_wm_workspace(C);
ScrArea *sa = CTX_wm_area(C);
uiStyle *style = UI_style_get_dpi();
uiBlock *block;
@@ -1929,6 +1930,11 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
continue;
}
+ /* If we're tagged, only use compatible. */
+ if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) {
+ continue;
+ }
+
/* draw panel */
if (pt->draw && (!pt->poll || pt->poll(C, pt))) {
BLI_SMALLSTACK_PUSH(pt_stack, pt);
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 2a48ae46b12..4c217a5e829 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -93,7 +93,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace);
Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL;
- Object *obedit = BKE_workspace_edit_object(workspace, scene);
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
@@ -104,11 +103,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_objects")) {
- FOREACH_VISIBLE_OBJECT(view_layer, ob)
+ FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, ob)
{
CTX_data_id_list_add(result, &ob->id);
}
- FOREACH_VISIBLE_BASE_END
+ FOREACH_VISIBLE_BASE_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -122,43 +121,43 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_objects")) {
- FOREACH_SELECTED_OBJECT(view_layer, ob)
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
{
CTX_data_id_list_add(result, &ob->id);
}
- FOREACH_SELECTED_OBJECT_END
+ FOREACH_SELECTED_OBJECT_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
else if (CTX_data_equals(member, "selected_editable_objects")) {
- FOREACH_SELECTED_OBJECT(view_layer, ob)
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
{
if (0 == BKE_object_is_libdata(ob)) {
CTX_data_id_list_add(result, &ob->id);
}
}
- FOREACH_SELECTED_OBJECT_END
+ FOREACH_SELECTED_OBJECT_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
else if (CTX_data_equals(member, "editable_objects")) {
/* Visible + Editable, but not necessarily selected */
- FOREACH_VISIBLE_OBJECT(view_layer, ob)
+ FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, ob)
{
if (0 == BKE_object_is_libdata(ob)) {
CTX_data_id_list_add(result, &ob->id);
}
}
- FOREACH_VISIBLE_OBJECT_END
+ FOREACH_VISIBLE_OBJECT_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
else if ( CTX_data_equals(member, "visible_bases")) {
- FOREACH_VISIBLE_BASE(view_layer, base)
+ FOREACH_VISIBLE_BASE_BEGIN(view_layer, base)
{
CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
}
- FOREACH_VISIBLE_BASE_END
+ FOREACH_VISIBLE_BASE_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -204,6 +203,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_bones") || CTX_data_equals(member, "editable_bones")) {
+ Object *obedit = BKE_workspace_edit_object(workspace, scene);
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
const bool editable_bones = CTX_data_equals(member, "editable_bones");
@@ -246,6 +246,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "selected_bones") || CTX_data_equals(member, "selected_editable_bones")) {
+ Object *obedit = BKE_workspace_edit_object(workspace, scene);
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
@@ -367,6 +368,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "edit_object")) {
/* convenience for now, 1 object per scene in editmode */
+ Object *obedit = BKE_workspace_edit_object(workspace, scene);
if (obedit)
CTX_data_id_pointer_set(result, &obedit->id);
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index c749d77869f..3ffb125cdde 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -485,6 +485,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
wmOrtho2(0.0f, size_x, 0.0f, size_y);
/* center */
gpuPushMatrix();
+ gpuLoadIdentity();
gpuTranslate2f(size_x * (1.0f - asp[0]) * 0.5f, size_y * (1.0f - asp[1]) * 0.5f);
screen_preview_scale_get(screen, size_x, size_y, asp, scale);
@@ -503,7 +504,7 @@ void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uns
GPU_offscreen_bind(offscreen, true);
glClearColor(0.0, 0.0, 0.0, 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
screen_preview_draw(screen, size_x, size_y);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 2e738d71a91..c20d95f8e1b 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1175,7 +1175,7 @@ bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *b
return NULL;
}
-void screen_changed_update(bContext *C, wmWindow *win, bScreen *sc)
+void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
{
Scene *scene = WM_window_get_active_scene(win);
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
@@ -1212,7 +1212,7 @@ bool ED_screen_change(bContext *C, bScreen *sc)
if (screen_new) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
WM_window_set_active_screen(win, workspace, sc);
- screen_changed_update(C, win, screen_new);
+ screen_change_update(C, win, screen_new);
return true;
}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 9214b4b7a68..11fb0666df4 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -51,7 +51,7 @@ void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_
bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y);
void screen_data_copy(bScreen *to, bScreen *from);
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
-void screen_changed_update(struct bContext *C, wmWindow *win, bScreen *sc);
+void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc);
bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, struct Main *bmain, struct bContext *C, wmWindow *win);
ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 6ec1ac2e239..e1bcec01a8a 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -36,6 +36,7 @@
#include "BKE_context.h"
#include "BKE_idcode.h"
#include "BKE_main.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -56,6 +57,8 @@
#include "RNA_access.h"
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -166,11 +169,38 @@ bool ED_workspace_change(
BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new);
if (screen_new) {
+ bool use_object_mode = false;
+
+ /* Store old context for exiting edit-mode. */
+ EvaluationContext eval_ctx_old;
+ CTX_data_eval_ctx(C, &eval_ctx_old);
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer_old = BKE_workspace_view_layer_get(workspace_old, scene);
+ Object *obact_old = OBACT(view_layer_old);
+
+ ViewLayer *view_layer_new = BKE_workspace_view_layer_get(workspace_new, scene);
+ Object *obact_new = OBACT(view_layer_new);
+
+ /* Handle object mode switching */
+ if ((workspace_old->object_mode != OB_MODE_OBJECT) ||
+ (workspace_new->object_mode != OB_MODE_OBJECT))
+ {
+ if ((workspace_old->object_mode == workspace_new->object_mode) &&
+ (obact_old == obact_new))
+ {
+ /* pass */
+ }
+ else {
+ use_object_mode = true;
+ }
+ }
+
+
WM_window_set_active_layout(win, workspace_new, layout_new);
WM_window_set_active_workspace(win, workspace_new);
/* update screen *after* changing workspace - which also causes the actual screen change */
- screen_changed_update(C, win, screen_new);
+ screen_change_update(C, win, screen_new);
workspace_change_update(workspace_new, workspace_old, C);
BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL);
@@ -179,6 +209,20 @@ bool ED_workspace_change(
WM_toolsystem_unlink(C, workspace_old);
WM_toolsystem_link(C, workspace_new);
+ if (use_object_mode) {
+ /* weak, set it back so it's used when activating again. */
+ eObjectMode object_mode = workspace_old->object_mode;
+ ED_object_mode_generic_exit_or_other_window(&eval_ctx_old, bmain->wm.first, workspace_old, scene, obact_old);
+ workspace_old->object_mode = object_mode;
+ ED_workspace_object_mode_sync_from_object(bmain->wm.first, workspace_old, obact_old);
+ ED_object_mode_generic_enter_or_other_window(C, NULL, workspace_new->object_mode);
+ }
+ else {
+ if (obact_new == NULL) {
+ workspace_new->object_mode = OB_MODE_OBJECT;
+ }
+ }
+
return true;
}
@@ -205,6 +249,7 @@ WorkSpace *ED_workspace_duplicate(
BLI_duplicatelist(transform_orientations_new, transform_orientations_old);
workspace_new->tool = workspace_old->tool;
+ workspace_new->object_mode = workspace_old->object_mode;
for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace_new, layout_old, win);
@@ -261,6 +306,63 @@ void ED_workspace_view_layer_unset(
}
}
+/**
+ * When a work-space mode has changed,
+ * flush it to all other visible work-spaces using the same object
+ * since we don't support one object being in two different modes at once.
+ * \note We could support this but it's more trouble than it's worth.
+ */
+
+void ED_workspace_object_mode_sync_from_object(wmWindowManager *wm, WorkSpace *workspace, Object *obact)
+{
+ if (obact == NULL) {
+ return;
+ }
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace_iter = BKE_workspace_active_get(win->workspace_hook);
+ if ((workspace != workspace_iter) && (workspace->object_mode != workspace_iter->object_mode)) {
+ Scene *scene_iter = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene_iter, workspace_iter);
+ if (obact == OBACT(view_layer)) {
+ workspace_iter->object_mode = workspace->object_mode;
+ /* TODO(campbell), use msgbus */
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene_iter);
+ }
+ }
+ }
+}
+
+void ED_workspace_object_mode_sync_from_scene(wmWindowManager *wm, WorkSpace *workspace, Scene *scene)
+{
+ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
+ if (view_layer) {
+ Object *obact = OBACT(view_layer);
+ ED_workspace_object_mode_sync_from_object(wm, workspace, obact);
+ }
+}
+
+bool ED_workspace_object_mode_in_other_window(
+ struct wmWindowManager *wm, const wmWindow *win_compare, Object *obact,
+ eObjectMode *r_object_mode)
+{
+ for (wmWindow *win_iter = wm->windows.first; win_iter; win_iter = win_iter->next) {
+ if (win_compare != win_iter) {
+ WorkSpace *workspace_iter = BKE_workspace_active_get(win_iter->workspace_hook);
+ Scene *scene_iter = WM_window_get_active_scene(win_iter);
+ ViewLayer *view_layer_iter = BKE_view_layer_from_workspace_get(scene_iter, workspace_iter);
+ Object *obact_iter = OBACT(view_layer_iter);
+ if (obact == obact_iter) {
+ if (r_object_mode) {
+ *r_object_mode = workspace_iter->object_mode;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
/** \} Workspace API */
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 3a43c7a6585..d2063d15ddf 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1033,7 +1033,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* can't use stroke vc here because this will be called during
* mouse over too, not just during a stroke */
ViewContext vc;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
return;
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index b175a33934a..5d4451dd3d8 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -325,7 +325,7 @@ static void clip_planes_from_rect(bContext *C,
BoundBox bb;
view3d_operator_needs_opengl(C);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
negate_m4(clip_planes);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 1cb37fc10cd..969bf8f37b1 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -760,7 +760,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
- view3d_set_viewcontext(C, &pop->vc);
+ ED_view3d_viewcontext_init(C, &pop->vc);
copy_v2_v2(pop->prevmouse, mouse);
copy_v2_v2(pop->startmouse, mouse);
@@ -1376,6 +1376,7 @@ static int texture_paint_toggle_poll(bContext *C)
static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
WorkSpace *workspace = CTX_wm_workspace(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -1450,6 +1451,8 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 1);
}
+ ED_workspace_object_mode_sync_from_object(wm, workspace, ob);
+
GPU_drawobject_free(ob->derivedFinal);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 64969075d89..162c067166c 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -449,7 +449,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* Calculations of individual vertices are done in 2D screen space to diminish the amount of
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
* of lasso */
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
/* lasso data calculations */
data.vc = &vc;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 3982c9a3c30..861015375cb 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -698,7 +698,7 @@ PaintStroke *paint_stroke_new(bContext *C,
Brush *br = stroke->brush = BKE_paint_brush(p);
float zoomx, zoomy;
- view3d_set_viewcontext(C, &stroke->vc);
+ ED_view3d_viewcontext_init(C, &stroke->vc);
stroke->get_location = get_location;
stroke->test_start = test_start;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 6b14f97d80c..a45e33e4654 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -468,7 +468,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
unsigned int totpoly = me->totpoly;
if (dm->getLoopDataArray(dm, CD_MLOOPUV)) {
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 8ce0af068d6..f8ad943ffef 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -55,6 +55,8 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object_deform.h"
@@ -1089,6 +1091,8 @@ static void ed_vwpaintmode_enter_generic(
}
vertex_paint_init_session(eval_ctx, scene, ob);
+
+ ED_workspace_object_mode_sync_from_object(wm, workspace, ob);
}
void ED_object_vpaintmode_enter_ex(
@@ -1161,7 +1165,7 @@ static void ed_vwpaintmode_exit_generic(
}
/* If the cache is not released by a cancel or a done, free it now. */
- if (ob->sculpt->cache) {
+ if (ob->sculpt && ob->sculpt->cache) {
sculpt_cache_free(ob->sculpt->cache);
ob->sculpt->cache = NULL;
}
@@ -1174,6 +1178,8 @@ static void ed_vwpaintmode_exit_generic(
ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
ED_mesh_mirror_topo_table(NULL, NULL, 'e');
}
+
+ ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob);
}
void ED_object_vpaintmode_exit_ex(WorkSpace *workspace, Object *ob)
@@ -1475,7 +1481,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* make mode data storage */
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
- view3d_set_viewcontext(C, &wpd->vc);
+ ED_view3d_viewcontext_init(C, &wpd->vc);
view_angle_limits_init(&wpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -2475,7 +2481,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* make mode data storage */
vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
- view3d_set_viewcontext(C, &vpd->vc);
+ ED_view3d_viewcontext_init(C, &vpd->vc);
view_angle_limits_init(&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 72e2e7b323d..7ff9c3851ac 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -183,7 +183,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
Mesh *me;
bool changed = false;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
@@ -298,7 +298,7 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(
ViewContext vc;
Mesh *me;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
@@ -367,7 +367,7 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op)
{
int type = RNA_enum_get(op->ptr, "group");
ViewContext vc;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
BLI_assert(type + 1 >= 0);
vc.obact->actdef = type + 1;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 8df3d4e9f90..2d847d53877 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -60,6 +60,7 @@
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
@@ -4727,7 +4728,7 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
bool original;
ViewContext vc;
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
ob = vc.obact;
@@ -5459,13 +5460,11 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
return OPERATOR_INTERFACE;
}
-static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C)
+static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(Scene *scene, Object *ob)
{
- Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
SculptSession *ss = ob->sculpt;
- Scene *scene = CTX_data_scene(C);
enum eDynTopoWarnFlag flag = 0;
BLI_assert(ss->bm == NULL);
@@ -5510,7 +5509,8 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
SculptSession *ss = ob->sculpt;
if (!ss->bm) {
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
if (flag) {
/* The mesh has customdata that will be lost, let the user confirm this is OK */
@@ -5637,6 +5637,126 @@ static void sculpt_init_session(const EvaluationContext *eval_ctx, Scene *scene,
BKE_sculpt_update_mesh_elements(eval_ctx, scene, scene->toolsettings->sculpt, ob, 0, false);
}
+static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, MultiresModifierData *mmd)
+{
+ int flush_recalc = 0;
+ /* multires in sculpt mode could have different from object mode subdivision level */
+ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
+ /* if object has got active modifiers, it's dm could be different in sculpt mode */
+ flush_recalc |= sculpt_has_active_modifiers(scene, ob);
+ return flush_recalc;
+}
+
+void ED_object_sculptmode_enter_ex(
+ const EvaluationContext *eval_ctx,
+ WorkSpace *workspace, Scene *scene, Object *ob,
+ ReportList *reports)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Enter sculptmode */
+ workspace->object_mode |= mode_flag;
+
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+
+ if (flush_recalc)
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* Create sculpt mode session data */
+ if (ob->sculpt) {
+ BKE_sculptsession_free(ob);
+ }
+
+ sculpt_init_session(eval_ctx, scene, ob);
+
+ /* Mask layer is required */
+ if (mmd) {
+ /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res)
+ * but this ends up being quite tricky (and slow) */
+ BKE_sculpt_mask_layers_ensure(ob, mmd);
+ }
+
+ if (!(fabsf(ob->size[0] - ob->size[1]) < 1e-4f && fabsf(ob->size[1] - ob->size[2]) < 1e-4f)) {
+ BKE_report(reports, RPT_WARNING,
+ "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(reports, RPT_WARNING,
+ "Object has negative scale, sculpting may be unpredictable");
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, ePaintSculpt);
+ BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start_explicit(paint, G.main->wm.first, sculpt_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (message_unsupported == NULL) {
+ /* undo push is needed to prevent memory leak */
+ sculpt_undo_push_begin("Dynamic topology enable");
+ sculpt_dynamic_topology_enable_ex(eval_ctx, scene, ob);
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ }
+ else {
+ BKE_reportf(reports, RPT_WARNING,
+ "Dynamic Topology found: %s, disabled",
+ message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
+
+ ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob);
+
+ /* VBO no longer valid */
+ if (ob->derivedFinal) {
+ GPU_drawobject_free(ob->derivedFinal);
+ }
+}
+
+void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
+ ED_object_sculptmode_enter_ex(&eval_ctx, workspace, scene, ob, reports);
+}
+
void ED_object_sculptmode_exit_ex(
const EvaluationContext *eval_ctx,
WorkSpace *workspace, Scene *scene, Object *ob)
@@ -5649,6 +5769,11 @@ void ED_object_sculptmode_exit_ex(
multires_force_update(ob);
}
+ /* Not needed for now. */
+#if 0
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+#endif
+
/* Always for now, so leaving sculpt mode always ensures scene is in
* a consistent state.
*/
@@ -5669,6 +5794,8 @@ void ED_object_sculptmode_exit_ex(
/* Leave sculptmode */
workspace->object_mode &= ~mode_flag;
+ ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob);
+
BKE_sculptsession_free(ob);
paint_cursor_delete_textures();
@@ -5696,9 +5823,6 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_SCULPT;
const bool is_mode_set = (workspace->object_mode & mode_flag) != 0;
- Mesh *me;
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- int flush_recalc = 0;
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, workspace, mode_flag, op->reports)) {
@@ -5706,104 +5830,14 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
}
}
- me = BKE_mesh_from_object(ob);
-
- /* multires in sculpt mode could have different from object mode subdivision level */
- flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
- /* if object has got active modifiers, it's dm could be different in sculpt mode */
- flush_recalc |= sculpt_has_active_modifiers(scene, ob);
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
if (is_mode_set) {
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
ED_object_sculptmode_exit_ex(&eval_ctx, workspace, scene, ob);
}
else {
- /* Enter sculptmode */
- workspace->object_mode |= mode_flag;
-
- if (flush_recalc)
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* Create sculpt mode session data */
- if (ob->sculpt) {
- BKE_sculptsession_free(ob);
- }
-
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
- sculpt_init_session(&eval_ctx, scene, ob);
-
- /* Mask layer is required */
- if (mmd) {
- /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res)
- * but this ends up being quite tricky (and slow) */
- BKE_sculpt_mask_layers_ensure(ob, mmd);
- }
-
- if (!(fabsf(ob->size[0] - ob->size[1]) < 1e-4f && fabsf(ob->size[1] - ob->size[2]) < 1e-4f)) {
- BKE_report(op->reports, RPT_WARNING,
- "Object has non-uniform scale, sculpting may be unpredictable");
- }
- else if (is_negative_m4(ob->obmat)) {
- BKE_report(op->reports, RPT_WARNING,
- "Object has negative scale, sculpting may be unpredictable");
- }
-
- BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start(C, sculpt_poll_view3d);
-
- /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
- * As long as no data was added that is not supported. */
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- const char *message_unsupported = NULL;
- if (me->totloop != me->totpoly * 3) {
- message_unsupported = TIP_("non-triangle face");
- }
- else if (mmd != NULL) {
- message_unsupported = TIP_("multi-res modifier");
- }
- else {
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
- if (flag == 0) {
- /* pass */
- }
- else if (flag & DYNTOPO_WARN_VDATA) {
- message_unsupported = TIP_("vertex data");
- }
- else if (flag & DYNTOPO_WARN_EDATA) {
- message_unsupported = TIP_("edge data");
- }
- else if (flag & DYNTOPO_WARN_LDATA) {
- message_unsupported = TIP_("face data");
- }
- else if (flag & DYNTOPO_WARN_MODIFIER) {
- message_unsupported = TIP_("constructive modifier");
- }
- else {
- BLI_assert(0);
- }
- }
-
- if (message_unsupported == NULL) {
- /* undo push is needed to prevent memory leak */
- sculpt_undo_push_begin("Dynamic topology enable");
- sculpt_dynamic_topology_enable_ex(&eval_ctx, scene, ob);
- sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- }
- else {
- BKE_reportf(op->reports, RPT_WARNING,
- "Dynamic Topology found: %s, disabled",
- message_unsupported);
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
- }
-
- /* VBO no longer valid */
- if (ob->derivedFinal) {
- GPU_drawobject_free(ob->derivedFinal);
- }
+ ED_object_sculptmode_enter_ex(&eval_ctx, workspace, scene, ob, op->reports);
}
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
@@ -5906,7 +5940,7 @@ static void sample_detail(bContext *C, int ss_co[2])
float ray_start[3], ray_end[3], ray_normal[3], depth;
SculptDetailRaycastData srd;
float mouse[2] = {ss_co[0], ss_co[1]};
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
sd = CTX_data_tool_settings(C)->sculpt;
ob = vc.obact;
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 700b0969277..6928610f280 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -650,9 +650,9 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
/* we need to find the active island here */
if (do_island_optimization) {
UvElement *element;
- NearestHit hit;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
Image *ima = CTX_data_edit_image(C);
- uv_find_nearest_vert(scene, ima, obedit, em, co, NULL, &hit);
+ uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
island_index = element->island;
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 29b3c6f2f6c..fbef14c07c4 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -568,11 +568,11 @@ void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act,
if (strip->act == act) {
/* Remove this strip, and the track too if it doesn't have anything else */
- free_nlastrip(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip);
if (nlt->strips.first == NULL) {
BLI_assert(nstrip == NULL);
- free_nlatrack(&adt->nla_tracks, nlt);
+ BKE_nlatrack_free(&adt->nla_tracks, nlt);
}
}
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 3c3a71d00fd..2b974ac73d7 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -220,7 +220,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get beztriple editing/validation funcs */
@@ -262,7 +262,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
{
/* loop over data selecting */
switch (ale->type) {
-#if 0 /* XXXX: Keyframes are not currently shown here */
+#if 0 /* XXX: Keyframes are not currently shown here */
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = ale->data;
@@ -401,7 +401,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get beztriple editing/validation funcs */
@@ -466,6 +466,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
{
/* loop over data selecting */
switch (ale->type) {
+#if 0 /* XXX: Keyframes are not currently shown here */
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = ale->data;
@@ -475,6 +476,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
}
break;
}
+#endif
case ANIMTYPE_GPLAYER:
{
ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
@@ -718,8 +720,6 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
KeyframeEditFunc select_cb, ok_cb;
KeyframeEditData ked = {{NULL}};
- /* initialize keyframe editing data */
-
/* build list of columns */
switch (mode) {
case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index e47841ab574..df6e29086a0 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -61,6 +61,7 @@
#include "ED_space_api.h"
#include "ED_sound.h"
#include "ED_uvedit.h"
+#include "ED_lattice.h"
#include "ED_mball.h"
#include "ED_logic.h"
#include "ED_clip.h"
@@ -109,6 +110,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_animchannels();
ED_operatortypes_gpencil();
ED_operatortypes_object();
+ ED_operatortypes_lattice();
ED_operatortypes_mesh();
ED_operatortypes_sculpt();
ED_operatortypes_uvedit();
@@ -196,7 +198,8 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
ED_keymap_anim(keyconf);
ED_keymap_animchannels(keyconf);
ED_keymap_gpencil(keyconf);
- ED_keymap_object(keyconf); /* defines lattice also */
+ ED_keymap_object(keyconf);
+ ED_keymap_lattice(keyconf);
ED_keymap_mesh(keyconf);
ED_keymap_uvedit(keyconf);
ED_keymap_curve(keyconf);
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index d0e69a3dd7e..c6dda7f9f0d 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -351,18 +351,20 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
workspace = (WorkSpace *)workspace;
}
- if (!scene)
+ if (!scene) {
scene = CTX_data_scene(C);
+ }
- if (!pinid || GS(pinid->name) == ID_SCE) {
- wrld = scene->world;
+ const ID_Type id_type = pinid != NULL ? GS(pinid->name) : -1;
+ if (!pinid || ELEM(id_type, ID_SCE, ID_WS)) {
brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- linestyle = BKE_linestyle_active_from_scene(scene);
- }
- else if (!pinid || GS(pinid->name) == ID_WS) {
- if (!workspace) {
+
+ if (workspace == NULL) {
+ wrld = scene->world;
+ linestyle = BKE_linestyle_active_from_scene(scene);
workspace = CTX_wm_workspace(C);
}
+
ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace);
ob = OBACT(view_layer);
}
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 4ca2b54eaaf..f2bf817f502 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -1859,7 +1859,7 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
}
}
- if (count == 0) {
+ if (del && count == 0) {
ok = 0;
}
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
index 8e3871836e4..49cfc4b71b0 100644
--- a/source/blender/editors/space_clip/tracking_ops_orient.c
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -71,7 +71,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
return camera;
}
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
if (ob->type == OB_CAMERA) {
if (BKE_object_movieclip_get(scene, ob, false) == clip) {
@@ -80,7 +80,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
return camera;
}
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index 0e56dc817e4..907f346c931 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -171,8 +171,8 @@ int graphop_editable_keyframes_poll(bContext *C)
/* editable curves must fulfill the following criteria:
* - it has bezier keyframes
- * - it must not be protected from editing (this is already checked for with the foredit flag
- * - F-Curve modifiers do not interfere with the result too much
+ * - it must not be protected from editing (this is already checked for with the edit flag
+ * - F-Curve modifiers do not interfere with the result too much
* (i.e. the modifier-control drawing check returns false)
*/
if (fcu->bezt == NULL)
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 4b89c8db9e6..b03c6a2eb0b 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -700,13 +700,12 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
{
SpaceIpo *sgraph = (SpaceIpo *)slink;
- if (!ELEM(GS(old_id->name), ID_GR)) {
- return;
- }
-
if (sgraph->ads && (ID *)sgraph->ads->filter_grp == old_id) {
sgraph->ads->filter_grp = (Group *)new_id;
}
+ if ((ID *)sgraph->ads->source == old_id) {
+ sgraph->ads->source = new_id;
+ }
}
/* only called once, from space/spacetypes.c */
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 89bf57fdb6c..1cc3d5142f5 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -594,12 +594,12 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
*/
if (above_sel) {
/* just add a new one above this one */
- add_nlatrack(adt, nlt);
+ BKE_nlatrack_add(adt, nlt);
added = true;
}
else if ((lastAdt == NULL) || (adt != lastAdt)) {
/* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */
- add_nlatrack(adt, NULL);
+ BKE_nlatrack_add(adt, NULL);
lastAdt = adt;
added = true;
}
@@ -634,7 +634,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac)
/* ensure it is empty */
if (BLI_listbase_is_empty(&adt->nla_tracks)) {
/* add new track to this AnimData block then */
- add_nlatrack(adt, NULL);
+ BKE_nlatrack_add(adt, NULL);
added = true;
}
}
@@ -729,7 +729,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
adt->flag &= ~ADT_NLA_SOLO_TRACK;
/* call delete on this track - deletes all strips too */
- free_nlatrack(&adt->nla_tracks, nlt);
+ BKE_nlatrack_free(&adt->nla_tracks, nlt);
}
}
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index a18a692c0a3..a7773aaaed5 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -316,18 +316,20 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uns
float cfra;
/* plot the curve (over the strip's main region) */
- immBegin(GWN_PRIM_LINE_STRIP, abs((int)(strip->end - strip->start) + 1));
+ if (fcu) {
+ immBegin(GWN_PRIM_LINE_STRIP, abs((int)(strip->end - strip->start) + 1));
- /* sample at 1 frame intervals, and draw
- * - min y-val is yminc, max is y-maxc, so clamp in those regions
- */
- for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
- float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */
- CLAMP(y, 0.0f, 1.0f);
- immVertex2f(pos, cfra, ((y * yheight) + yminc));
- }
+ /* sample at 1 frame intervals, and draw
+ * - min y-val is yminc, max is y-maxc, so clamp in those regions
+ */
+ for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
+ float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */
+ CLAMP(y, 0.0f, 1.0f);
+ immVertex2f(pos, cfra, ((y * yheight) + yminc));
+ }
- immEnd();
+ immEnd();
+ }
}
else {
/* use blend in/out values only if both aren't zero */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 31524f8450a..87b7599ec66 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -645,7 +645,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
}
/* create a new strip, and offset it to start on the current frame */
- strip = add_nlastrip(act);
+ strip = BKE_nlastrip_new(act);
strip->end += (cfra - strip->start);
strip->start = cfra;
@@ -655,7 +655,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
- nlt = add_nlatrack(adt, NULL);
+ nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
}
@@ -858,7 +858,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
continue;
/* create a new strip, and offset it to start on the current frame */
- strip = add_nla_soundstrip(ac.scene, ob->data);
+ strip = BKE_nla_add_soundstrip(ac.scene, ob->data);
strip->start += cfra;
strip->end += cfra;
@@ -868,7 +868,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
- nlt = add_nlatrack(adt, NULL);
+ nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
}
@@ -1057,7 +1057,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
/* if selected, split the strip at its midpoint */
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* make a copy (assume that this is possible) */
- nstrip = copy_nlastrip(strip, linked);
+ nstrip = BKE_nlastrip_copy(strip, linked);
/* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
@@ -1065,7 +1065,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
* - if the current one is the last one, nlt->next will be NULL, which defaults to adding
* at the top of the stack anyway...
*/
- track = add_nlatrack(adt, nlt->next);
+ track = BKE_nlatrack_add(adt, nlt->next);
BKE_nlatrack_add_strip(track, nstrip);
}
@@ -1160,14 +1160,14 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* if a strip either side of this was a transition, delete those too */
if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
- free_nlastrip(&nlt->strips, strip->prev);
+ BKE_nlastrip_free(&nlt->strips, strip->prev);
if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
nstrip = nstrip->next;
- free_nlastrip(&nlt->strips, strip->next);
+ BKE_nlastrip_free(&nlt->strips, strip->next);
}
/* finally, delete this strip */
- free_nlastrip(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip);
}
}
}
@@ -1242,7 +1242,7 @@ static void nlaedit_split_strip_actclip(AnimData *adt, NlaTrack *nlt, NlaStrip *
/* make a copy (assume that this is possible) and append
* it immediately after the current strip
*/
- nstrip = copy_nlastrip(strip, true);
+ nstrip = BKE_nlastrip_copy(strip, true);
BLI_insertlinkafter(&nlt->strips, strip, nstrip);
/* set the endpoint of the first strip and the start of the new strip
@@ -2186,7 +2186,7 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
/* in case there's no space in the current track, try adding */
if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
/* need to add a new track above the current one */
- track = add_nlatrack(adt, nlt);
+ track = BKE_nlatrack_add(adt, nlt);
BKE_nlatrack_add_strip(track, strip);
/* clear temp meta-strips on this new track, as we may not be able to get back to it */
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index f6068087f02..03265c8dcba 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -518,13 +518,12 @@ static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *
{
SpaceNla *snla = (SpaceNla *)slink;
- if (!ELEM(GS(old_id->name), ID_GR)) {
- return;
- }
-
if ((ID *)snla->ads->filter_grp == old_id) {
snla->ads->filter_grp = (Group *)new_id;
}
+ if ((ID *)snla->ads->source == old_id) {
+ snla->ads->source = new_id;
+ }
}
/* only called once, from space/spacetypes.c */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 68934ebedd6..3c00114579e 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3016,7 +3016,7 @@ static const float std_node_socket_colors[][4] = {
{0.70, 0.65, 0.19, 1.0}, /* SOCK_BOOLEAN */
{0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */
{0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */
- {1.0, 1.0, 1.0, 1.0}, /* SOCK_STRING */
+ {0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
};
/* common color callbacks for standard types */
@@ -3103,20 +3103,11 @@ static void std_node_socket_draw(bContext *C, uiLayout *layout, PointerRNA *ptr,
uiTemplateComponentMenu(layout, ptr, "default_value", text);
break;
case SOCK_RGBA:
- {
- uiLayout *row = uiLayoutRow(layout, false);
- uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
- /* draw the socket name right of the actual button */
- uiItemR(row, ptr, "default_value", 0, "", 0);
- uiItemL(row, text, 0);
- break;
- }
case SOCK_STRING:
{
- uiLayout *row = uiLayoutRow(layout, true);
- /* draw the socket name right of the actual button */
- uiItemR(row, ptr, "default_value", 0, "", 0);
+ uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
uiItemL(row, text, 0);
+ uiItemR(row, ptr, "default_value", 0, "", 0);
break;
}
default:
@@ -3150,11 +3141,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
break;
}
- case SOCK_BOOLEAN:
- {
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
- break;
- }
case SOCK_VECTOR:
{
uiLayout *row;
@@ -3164,11 +3150,8 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
break;
}
+ case SOCK_BOOLEAN:
case SOCK_RGBA:
- {
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
- break;
- }
case SOCK_STRING:
{
uiItemR(layout, ptr, "default_value", 0, NULL, 0);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 94bd752cf81..83ea519a015 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -359,6 +359,8 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
dy -= NODE_DYS / 2;
/* output sockets */
+ bool add_output_space = false;
+
for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
if (nodeSocketIsHidden(nsock))
continue;
@@ -391,6 +393,12 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
dy = buty;
if (nsock->next)
dy -= NODE_SOCKDY;
+
+ add_output_space = true;
+ }
+
+ if (add_output_space) {
+ dy -= NODE_DY / 4;
}
node->prvr.xmin = locx + NODE_DYS;
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index c791b9f6eae..1047c498e4d 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -482,10 +482,10 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
}
NODE_TYPES_END
- qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
+ qsort(sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
/* generate UI */
- for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) {
+ for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) {
bNodeType *ntype = sorted_ntypes[j];
NodeLinkItem *items;
int totitems;
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index efc28eea917..7c3bccd1385 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -656,7 +656,7 @@ static int object_add_to_new_collection_exec(bContext *C, wmOperator *op)
SceneCollection *scene_collection_parent, *scene_collection_new;
TreeElement *te_active, *te_parent;
- struct ObjectsSelectedData data = {NULL}, active = {NULL};
+ struct ObjectsSelectedData data = {{NULL}}, active = {{NULL}};
outliner_tree_traverse(soops, &soops->tree, 0, TSE_HIGHLIGHTED, outliner_find_selected_objects, &active);
if (BLI_listbase_is_empty(&active.objects_selected_array)) {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 16f3aeaf110..e720eedbb22 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -924,7 +924,7 @@ static void do_outliner_item_activate_tree_element(
if (extend) {
int sel = BA_SELECT;
- FOREACH_GROUP_BASE(gr, base)
+ FOREACH_GROUP_BASE_BEGIN(gr, base)
{
if (base->flag & BASE_SELECTED) {
sel = BA_DESELECT;
@@ -933,16 +933,16 @@ static void do_outliner_item_activate_tree_element(
}
FOREACH_GROUP_BASE_END
- FOREACH_GROUP_OBJECT(gr, object)
+ FOREACH_GROUP_OBJECT_BEGIN(gr, object)
{
ED_object_base_select(BKE_view_layer_base_find(view_layer, object), sel);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
else {
BKE_view_layer_base_deselect_all(view_layer);
- FOREACH_GROUP_OBJECT(gr, object)
+ FOREACH_GROUP_OBJECT_BEGIN(gr, object)
{
Base *base = BKE_view_layer_base_find(view_layer, object);
/* Object may not be in this scene */
@@ -952,7 +952,7 @@ static void do_outliner_item_activate_tree_element(
}
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index b97046d1470..c30b14d43fa 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -541,7 +541,7 @@ static void group_linkobs2scene_cb(
Group *group = (Group *)tselem->id;
Base *base;
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
base = BKE_view_layer_base_find(view_layer, object);
if (!base) {
@@ -553,7 +553,7 @@ static void group_linkobs2scene_cb(
base->flag |= BASE_SELECTED;
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
static void group_instance_cb(
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 00eb4efde02..8c6d7783f01 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -2380,11 +2380,11 @@ void outliner_build_tree(
}
else if (soops->outlinevis == SO_COLLECTIONS) {
if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) {
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
outliner_add_element(soops, eval_ctx, &soops->tree, ob, NULL, 0, 0);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
outliner_make_hierarchy(&soops->tree);
}
else {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index e1163fd3207..9a0578fe220 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -671,6 +671,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
Sequence *seqn = NULL;
bool skip_dup = false;
+ /* Unlike soft-cut, it's important to use the same value for both strips. */
+ const bool is_end_exact = ((seq->start + seq->len) == cutframe);
+
/* backup values */
ts.start = seq->start;
ts.machine = seq->machine;
@@ -683,7 +686,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
ts.anim_startofs = seq->anim_startofs;
ts.anim_endofs = seq->anim_endofs;
ts.len = seq->len;
-
+
/* First Strip! */
/* strips with extended stillfames before */
@@ -695,6 +698,8 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
BKE_sequence_calc(scene, seq);
}
+ /* Important to offset the start when 'cutframe == seq->start'
+ * because we need at least one frame of content after start/end still have clipped it. */
if ((seq->startstill) && (cutframe <= seq->start)) {
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
@@ -709,13 +714,15 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
}
}
/* normal strip */
- else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) {
+ else if ((is_end_exact == false) &&
+ ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))))
+ {
seq->endofs = 0;
seq->endstill = 0;
seq->anim_endofs += (seq->start + seq->len) - cutframe;
}
/* strips with extended stillframes after */
- else if (((seq->start + seq->len) == cutframe) ||
+ else if ((is_end_exact == true) ||
(((seq->start + seq->len) < cutframe) && (seq->endstill)))
{
seq->endstill -= seq->enddisp - cutframe;
@@ -735,7 +742,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
if (seqn) {
seqn->flag |= SELECT;
-
+
+ /* Important not to re-assign this (unlike soft-cut) */
+#if 0
+ is_end_exact = ((seqn->start + seqn->len) == cutframe);
+#endif
/* Second Strip! */
/* strips with extended stillframes before */
if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
@@ -744,9 +755,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
seqn->anim_endofs = ts.anim_endofs;
seqn->endstill = ts.endstill;
}
-
+
/* normal strip */
- else if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) {
+ else if ((is_end_exact == false) &&
+ ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))))
+ {
seqn->start = cutframe;
seqn->startstill = 0;
seqn->startofs = 0;
@@ -755,9 +768,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
seqn->anim_endofs = ts.anim_endofs;
seqn->endstill = ts.endstill;
}
-
+
/* strips with extended stillframes after */
- else if (((seqn->start + seqn->len) == cutframe) ||
+ else if ((is_end_exact == true) ||
(((seqn->start + seqn->len) < cutframe) && (seqn->endstill)))
{
seqn->start = cutframe;
@@ -766,7 +779,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
seqn->endstill = ts.enddisp - cutframe - 1;
seqn->startstill = 0;
}
-
+
BKE_sequence_reload_new_file(scene, seqn, false);
BKE_sequence_calc(scene, seqn);
}
@@ -779,6 +792,8 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
Sequence *seqn = NULL;
bool skip_dup = false;
+ bool is_end_exact = ((seq->start + seq->len) == cutframe);
+
/* backup values */
ts.start = seq->start;
ts.machine = seq->machine;
@@ -791,10 +806,12 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
ts.anim_startofs = seq->anim_startofs;
ts.anim_endofs = seq->anim_endofs;
ts.len = seq->len;
-
+
/* First Strip! */
/* strips with extended stillfames before */
-
+
+ /* Important to offset the start when 'cutframe == seq->start'
+ * because we need at least one frame of content after start/end still have clipped it. */
if ((seq->startstill) && (cutframe <= seq->start)) {
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
@@ -809,11 +826,13 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
}
}
/* normal strip */
- else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) {
+ else if ((is_end_exact == false) &&
+ (cutframe >= seq->start) && (cutframe <= (seq->start + seq->len)))
+ {
seq->endofs = (seq->start + seq->len) - cutframe;
}
/* strips with extended stillframes after */
- else if (((seq->start + seq->len) == cutframe) ||
+ else if ((is_end_exact == true) ||
(((seq->start + seq->len) < cutframe) && (seq->endstill)))
{
seq->endstill -= seq->enddisp - cutframe;
@@ -832,7 +851,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
if (seqn) {
seqn->flag |= SELECT;
-
+
+ is_end_exact = ((seqn->start + seqn->len) == cutframe);
+
/* Second Strip! */
/* strips with extended stillframes before */
if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
@@ -843,15 +864,17 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
}
/* normal strip */
- if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) {
+ else if ((is_end_exact == false) &&
+ (cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len)))
+ {
seqn->startstill = 0;
seqn->startofs = cutframe - ts.start;
seqn->endofs = ts.endofs;
seqn->endstill = ts.endstill;
}
-
+
/* strips with extended stillframes after */
- else if (((seqn->start + seqn->len) == cutframe) ||
+ else if ((is_end_exact == true) ||
(((seqn->start + seqn->len) < cutframe) && (seqn->endstill)))
{
seqn->start = cutframe - ts.len + 1;
@@ -859,7 +882,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
seqn->endstill = ts.enddisp - cutframe - 1;
seqn->startstill = 0;
}
-
+
BKE_sequence_calc(scene, seqn);
}
return seqn;
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 75c217c4f0c..adb2d475464 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -6622,7 +6622,7 @@ static void draw_update_ptcache_edit(
const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, PTCacheEdit *edit)
{
if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED)
- PE_update_object(eval_ctx, scene, view_layer, ob, 0);
+ PE_update_object(eval_ctx, scene, ob, 0);
/* create path and child path cache if it doesn't exist already */
if (edit->pathcache == NULL) {
@@ -9623,7 +9623,7 @@ static void bbs_mesh_face(BMEditMesh *em, DerivedMesh *UNUSED(dm), const bool us
GPU_select_index_get(0, &selcol);
batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true);
GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32);
- GWN_batch_uniform_1i(batch, "color", selcol);
+ GWN_batch_uniform_1ui(batch, "color", selcol);
GWN_batch_draw(batch);
}
}
@@ -9753,7 +9753,7 @@ static void bbs_mesh_solid_verts(const EvaluationContext *UNUSED(eval_ctx), Scen
GPU_select_index_get(0, &selcol);
batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true);
GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32);
- GWN_batch_uniform_1i(batch, "color", selcol);
+ GWN_batch_uniform_1ui(batch, "color", selcol);
GWN_batch_draw(batch);
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 0eaf1e10086..af9d738d71e 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -65,6 +65,8 @@
#include "GPU_viewport.h"
#include "GPU_matrix.h"
+#include "DRW_engine.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "WM_message.h"
@@ -554,8 +556,9 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar)
}
if (rv3d->viewport) {
+ DRW_opengl_context_enable();
GPU_viewport_free(rv3d->viewport);
- MEM_freeN(rv3d->viewport);
+ DRW_opengl_context_disable();
rv3d->viewport = NULL;
}
}
@@ -739,8 +742,9 @@ static void view3d_main_region_free(ARegion *ar)
GPU_fx_compositor_destroy(rv3d->compositor);
}
if (rv3d->viewport) {
+ DRW_opengl_context_enable();
GPU_viewport_free(rv3d->viewport);
- MEM_freeN(rv3d->viewport);
+ DRW_opengl_context_disable();
}
MEM_freeN(rv3d);
@@ -1050,7 +1054,7 @@ static void view3d_main_region_message_subscribe(
*
* For other space types we might try avoid this, keep the 3D view as an exceptional case! */
ViewRender *view_render = BKE_viewrender_get(scene, workspace);
- wmMsgParams_RNA msg_key_params = {0};
+ wmMsgParams_RNA msg_key_params = {{{0}}};
/* Only subscribe to types. */
StructRNA *type_array[] = {
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index c39057431c2..5962f1ed2ff 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -31,10 +31,10 @@
*
* Typical view-control usage:
*
- * - acquire a view-control (#ED_view3d_control_acquire).
+ * - acquire a view-control (#ED_view3d_cameracontrol_acquire).
* - modify ``rv3d->ofs``, ``rv3d->viewquat``.
- * - update the view data (#ED_view3d_control_acquire) - within a loop which draws the viewport.
- * - finish and release the view-control (#ED_view3d_control_release),
+ * - update the view data (#ED_view3d_cameracontrol_acquire) - within a loop which draws the viewport.
+ * - finish and release the view-control (#ED_view3d_cameracontrol_release),
* either keeping the current view or restoring the initial view.
*
* Notes:
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 6e3a0883489..b14128ab400 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1922,6 +1922,9 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
BLI_rcti_translate(&rect, -ar->winrct.xmin, -ar->winrct.ymin);
GPU_viewport_draw_to_screen(rv3d->viewport, &rect);
+ GPU_free_images_old();
+ GPU_pass_cache_garbage_collect();
+
v3d->flag |= V3D_INVALID_BACKBUF;
}
@@ -2022,23 +2025,12 @@ void ED_view3d_draw_offscreen(
gpuPushMatrix();
gpuLoadIdentity();
- /* clear opengl buffers */
- if (do_sky) {
- view3d_main_region_clear(scene, v3d, ar);
- }
- else {
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
-
if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
view3d_stereo3d_setup_offscreen(eval_ctx, scene, v3d, ar, winmat, viewname);
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);
+ Depsgraph *depsgraph = eval_ctx->depsgraph;
/* main drawing call */
RenderEngineType *engine_type = eval_ctx->engine_type;
@@ -2131,11 +2123,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
}
const bool own_ofs = (ofs == NULL);
+ DRW_opengl_context_enable();
if (own_ofs) {
/* bind */
ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out);
if (ofs == NULL) {
+ DRW_opengl_context_disable();
return NULL;
}
}
@@ -2235,7 +2229,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
/* 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) {
@@ -2267,6 +2260,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
GPU_offscreen_free(ofs);
}
+ DRW_opengl_context_disable();
+
if (ibuf->rect_float && ibuf->rect)
IMB_rect_from_float(ibuf);
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index 6a746ffe27c..775169e0b45 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -212,31 +212,31 @@ static void draw_view_icon(RegionView3D *rv3d, rcti *rect)
/* *********************** backdraw for selection *************** */
static void backdrawview3d(
- const struct EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer,
- ARegion *ar, View3D *v3d)
+ const struct EvaluationContext *eval_ctx, Scene *scene,
+ ARegion *ar, View3D *v3d,
+ Object *obact, Object *obedit)
{
RegionView3D *rv3d = ar->regiondata;
- struct Base *base = view_layer->basact;
BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
- if (base && (eval_ctx->object_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
- BKE_paint_select_face_test(base->object, eval_ctx->object_mode)))
+ if (obact && (eval_ctx->object_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
+ BKE_paint_select_face_test(obact, eval_ctx->object_mode)))
{
/* do nothing */
}
/* texture paint mode sampling */
- else if (base && (eval_ctx->object_mode & OB_MODE_TEXTURE_PAINT) &&
+ else if (obact && (eval_ctx->object_mode & OB_MODE_TEXTURE_PAINT) &&
(v3d->drawtype > OB_WIRE))
{
/* do nothing */
}
- else if ((base && (eval_ctx->object_mode & OB_MODE_PARTICLE_EDIT)) &&
+ else if ((obact && (eval_ctx->object_mode & OB_MODE_PARTICLE_EDIT)) &&
V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
- else if ((eval_ctx->object_mode & OB_MODE_EDIT) &&
+ else if ((eval_ctx->object_mode & OB_MODE_EDIT) && (obedit != NULL) &&
V3D_IS_ZBUF(v3d))
{
/* do nothing */
@@ -310,10 +310,11 @@ static void backdrawview3d(
ED_view3d_clipping_set(rv3d);
G.f |= G_BACKBUFSEL;
-
- if (base && ((base->flag & BASE_VISIBLED) != 0))
- draw_object_backbufsel(eval_ctx, scene, v3d, rv3d, base->object);
-
+
+ if (obact && ((obact->base_flag & BASE_VISIBLED) != 0)) {
+ draw_object_backbufsel(eval_ctx, scene, v3d, rv3d, obact);
+ }
+
if (rv3d->gpuoffscreen)
GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
else
@@ -354,7 +355,7 @@ static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h,
void ED_view3d_backbuf_validate(const struct EvaluationContext *eval_ctx, ViewContext *vc)
{
if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
- backdrawview3d(eval_ctx, vc->scene, vc->view_layer, vc->ar, vc->v3d);
+ backdrawview3d(eval_ctx, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 47778623561..45284c1805a 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -2094,7 +2094,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
viewzoom_apply(
vod, &event->x, U.viewzoom,
(U.uiflag & USER_ZOOM_INVERT) != 0,
- (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) ? vod->prev.event_xy : NULL);
+ (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 79fa9e14dc1..8e6f5228b09 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -82,7 +82,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
for (Group *group = bmain->group.first; group; group = group->id.next) {
- FOREACH_GROUP_OBJECT(group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(group, object)
{
if (object && (object->id.tag & LIB_TAG_DOIT)) {
BKE_copybuffer_tag_ID(&group->id);
@@ -91,7 +91,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
break;
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index b352a2083a7..6364df2af2b 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -83,6 +83,7 @@
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_lattice.h"
#include "ED_particle.h"
#include "ED_mesh.h"
#include "ED_object.h"
@@ -106,7 +107,7 @@ float ED_view3d_select_dist_px(void)
}
/* TODO: should return whether there is valid context to continue */
-void view3d_set_viewcontext(bContext *C, ViewContext *vc)
+void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
{
memset(vc, 0, sizeof(ViewContext));
vc->ar = CTX_wm_region(C);
@@ -224,9 +225,10 @@ typedef struct LassoSelectUserData {
bool is_changed;
} LassoSelectUserData;
-static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
- ViewContext *vc, const rcti *rect, const int (*mcords)[2],
- const int moves, const bool select)
+static void view3d_userdata_lassoselect_init(
+ LassoSelectUserData *r_data,
+ ViewContext *vc, const rcti *rect, const int (*mcords)[2],
+ const int moves, const bool select)
{
r_data->vc = vc;
@@ -302,7 +304,8 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2
return 1;
}
-static void do_lasso_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
+static void do_lasso_select_pose__doSelectBone(
+ void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
{
LassoSelectUserData *data = userData;
bArmature *arm = data->vc->obact->data;
@@ -424,7 +427,8 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, cons
BM_vert_select_set(data->vc->em->bm, eve, data->select);
}
}
-static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+static void do_lasso_select_mesh__doSelectEdge(
+ void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
LassoSelectUserData *data = userData;
@@ -462,7 +466,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, cons
}
static void do_lasso_select_mesh(
- const struct EvaluationContext *eval_ctx, ViewContext *vc,
+ const EvaluationContext *eval_ctx, ViewContext *vc,
const int mcords[][2], short moves, bool extend, bool select)
{
LassoSelectUserData data;
@@ -518,7 +522,8 @@ static void do_lasso_select_mesh(
EDBM_selectmode_flush(vc->em);
}
-static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void do_lasso_select_curve__doSelect(
+ void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
LassoSelectUserData *data = userData;
Object *obedit = data->vc->obedit;
@@ -593,7 +598,8 @@ static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], shor
lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
-static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
+static void do_lasso_select_armature__doSelectBone(
+ void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
{
LassoSelectUserData *data = userData;
bArmature *arm = data->vc->obedit->data;
@@ -699,7 +705,8 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m
mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
-static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void do_lasso_select_meshobject__doSelectVert(
+ void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{
LassoSelectUserData *data = userData;
@@ -709,7 +716,9 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv,
SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
}
}
-static void do_lasso_select_paintvert(const struct EvaluationContext *eval_ctx, ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_paintvert(
+ const EvaluationContext *eval_ctx,
+ ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
{
const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
@@ -740,8 +749,8 @@ static void do_lasso_select_paintvert(const struct EvaluationContext *eval_ctx,
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
- meshobject_foreachScreenVert(eval_ctx, vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
-
+ meshobject_foreachScreenVert(
+ eval_ctx, vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
if (select == false) {
@@ -749,7 +758,9 @@ static void do_lasso_select_paintvert(const struct EvaluationContext *eval_ctx,
}
paintvert_flush_flags(ob);
}
-static void do_lasso_select_paintface(const struct EvaluationContext *eval_ctx, ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_paintface(
+ const EvaluationContext *eval_ctx,
+ ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
{
Object *ob = vc->obact;
Mesh *me = ob->data;
@@ -804,9 +815,10 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select
}
#endif
-static void view3d_lasso_select(bContext *C, ViewContext *vc,
- const int mcords[][2], short moves,
- bool extend, bool select)
+static void view3d_lasso_select(
+ bContext *C, ViewContext *vc,
+ const int mcords[][2], short moves,
+ bool extend, bool select)
{
Object *ob = CTX_data_active_object(C);
@@ -872,7 +884,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
/* setup view context for argument to callbacks */
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
extend = RNA_boolean_get(op->ptr, "extend");
select = !RNA_boolean_get(op->ptr, "deselect");
@@ -904,61 +916,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
WM_operator_properties_gesture_lasso_select(ot);
}
-
-/* ************************************************* */
-
-#if 0
-/* smart function to sample a rect spiralling outside, nice for backbuf selection */
-static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
-{
- Base *base;
- unsigned int *bufmin, *bufmax;
- int a, b, rc, tel, len, dirvec[4][2], maxob;
- unsigned int retval = 0;
-
- base = LASTBASE;
- if (base == 0) return 0;
- maxob = base->object->select_color;
-
- len = (size - 1) / 2;
- rc = 0;
-
- dirvec[0][0] = 1;
- dirvec[0][1] = 0;
- dirvec[1][0] = 0;
- dirvec[1][1] = -size;
- dirvec[2][0] = -1;
- dirvec[2][1] = 0;
- dirvec[3][0] = 0;
- dirvec[3][1] = size;
-
- bufmin = buf;
- bufmax = buf + size * size;
- buf += len * size + len;
-
- for (tel = 1; tel <= size; tel++) {
-
- for (a = 0; a < 2; a++) {
- for (b = 0; b < tel; b++) {
-
- if (*buf && *buf <= maxob && *buf != dontdo) return *buf;
- if (*buf == dontdo) retval = dontdo; /* if only color dontdo is available, still return dontdo */
-
- buf += (dirvec[rc][0] + dirvec[rc][1]);
-
- if (buf < bufmin || buf >= bufmax) return retval;
- }
- rc++;
- rc &= 3;
- }
- }
- return retval;
-}
-#endif
-
/* ************************** mouse select ************************* */
-
/* The max number of menu items in an object select menu */
typedef struct SelMenuItemF {
char idname[MAX_ID_NAME - 2];
@@ -969,7 +928,8 @@ typedef struct SelMenuItemF {
static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE];
/* special (crappy) operator only for menu select */
-static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *object_select_menu_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem *item = NULL, item_tmp = {0};
int totitem = 0;
@@ -1154,7 +1114,7 @@ static Base *object_mouse_select_menu(
}
}
-static bool selectbuffer_has_bones(const unsigned int *buffer, const unsigned int hits)
+static bool selectbuffer_has_bones(const uint *buffer, const uint hits)
{
unsigned int i;
for (i = 0; i < hits; i++) {
@@ -1275,8 +1235,9 @@ finally:
}
/* returns basact */
-static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits,
- Base *startbase, bool has_bones, bool do_nearest)
+static Base *mouse_select_eval_buffer(
+ ViewContext *vc, const uint *buffer, int hits,
+ Base *startbase, bool has_bones, bool do_nearest)
{
ViewLayer *view_layer = vc->view_layer;
Base *base, *basact = NULL;
@@ -1372,7 +1333,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
hits = mixed_bones_object_selectbuffer(&eval_ctx, &vc, buffer, mval, false, false, &do_nearest);
@@ -1423,7 +1384,7 @@ static bool ed_object_select_pick(
/* setup view context for argument to callbacks */
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
is_obedit = (vc.obedit != NULL);
if (object) {
@@ -1448,8 +1409,9 @@ static bool ed_object_select_pick(
while (base) {
if (BASE_SELECTABLE(base)) {
float screen_co[2];
- if (ED_view3d_project_float_global(ar, base->object->obmat[3], screen_co,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ if (ED_view3d_project_float_global(
+ ar, base->object->obmat[3], screen_co,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
if (base == BASACT(view_layer)) dist_temp += 10.0f;
@@ -1638,8 +1600,9 @@ typedef struct BoxSelectUserData {
bool is_changed;
} BoxSelectUserData;
-static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
- ViewContext *vc, const rcti *rect, const bool select)
+static void view3d_userdata_boxselect_init(
+ BoxSelectUserData *r_data,
+ ViewContext *vc, const rcti *rect, const bool select)
{
r_data->vc = vc;
@@ -1661,7 +1624,8 @@ bool edge_inside_circle(const float cent[2], float radius, const float screen_co
return (dist_squared_to_line_segment_v2(cent, screen_co_a, screen_co_b) < radius_squared);
}
-static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void do_paintvert_box_select__doSelectVert(
+ void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{
BoxSelectUserData *data = userData;
@@ -1753,7 +1717,8 @@ static int do_paintvert_box_select(
return OPERATOR_FINISHED;
}
-static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void do_nurbs_box_select__doSelect(
+ void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
BoxSelectUserData *data = userData;
Object *obedit = data->vc->obedit;
@@ -1831,7 +1796,8 @@ static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const
BM_vert_select_set(data->vc->em->bm, eve, data->select);
}
}
-static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+static void do_mesh_box_select__doSelectEdge(
+ void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
BoxSelectUserData *data = userData;
@@ -1858,7 +1824,7 @@ static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const
}
}
static int do_mesh_box_select(
- const struct EvaluationContext *eval_ctx, ViewContext *vc, rcti *rect, bool select, bool extend)
+ const EvaluationContext *eval_ctx, ViewContext *vc, rcti *rect, bool select, bool extend)
{
BoxSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings;
@@ -1912,7 +1878,7 @@ static int do_mesh_box_select(
}
static int do_meta_box_select(
- const struct EvaluationContext *eval_ctx, ViewContext *vc,
+ const EvaluationContext *eval_ctx, ViewContext *vc,
const rcti *rect, bool select, bool extend)
{
MetaBall *mb = (MetaBall *)vc->obedit->data;
@@ -1948,7 +1914,7 @@ static int do_meta_box_select(
}
static int do_armature_box_select(
- const struct EvaluationContext *eval_ctx, ViewContext *vc,
+ const EvaluationContext *eval_ctx, ViewContext *vc,
const rcti *rect, bool select, bool extend)
{
bArmature *arm = vc->obedit->data;
@@ -2097,7 +2063,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
qsort(vbuffer, hits, sizeof(uint[4]), opengl_select_buffer_cmp);
/*
- * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER',
+ * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER_BEGIN',
* we can be sure the order remains the same between both.
*/
for (base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
@@ -2165,7 +2131,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
/* setup view context for argument to callbacks */
CTX_data_eval_ctx(C, &eval_ctx);
- view3d_set_viewcontext(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc);
select = !RNA_boolean_get(op->ptr, "deselect");
extend = RNA_boolean_get(op->ptr, "extend");
@@ -2423,8 +2389,9 @@ typedef struct CircleSelectUserData {
bool is_changed;
} CircleSelectUserData;
-static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
- ViewContext *vc, const bool select, const int mval[2], const float rad)
+static void view3d_userdata_circleselect_init(
+ CircleSelectUserData *r_data,
+ ViewContext *vc, const bool select, const int mval[2], const float rad)
{
r_data->vc = vc;
r_data->select = select;
@@ -2447,7 +2414,8 @@ static void mesh_circle_doSelectVert(void *userData, BMVert *eve, const float sc
BM_vert_select_set(data->vc->em->bm, eve, data->select);
}
}
-static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
+static void mesh_circle_doSelectEdge(
+ void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
{
CircleSelectUserData *data = userData;
@@ -2464,7 +2432,9 @@ static void mesh_circle_doSelectFace(void *userData, BMFace *efa, const float sc
}
}
-static void mesh_circle_select(const struct EvaluationContext *eval_ctx, ViewContext *vc, const bool select, const int mval[2], float rad)
+static void mesh_circle_select(
+ const EvaluationContext *eval_ctx,
+ ViewContext *vc, const bool select, const int mval[2], float rad)
{
ToolSettings *ts = vc->scene->toolsettings;
int bbsel;
@@ -2508,7 +2478,9 @@ static void mesh_circle_select(const struct EvaluationContext *eval_ctx, ViewCon
EDBM_selectmode_flush(vc->em);
}
-static void paint_facesel_circle_select(const struct EvaluationContext *eval_ctx, ViewContext *vc, const bool select, const int mval[2], float rad)
+static void paint_facesel_circle_select(
+ const EvaluationContext *eval_ctx,
+ ViewContext *vc, const bool select, const int mval[2], float rad)
{
Object *ob = vc->obact;
Mesh *me = ob->data;
@@ -2524,7 +2496,8 @@ static void paint_facesel_circle_select(const struct EvaluationContext *eval_ctx
}
}
-static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void paint_vertsel_circle_select_doSelectVert(
+ void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{
CircleSelectUserData *data = userData;
@@ -2532,7 +2505,8 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv,
SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
}
}
-static void paint_vertsel_circle_select(const struct EvaluationContext *eval_ctx, ViewContext *vc, const bool select, const int mval[2], float rad)
+static void paint_vertsel_circle_select(
+ const EvaluationContext *eval_ctx, ViewContext *vc, const bool select, const int mval[2], float rad)
{
const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
@@ -2555,7 +2529,8 @@ static void paint_vertsel_circle_select(const struct EvaluationContext *eval_ctx
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
- meshobject_foreachScreenVert(eval_ctx, vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ meshobject_foreachScreenVert(
+ eval_ctx, vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
if (select != LEFTMOUSE) {
@@ -2565,7 +2540,8 @@ static void paint_vertsel_circle_select(const struct EvaluationContext *eval_ctx
}
-static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void nurbscurve_circle_doSelect(
+ void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
CircleSelectUserData *data = userData;
Object *obedit = data->vc->obedit;
@@ -2639,7 +2615,8 @@ static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, cons
}
return 0;
}
-static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
+static void do_circle_select_pose__doSelectBone(
+ void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
{
CircleSelectUserData *data = userData;
bArmature *arm = data->vc->obact->data;
@@ -2725,7 +2702,8 @@ static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const
}
return 0;
}
-static void do_circle_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
+static void do_circle_select_armature__doSelectBone(
+ void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
{
CircleSelectUserData *data = userData;
bArmature *arm = data->vc->obedit->data;
@@ -2810,7 +2788,7 @@ static void mball_circle_select(ViewContext *vc, const bool select, const int mv
/** Callbacks for circle selection in Editmode */
static void obedit_circle_select(
- const struct EvaluationContext *eval_ctx, ViewContext *vc, const bool select, const int mval[2], float rad)
+ const EvaluationContext *eval_ctx, ViewContext *vc, const bool select, const int mval[2], float rad)
{
switch (vc->obedit->type) {
case OB_MESH:
@@ -2847,8 +2825,9 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m
for (base = FIRSTBASE(view_layer); base; base = base->next) {
if (BASE_SELECTABLE(base) && ((base->flag & BASE_SELECTED) != select_flag)) {
float screen_co[2];
- if (ED_view3d_project_float_global(vc->ar, base->object->obmat[3], screen_co,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ if (ED_view3d_project_float_global(
+ vc->ar, base->object->obmat[3], screen_co,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) {
ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
@@ -2864,24 +2843,22 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m
/* not a real operator, only for circle test */
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
+ Object *obact = vc.obact;
+ Object *obedit = vc.obedit;
EvaluationContext eval_ctx;
CTX_data_eval_ctx(C, &eval_ctx);
- Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
const int radius = RNA_int_get(op->ptr, "radius");
const bool select = !RNA_boolean_get(op->ptr, "deselect");
const int mval[2] = {RNA_int_get(op->ptr, "x"),
RNA_int_get(op->ptr, "y")};
- if (CTX_data_edit_object(C) || BKE_paint_select_elem_test(obact, eval_ctx.object_mode) ||
+ if (obedit || BKE_paint_select_elem_test(obact, eval_ctx.object_mode) ||
(obact && (eval_ctx.object_mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
{
- ViewContext vc;
-
view3d_operator_needs_opengl(C);
- view3d_set_viewcontext(C, &vc);
-
if (CTX_data_edit_object(C)) {
obedit_circle_select(&eval_ctx, &vc, select, mval, (float)radius);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
@@ -2903,14 +2880,11 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- ViewContext vc;
- view3d_set_viewcontext(C, &vc);
-
if (object_circle_select(&vc, select, mval, (float)radius)) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
}
}
-
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 4ccf86138e7..4225ee8b425 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -861,6 +861,45 @@ void view3d_opengl_select_cache_end(void)
GPU_select_cache_end();
}
+#ifndef WITH_OPENGL_LEGACY
+struct DrawSelectLoopUserData {
+ uint pass;
+ uint hits;
+ uint *buffer;
+ uint buffer_len;
+ const rcti *rect;
+ char gpu_select_mode;
+};
+
+static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
+{
+ bool continue_pass = false;
+ struct DrawSelectLoopUserData *data = user_data;
+ if (stage == DRW_SELECT_PASS_PRE) {
+ GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
+ /* always run POST after PRE. */
+ continue_pass = true;
+ }
+ else if (stage == DRW_SELECT_PASS_POST) {
+ int hits = GPU_select_end();
+ if (data->pass == 0) {
+ /* quirk of GPU_select_end, only take hits value from first call. */
+ data->hits = hits;
+ }
+ if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+ data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS;
+ continue_pass = (hits > 0);
+ }
+ data->pass += 1;
+ }
+ else {
+ BLI_assert(0);
+ }
+ return continue_pass;
+
+}
+#endif /* WITH_OPENGL_LEGACY */
+
/**
* \warning be sure to account for a negative return value
* This is an error, "Too many objects in select buffer"
@@ -931,6 +970,11 @@ int view3d_opengl_select(
goto finally;
}
+#ifndef WITH_OPENGL_LEGACY
+ /* All of the queries need to be perform on the drawing context. */
+ DRW_opengl_context_enable();
+#endif
+
G.f |= G_PICKSEL;
/* Important we use the 'viewmat' and don't re-calculate since
@@ -941,47 +985,44 @@ int view3d_opengl_select(
v3d->zbuf = true;
glEnable(GL_DEPTH_TEST);
}
-
+
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_set(vc->rv3d);
- GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
#ifdef WITH_OPENGL_LEGACY
if (IS_VIEWPORT_LEGACY(vc->v3d)) {
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
+ hits = GPU_select_end();
+
+ if (do_passes && (hits > 0)) {
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
+ GPU_select_end();
+ }
}
else
#else
{
+ /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop
+ * because the OpenGL context created & destroyed inside this function. */
+ struct DrawSelectLoopUserData drw_select_loop_user_data = {
+ .pass = 0,
+ .hits = 0,
+ .buffer = buffer,
+ .buffer_len = bufsize,
+ .rect = &rect,
+ .gpu_select_mode = gpu_select_mode,
+ };
DRW_draw_select_loop(
graph, ar, v3d, eval_ctx->object_mode,
- use_obedit_skip, use_nearest, &rect);
+ use_obedit_skip, use_nearest, &rect,
+ drw_select_loop_pass, &drw_select_loop_user_data);
+ hits = drw_select_loop_user_data.hits;
}
#endif /* WITH_OPENGL_LEGACY */
- hits = GPU_select_end();
-
- /* second pass, to get the closest object to camera */
- if (do_passes && (hits > 0)) {
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
-
-#ifdef WITH_OPENGL_LEGACY
- if (IS_VIEWPORT_LEGACY(vc->v3d)) {
- ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
- }
- else
-#else
- {
- DRW_draw_select_loop(
- graph, ar, v3d, eval_ctx->object_mode,
- use_obedit_skip, use_nearest, &rect);
- }
-#endif /* WITH_OPENGL_LEGACY */
-
- GPU_select_end();
- }
-
G.f &= ~G_PICKSEL;
ED_view3d_draw_setup_view(vc->win, eval_ctx, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
@@ -993,7 +1034,12 @@ int view3d_opengl_select(
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
+#ifndef WITH_OPENGL_LEGACY
+ DRW_opengl_context_disable();
+#endif
+
finally:
+
if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */
UI_Theme_Restore(&theme_state);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 96970fa8a0f..5d267767cf9 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -2049,7 +2049,7 @@ void flushTransParticles(TransInfo *t)
point->flag |= PEP_EDIT_RECALC;
}
- PE_update_object(&t->eval_ctx, scene, view_layer, OBACT(view_layer), 1);
+ PE_update_object(&t->eval_ctx, scene, OBACT(view_layer), 1);
}
/* ********************* mesh ****************** */
@@ -3497,67 +3497,136 @@ static void posttrans_mask_clean(Mask *mask)
}
}
+/* Time + Average value */
+typedef struct tRetainedKeyframe {
+ struct tRetainedKeyframe *next, *prev;
+ float frame; /* frame to cluster around */
+ float val; /* average value */
+
+ size_t tot_count; /* number of keyframes that have been averaged */
+ size_t del_count; /* number of keyframes of this sort that have been deleted so far */
+} tRetainedKeyframe;
+
/* Called during special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
*/
static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
{
- float *selcache; /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */
- int len, index, i; /* number of frames in cache, item index */
-
- /* allocate memory for the cache */
- // TODO: investigate using BezTriple columns instead?
- if (fcu->totvert == 0 || fcu->bezt == NULL)
+ /* NOTE: We assume that all keys are sorted */
+ ListBase retained_keys = {NULL, NULL};
+ const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) == 0);
+
+ /* sanity checks */
+ if ((fcu->totvert == 0) || (fcu->bezt == NULL))
return;
- selcache = MEM_callocN(sizeof(float) * fcu->totvert, "FCurveSelFrameNums");
- len = 0;
- index = 0;
-
- /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting
- * as there is no guarantee what order the keyframes are exactly, even though
- * they have been sorted by time.
+
+ /* 1) Identify selected keyframes, and average the values on those
+ * in case there are collisions due to multiple keys getting scaled
+ * to all end up on the same frame
*/
-
- /* Loop 1: find selected keyframes */
- for (i = 0; i < fcu->totvert; i++) {
+ for (int i = 0; i < fcu->totvert; i++) {
BezTriple *bezt = &fcu->bezt[i];
if (BEZT_ISSEL_ANY(bezt)) {
- selcache[index] = bezt->vec[1][0];
- index++;
- len++;
+ bool found = false;
+
+ /* If there's another selected frame here, merge it */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
+ rk->val += bezt->vec[1][1];
+ rk->tot_count++;
+
+ found = true;
+ break;
+ }
+ else if (rk->frame < bezt->vec[1][0]) {
+ /* Terminate early if have passed the supposed insertion point? */
+ break;
+ }
+ }
+
+ /* If nothing found yet, create a new one */
+ if (found == false) {
+ tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe");
+
+ rk->frame = bezt->vec[1][0];
+ rk->val = bezt->vec[1][1];
+ rk->tot_count = 1;
+
+ BLI_addtail(&retained_keys, rk);
+ }
}
}
-
- /* Loop 2: delete unselected keyframes on the same frames
- * (if any keyframes were found, or the whole curve wasn't affected)
+
+ if (BLI_listbase_is_empty(&retained_keys)) {
+ /* This may happen if none of the points were selected... */
+ if (G.debug & G_DEBUG) {
+ printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
+ }
+ return;
+ }
+ else {
+ /* Compute the average values for each retained keyframe */
+ for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ rk->val = rk->val / (float)rk->tot_count;
+ }
+ }
+
+ /* 2) Delete all keyframes duplicating the "retained keys" found above
+ * - Most of these will be unselected keyframes
+ * - Some will be selected keyframes though. For those, we only keep the last one
+ * (or else everything is gone), and replace its value with the averaged value.
*/
- if ((len) && (len != fcu->totvert)) {
- for (i = fcu->totvert - 1; i >= 0; i--) {
- BezTriple *bezt = &fcu->bezt[i];
-
- if (BEZT_ISSEL_ANY(bezt) == 0) {
- /* check beztriple should be removed according to cache */
- for (index = 0; index < len; index++) {
- if (IS_EQF(bezt->vec[1][0], selcache[index])) {
+ for (int i = fcu->totvert - 1; i >= 0; i--) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ /* Is this keyframe a candidate for deletion? */
+ /* TODO: Replace loop with an O(1) lookup instead */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
+ /* Selected keys are treated with greater care than unselected ones... */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
+ * (or else we wouldn't have any keyframe left here)
+ * - Otherwise, there are still other selected keyframes on this frame
+ * to be merged down still ==> DELETE IT
+ */
+ if (rk->del_count == rk->tot_count - 1) {
+ /* Update keyframe... */
+ if (can_average_points) {
+ /* TODO: update handles too? */
+ bezt->vec[1][1] = rk->val;
+ }
+ }
+ else {
+ /* Delete Keyframe */
delete_fcurve_key(fcu, i, 0);
- break;
}
- else if (bezt->vec[1][0] < selcache[index])
- break;
+
+ /* Update count of how many we've deleted
+ * - It should only matter that we're doing this for all but the last one
+ */
+ rk->del_count++;
+ }
+ else {
+ /* Always delete - Unselected keys don't matter */
+ delete_fcurve_key(fcu, i, 0);
}
+
+ /* Stop the RK search... we've found our match now */
+ break;
}
}
-
- testhandles_fcurve(fcu, use_handle);
}
-
- /* free cache */
- MEM_freeN(selcache);
+
+ /* 3) Recalculate handles */
+ testhandles_fcurve(fcu, use_handle);
+
+ /* cleanup */
+ BLI_freelistN(&retained_keys);
}
-
/* Called by special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
* remake_action_ipos should have already been called
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index fdf5665b6d4..fbe9c2ef240 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -280,7 +280,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
/* only push down if action is more than 1-2 frames long */
calc_action_range(adt->action, &astart, &aend, 1);
if (aend > astart + 2.0f) {
- NlaStrip *strip = add_nlastrip_to_stack(adt, adt->action);
+ NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action);
/* clear reference to action now that we've pushed it onto the stack */
id_us_min(&adt->action->id);
diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c
index 9b6dd187c15..a9414a7f4bf 100644
--- a/source/blender/editors/transform/transform_manipulator2d.c
+++ b/source/blender/editors/transform/transform_manipulator2d.c
@@ -353,6 +353,10 @@ void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorG
*/
bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ if ((U.manipulator_flag & USER_MANIPULATOR_DRAW) == 0) {
+ return false;
+ }
+
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 14cd4bcc7ac..0020b0924bb 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -62,6 +62,10 @@
#include "transform.h"
+/* -------------------------------------------------------------------- */
+/** Internal Data Types
+ * \{ */
+
enum eViewProj {
VIEW_PROJ_NONE = -1,
VIEW_PROJ_ORTHO = 0,
@@ -137,10 +141,8 @@ struct SnapObjectContext {
/** \} */
-
/* -------------------------------------------------------------------- */
-
-/** Common utilities
+/** Common Utilities
* \{ */
@@ -260,9 +262,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
/** \} */
-
/* -------------------------------------------------------------------- */
-
/** \name Ray Cast Funcs
* \{ */
@@ -789,7 +789,6 @@ static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob,
* Walks through all objects in the scene to find the `hit` on object surface.
*
* \param sctx: Snap context to store data.
- * \param snapdata: struct generated in `set_snapdata`.
* \param snap_select : from enum eSnapSelect.
* \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
* \param obj_list: List with objects to snap (created in `create_object_list`).
@@ -846,9 +845,7 @@ static bool raycastObjects(
/** \} */
-
/* -------------------------------------------------------------------- */
-
/** Snap Nearest utilities
* \{ */
@@ -1158,9 +1155,7 @@ static float dist_squared_to_projected_aabb_simple(
/** \} */
-
/* -------------------------------------------------------------------- */
-
/** Walk DFS
* \{ */
@@ -1256,7 +1251,6 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a
/** \} */
/* -------------------------------------------------------------------- */
-
/** \name Internal Object Snapping API
* \{ */
@@ -2080,9 +2074,7 @@ static bool snapObjectsRay(
/** \} */
-
/* -------------------------------------------------------------------- */
-
/** \name Public Object Snapping API
* \{ */
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index a5a26cf4d57..7a5b8bfbda1 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -60,6 +60,8 @@
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
+#include "BKE_layer.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -90,7 +92,6 @@
void ED_editors_init(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Scene *sce = CTX_data_scene(C);
/* This is called during initialization, so we don't want to store any reports */
ReportList *reports = CTX_wm_reports(C);
@@ -98,9 +99,45 @@ void ED_editors_init(bContext *C)
SWAP(int, reports->flag, reports_flag_prev);
+
+ /* toggle on modes for objects that were saved with these enabled. for
+ * e.g. linked objects we have to ensure that they are actually the
+ * active object in this scene. */
+ {
+ wmWindow *win_orig = CTX_wm_window(C);
+ CTX_wm_window_set(C, NULL);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace);
+ Object *obact = view_layer ? OBACT(view_layer) : NULL;
+ eObjectMode object_mode = workspace->object_mode;
+ workspace->object_mode = OB_MODE_OBJECT;
+ if (view_layer && obact) {
+ const ID *data = obact->data;
+ if (!ELEM(object_mode, OB_MODE_OBJECT, OB_MODE_POSE)) {
+ if (!ID_IS_LINKED(obact) && !(data && ID_IS_LINKED(data))) {
+ CTX_wm_window_set(C, win);
+ ED_object_mode_toggle(C, object_mode);
+ CTX_wm_window_set(C, NULL);
+ }
+ }
+ else if (object_mode == OB_MODE_POSE) {
+ if (!ID_IS_LINKED(obact) && (obact->type == OB_ARMATURE)) {
+ workspace->object_mode = object_mode;
+ }
+ }
+ }
+ }
+ CTX_wm_window_set(C, win_orig);
+ }
+
/* image editor paint mode */
- if (sce) {
- ED_space_image_paint_update(wm, sce);
+ {
+ Scene *sce = CTX_data_scene(C);
+ if (sce) {
+ ED_space_image_paint_update(wm, sce);
+ }
}
SWAP(int, reports->flag, reports_flag_prev);
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index d9f777771a8..43d1bfe1e6c 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -49,54 +49,38 @@
#include "ED_util.h"
#include "ED_mesh.h"
-
#include "util_intern.h"
-/* ***************** generic editmode undo system ********************* */
-/*
- * Add this in your local code:
- *
- * void undo_editmode_push(bContext *C, const char *name,
- * void * (*getdata)(bContext *C), // use context to retrieve current editdata
- * void (*freedata)(void *), // pointer to function freeing data
- * void (*to_editmode)(void *, void *), // data to editmode conversion
- * void * (*from_editmode)(void *)) // editmode to data conversion
- * int (*validate_undo)(void *, void *)) // check if undo data is still valid
- *
- *
- * Further exported for UI is:
- *
- * void undo_editmode_step(bContext *C, int step); // undo and redo
- * void undo_editmode_clear(void) // free & clear all data
- * void undo_editmode_menu(void) // history menu
- */
-
-/* ********************************************************************* */
-
/* ****** XXX ***** */
static void error(const char *UNUSED(arg)) {}
/* ****** XXX ***** */
typedef struct UndoElem {
struct UndoElem *next, *prev;
- ID id; // copy of editmode object ID
- Object *ob; // pointer to edited object
- int type; // type of edited object
+ /** copy of edit-mode object ID */
+ ID id;
+ /** pointer to edited object */
+ Object *ob;
+ /** type of edited object */
+ int type;
void *undodata;
uintptr_t undosize;
char name[BKE_UNDO_STR_MAX];
+
+ /** Use context to retrieve current edit-data. */
void * (*getdata)(bContext * C);
+ /** Pointer to function freeing data. */
void (*freedata)(void *);
+ /** Data to edit-mode conversion. */
void (*to_editmode)(void *, void *, void *);
+ /** Edit-mode to data conversion. */
void * (*from_editmode)(void *, void *);
+ /** Check if undo data is still valid. */
int (*validate_undo)(void *, void *);
} UndoElem;
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
-
-
-/* ********************* xtern api calls ************* */
+static ListBase g_undobase = {NULL, NULL};
+static UndoElem *g_curundo = NULL;
static void undo_restore(UndoElem *undo, void *editdata, void *obdata)
{
@@ -105,34 +89,38 @@ static void undo_restore(UndoElem *undo, void *editdata, void *obdata)
}
}
-/* name can be a dynamic string */
-void undo_editmode_push(bContext *C, const char *name,
- void * (*getdata)(bContext * C),
- void (*freedata)(void *),
- void (*to_editmode)(void *, void *, void *),
- void *(*from_editmode)(void *, void *),
- int (*validate_undo)(void *, void *))
+/**
+ * name can be a dynamic string
+ * See #UndoElem for callbacks docs.
+ * */
+void undo_editmode_push(
+ bContext *C, const char *name,
+ void * (*getdata)(bContext * C),
+ void (*freedata)(void *),
+ void (*to_editmode)(void *, void *, void *),
+ void *(*from_editmode)(void *, void *),
+ int (*validate_undo)(void *, void *))
{
UndoElem *uel;
Object *obedit = CTX_data_edit_object(C);
void *editdata;
int nr;
- uintptr_t memused, totmem, maxmem;
+ uintptr_t mem_used, mem_total, mem_max;
/* at first here was code to prevent an "original" key to be inserted twice
* this was giving conflicts for example when mesh changed due to keys or apply */
- /* remove all undos after (also when curundo == NULL) */
- while (undobase.last != curundo) {
- uel = undobase.last;
+ /* remove all undos after (also when g_curundo == NULL) */
+ while (g_undobase.last != g_curundo) {
+ uel = g_undobase.last;
uel->freedata(uel->undodata);
- BLI_freelinkN(&undobase, uel);
+ BLI_freelinkN(&g_undobase, uel);
}
/* make new */
- curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode");
+ g_curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode");
BLI_strncpy(uel->name, name, sizeof(uel->name));
- BLI_addtail(&undobase, uel);
+ BLI_addtail(&g_undobase, uel);
uel->getdata = getdata;
uel->freedata = freedata;
@@ -142,49 +130,53 @@ void undo_editmode_push(bContext *C, const char *name,
/* limit amount to the maximum amount*/
nr = 0;
- uel = undobase.last;
+ uel = g_undobase.last;
while (uel) {
nr++;
- if (nr == U.undosteps) break;
+ if (nr == U.undosteps) {
+ break;
+ }
uel = uel->prev;
}
if (uel) {
- while (undobase.first != uel) {
- UndoElem *first = undobase.first;
+ while (g_undobase.first != uel) {
+ UndoElem *first = g_undobase.first;
first->freedata(first->undodata);
- BLI_freelinkN(&undobase, first);
+ BLI_freelinkN(&g_undobase, first);
}
}
/* copy */
- memused = MEM_get_memory_in_use();
+ mem_used = MEM_get_memory_in_use();
editdata = getdata(C);
- curundo->undodata = curundo->from_editmode(editdata, obedit->data);
- curundo->undosize = MEM_get_memory_in_use() - memused;
- curundo->ob = obedit;
- curundo->id = obedit->id;
- curundo->type = obedit->type;
+ g_curundo->undodata = g_curundo->from_editmode(editdata, obedit->data);
+ g_curundo->undosize = MEM_get_memory_in_use() - mem_used;
+ g_curundo->ob = obedit;
+ g_curundo->id = obedit->id;
+ g_curundo->type = obedit->type;
if (U.undomemory != 0) {
/* limit to maximum memory (afterwards, we can't know in advance) */
- totmem = 0;
- maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024;
+ mem_total = 0;
+ mem_max = ((uintptr_t)U.undomemory) * 1024 * 1024;
- uel = undobase.last;
+ uel = g_undobase.last;
while (uel && uel->prev) {
- totmem += uel->undosize;
- if (totmem > maxmem) break;
+ mem_total += uel->undosize;
+ if (mem_total > mem_max) {
+ break;
+ }
uel = uel->prev;
}
if (uel) {
- if (uel->prev && uel->prev->prev)
+ if (uel->prev && uel->prev->prev) {
uel = uel->prev;
-
- while (undobase.first != uel) {
- UndoElem *first = undobase.first;
+ }
+ while (g_undobase.first != uel) {
+ UndoElem *first = g_undobase.first;
first->freedata(first->undodata);
- BLI_freelinkN(&undobase, first);
+ BLI_freelinkN(&g_undobase, first);
}
}
}
@@ -193,78 +185,85 @@ void undo_editmode_push(bContext *C, const char *name,
/* helper to remove clean other objects from undo stack */
static void undo_clean_stack(bContext *C)
{
- UndoElem *uel, *next;
+ UndoElem *uel;
Object *obedit = CTX_data_edit_object(C);
-
+
/* global undo changes pointers, so we also allow identical names */
/* side effect: when deleting/renaming object and start editing new one with same name */
-
- uel = undobase.first;
+
+ uel = g_undobase.first;
while (uel) {
void *editdata = uel->getdata(C);
bool is_valid = false;
- next = uel->next;
-
+ UndoElem *uel_next = uel->next;
+
/* for when objects are converted, renamed, or global undo changes pointers... */
if (uel->type == obedit->type) {
if (STREQ(uel->id.name, obedit->id.name)) {
- if (uel->validate_undo == NULL)
+ if (uel->validate_undo == NULL) {
is_valid = true;
- else if (uel->validate_undo(uel->undodata, editdata))
+ }
+ else if (uel->validate_undo(uel->undodata, editdata)) {
is_valid = true;
+ }
}
}
- if (is_valid)
+ if (is_valid) {
uel->ob = obedit;
+ }
else {
- if (uel == curundo)
- curundo = NULL;
+ if (uel == g_curundo) {
+ g_curundo = NULL;
+ }
uel->freedata(uel->undodata);
- BLI_freelinkN(&undobase, uel);
+ BLI_freelinkN(&g_undobase, uel);
}
-
- uel = next;
+
+ uel = uel_next;
+ }
+
+ if (g_curundo == NULL) {
+ g_curundo = g_undobase.last;
}
-
- if (curundo == NULL) curundo = undobase.last;
}
-/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
+/**
+ * 1 = an undo, -1 is a redo.
+ * we have to make sure 'g_curundo' remains at current situation
+ */
void undo_editmode_step(bContext *C, int step)
{
Object *obedit = CTX_data_edit_object(C);
-
+
/* prevent undo to happen on wrong object, stack can be a mix */
undo_clean_stack(C);
-
+
if (step == 0) {
- undo_restore(curundo, curundo->getdata(C), obedit->data);
+ undo_restore(g_curundo, g_curundo->getdata(C), obedit->data);
}
else if (step == 1) {
-
- if (curundo == NULL || curundo->prev == NULL) {
+ if (g_curundo == NULL || g_curundo->prev == NULL) {
error("No more steps to undo");
}
else {
- if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name);
- curundo = curundo->prev;
- undo_restore(curundo, curundo->getdata(C), obedit->data);
+ if (G.debug & G_DEBUG) printf("undo %s\n", g_curundo->name);
+ g_curundo = g_curundo->prev;
+ undo_restore(g_curundo, g_curundo->getdata(C), obedit->data);
}
}
else {
- /* curundo has to remain current situation! */
-
- if (curundo == NULL || curundo->next == NULL) {
+ /* g_curundo has to remain current situation! */
+ if (g_curundo == NULL || g_curundo->next == NULL) {
error("No more steps to redo");
}
else {
- undo_restore(curundo->next, curundo->getdata(C), obedit->data);
- curundo = curundo->next;
- if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name);
+ undo_restore(g_curundo->next, g_curundo->getdata(C), obedit->data);
+ g_curundo = g_curundo->next;
+ if (G.debug & G_DEBUG) printf("redo %s\n", g_curundo->name);
}
}
-
+
/* special case for editmesh, mode must be copied back to the scene */
if (obedit->type == OB_MESH) {
EDBM_selectmode_to_scene(C);
@@ -278,14 +277,14 @@ void undo_editmode_step(bContext *C, int step)
void undo_editmode_clear(void)
{
UndoElem *uel;
-
- uel = undobase.first;
+
+ uel = g_undobase.first;
while (uel) {
uel->freedata(uel->undodata);
uel = uel->next;
}
- BLI_freelistN(&undobase);
- curundo = NULL;
+ BLI_freelistN(&g_undobase);
+ g_curundo = NULL;
}
/* based on index nr it does a restore */
@@ -293,58 +292,69 @@ void undo_editmode_number(bContext *C, int nr)
{
UndoElem *uel;
int a = 1;
-
- for (uel = undobase.first; uel; uel = uel->next, a++) {
- if (a == nr) break;
+
+ for (uel = g_undobase.first; uel; uel = uel->next, a++) {
+ if (a == nr) {
+ break;
+ }
}
- curundo = uel;
+ g_curundo = uel;
undo_editmode_step(C, 0);
}
void undo_editmode_name(bContext *C, const char *undoname)
{
UndoElem *uel;
-
- for (uel = undobase.last; uel; uel = uel->prev) {
- if (STREQ(undoname, uel->name))
+
+ for (uel = g_undobase.last; uel; uel = uel->prev) {
+ if (STREQ(undoname, uel->name)) {
break;
+ }
}
if (uel && uel->prev) {
- curundo = uel->prev;
+ g_curundo = uel->prev;
undo_editmode_step(C, 0);
}
}
-/* undoname optionally, if NULL it just checks for existing undo steps */
+/**
+ * \a undoname is optional, when NULL it just checks for existing undo steps
+ */
bool undo_editmode_is_valid(const char *undoname)
{
if (undoname) {
UndoElem *uel;
-
- for (uel = undobase.last; uel; uel = uel->prev) {
- if (STREQ(undoname, uel->name))
+
+ for (uel = g_undobase.last; uel; uel = uel->prev) {
+ if (STREQ(undoname, uel->name)) {
break;
+ }
}
return uel != NULL;
}
- return undobase.last != undobase.first;
+ return g_undobase.last != g_undobase.first;
}
-/* get name of undo item, return null if no item with this index */
-/* if active pointer, set it to 1 if true */
+/**
+ * Get name of undo item, return null if no item with this index.
+ *
+ * if active pointer, set it to 1 if true
+ */
const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active)
{
UndoElem *uel;
-
+
/* prevent wrong numbers to be returned */
undo_clean_stack(C);
-
- if (r_active) *r_active = false;
-
- uel = BLI_findlink(&undobase, nr);
+
+ if (r_active) {
+ *r_active = false;
+ }
+
+ uel = BLI_findlink(&g_undobase, nr);
if (uel) {
- if (r_active && (uel == curundo)) {
+ if (r_active && (uel == g_curundo)) {
*r_active = true;
}
return uel->name;
@@ -355,7 +365,9 @@ const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active)
void *undo_editmode_get_prev(Object *ob)
{
- UndoElem *ue = undobase.last;
- if (ue && ue->prev && ue->prev->ob == ob) return ue->prev->undodata;
+ UndoElem *ue = g_undobase.last;
+ if (ue && ue->prev && ue->prev->ob == ob) {
+ return ue->prev->undodata;
+ }
return NULL;
}
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 0f3240946fd..a139f0e3c87 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -478,9 +478,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
/* At this point, our value has changed, try to interpret it with python (if str is not empty!). */
if (n->str[0]) {
const float val_prev = n->val[idx];
+ double val;
#ifdef WITH_PYTHON
Scene *sce = CTX_data_scene(C);
- double val;
char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */
const char *default_unit = NULL;
@@ -506,8 +506,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
n->val_flag[idx] |= NUM_INVALID;
}
#else /* Very unlikely, but does not harm... */
- n->val[idx] = (float)atof(n->str);
- (void)C;
+ val = atof(n->str);
+ n->val[idx] = (float)val;
+ UNUSED_VARS(C);
#endif /* WITH_PYTHON */
if (n->val_flag[idx] & NUM_NEGATE) {
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 8eaadb97888..54654a5ef16 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -55,6 +55,7 @@
#include "ED_particle.h"
#include "ED_curve.h"
#include "ED_gpencil.h"
+#include "ED_lattice.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_object.h"
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index b4d32b3d03a..cb8aa9660cf 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -59,6 +59,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "GPU_batch.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
@@ -73,7 +74,7 @@
#include "uvedit_intern.h"
-static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos);
+static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos);
void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
{
@@ -160,8 +161,6 @@ static void draw_uvs_shadow(Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
- BMFace *efa;
- BMIter iter;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
@@ -172,9 +171,7 @@ static void draw_uvs_shadow(Object *obedit)
/* draws the mesh when painting */
immUniformThemeColor(TH_UV_SHADOW);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
- }
+ draw_uvs_lineloop_bmfaces(bm, cd_loop_uv_offset, pos);
immUnbindProgram();
}
@@ -384,18 +381,43 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, Object *obedit, BME
BLI_buffer_free(&tf_uvorig_buf);
}
-static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos)
+static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos)
{
- BMIter liter;
+ BMIter iter, liter;
+ BMFace *efa;
BMLoop *l;
MLoopUV *luv;
- immBegin(GWN_PRIM_LINE_LOOP, efa->len);
+ /* For more efficiency first transfer the entire buffer to vram. */
+ Gwn_Batch *uv_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop);
+
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
+
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ immVertex2fv(shdr_pos, luv->uv);
+ }
+ }
+ immEnd();
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- immVertex2fv(shdr_pos, luv->uv);
+ /* Then draw each face contour separately. */
+ GWN_batch_program_use_begin(uv_batch);
+ unsigned int index = 0;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
+
+ GWN_batch_draw_range_ex(uv_batch, index, efa->len, false);
+ index += efa->len;
}
+ GWN_batch_program_use_end(uv_batch);
+
+ GWN_vertbuf_discard(uv_batch->verts[0]);
+ GWN_batch_discard(uv_batch);
+
+ immUnbindProgram();
immEnd();
}
@@ -615,7 +637,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
- unsigned char col1[4], col2[4];
+ float col1[4], col2[4];
float pointsize;
int drawfaces, interpedges;
Image *ima = sima->image;
@@ -685,14 +707,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) {
/* draw transparent faces */
- UI_GetThemeColor4ubv(TH_FACE, col1);
- UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
+ UI_GetThemeColor4fv(TH_FACE, col1);
+ UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
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);
+ color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
@@ -704,12 +726,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
if (efa == efa_act) {
/* only once */
- unsigned char tmp_col[4];
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col);
- immAttrib4ubv(color, tmp_col);
+ float tmp_col[4];
+ UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, tmp_col);
+ immAttrib4fv(color, tmp_col);
}
else {
- immAttrib4ubv(color, is_select ? col2 : col1);
+ immAttrib4fv(color, is_select ? col2 : col1);
}
draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos);
@@ -739,13 +761,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
- glLineWidth(1);
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
switch (sima->dt_uv) {
case SI_UVDT_DASH:
{
- const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
@@ -755,141 +775,160 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
immUniform1i("num_colors", 2); /* "advanced" mode */
immUniformArray4fv("colors", (float *)(float[][4]){{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}, 2);
immUniform1f("dash_width", 4.0f);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, shdr_pos);
- }
-
- immUnbindProgram();
+ glLineWidth(1.0f);
break;
}
case SI_UVDT_BLACK: /* black/white */
case SI_UVDT_WHITE:
- pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
if (sima->dt_uv == SI_UVDT_WHITE) {
immUniformColor3f(1.0f, 1.0f, 1.0f);
}
else {
immUniformColor3f(0.0f, 0.0f, 0.0f);
}
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
- }
-
- immUnbindProgram();
+ glLineWidth(1.0f);
break;
case SI_UVDT_OUTLINE:
- pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- glLineWidth(3);
imm_cpack(0x0);
+ glLineWidth(3.0f);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
+ break;
+ }
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
- }
+ /* For more efficiency first transfer the entire buffer to vram. */
+ Gwn_Batch *uv_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop);
+ Gwn_VertBuf* uv_vbo = uv_batch->verts[0];
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
- immUnbindProgram();
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ immVertex2fv(pos, luv->uv);
+ }
+ }
+ immEnd();
- glLineWidth(1);
- UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2);
+ /* Then draw each face contour separately. */
+ GWN_batch_program_use_begin(uv_batch);
+ unsigned int index = 0, vbo_len_used;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
- if (me->drawflag & ME_DRAWEDGES) {
- int sel;
- UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1);
+ GWN_batch_draw_range_ex(uv_batch, index, efa->len, false);
+ index += efa->len;
+ }
+ vbo_len_used = index;
+ GWN_batch_program_use_end(uv_batch);
+ immUnbindProgram();
- 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);
- if (interpedges) {
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ if (sima->dt_uv == SI_UVDT_OUTLINE) {
+ glLineWidth(1.0f);
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, col2);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
+ if (me->drawflag & ME_DRAWEDGES) {
+ int sel;
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, col1);
- immBegin(GWN_PRIM_LINE_LOOP, efa->len);
+ if (interpedges) {
+ /* Create a color buffer. */
+ static Gwn_VertFormat format = {0};
+ static uint shdr_col;
+ if (format.attrib_ct == 0) {
+ shdr_col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2);
+ Gwn_VertBuf *vbo_col = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo_col, vbo_len_used);
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- immVertex2fv(pos, luv->uv);
- }
+ index = 0;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
- immEnd();
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ GWN_vertbuf_attr_set(vbo_col, shdr_col, index++, sel ? col1 : col2);
}
-
- immUnbindProgram();
}
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ /* Reuse the UV buffer and add the color buffer. */
+ GWN_batch_vertbuf_add_ex(uv_batch, vbo_col, true);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- int lastsel = -1;
+ /* Now draw each face contour separately with another builtin program. */
+ GWN_batch_program_set_builtin(uv_batch, GPU_SHADER_2D_SMOOTH_COLOR);
+ gpuBindMatrices(uv_batch->interface);
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- immBegin(GWN_PRIM_LINES, efa->len * 2);
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset);
- if (sel != lastsel) {
- immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2);
- lastsel = sel;
- }
-
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- immVertex2fv(pos, luv->uv);
- luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- immVertex2fv(pos, luv->uv);
- }
-
- immEnd();
- }
+ GWN_batch_program_use_begin(uv_batch);
+ index = 0;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
- immUnbindProgram();
+ GWN_batch_draw_range_ex(uv_batch, index, efa->len, false);
+ index += efa->len;
}
+ GWN_batch_program_use_end(uv_batch);
}
else {
- pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ 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_F32, 4, GWN_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4ubv(col2);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- /* no nice edges */
+ /* Use batch here to avoid problems with `IMM_BUFFER_SIZE`. */
+ Gwn_Batch *flat_edges_batch = immBeginBatchAtMost(GWN_PRIM_LINES, vbo_len_used * 2);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
-
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset);
+ immAttrib4fv(color, sel ? col1 : col2);
+
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ immVertex2fv(pos, luv->uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ immVertex2fv(pos, luv->uv);
+ }
}
+ immEnd();
+
+ GWN_batch_draw(flat_edges_batch);
+ GWN_vertbuf_discard(flat_edges_batch->verts[0]);
+ GWN_batch_discard(flat_edges_batch);
immUnbindProgram();
}
+ }
+ else {
+ GWN_batch_uniform_4fv(uv_batch, "color", col2);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- break;
+ /* no nice edges */
+ GWN_batch_program_use_begin(uv_batch);
+ index = 0;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
+
+ GWN_batch_draw_range_ex(uv_batch, index, efa->len, false);
+ index += efa->len;
+ }
+ GWN_batch_program_use_end(uv_batch);
+ immUnbindProgram();
+ }
}
+ GWN_vertbuf_discard(uv_vbo);
+ GWN_batch_discard(uv_batch);
+
if (sima->flag & SI_SMOOTH_UV) {
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -903,7 +942,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);
- 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_F32, 3, GWN_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
@@ -921,8 +960,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
/* Only set color for the first face */
if (!col_set) {
- UI_GetThemeColor3ubv(TH_WIRE, col1);
- immAttrib3ubv(color, col1);
+ UI_GetThemeColor3fv(TH_WIRE, col1);
+ immAttrib3fv(color, col1);
col_set = true;
}
@@ -943,8 +982,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje
if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
/* Only set color for the first face */
if (!col_set) {
- UI_GetThemeColor3ubv(TH_FACE_DOT, col1);
- immAttrib3ubv(color, col1);
+ UI_GetThemeColor3fv(TH_FACE_DOT, col1);
+ immAttrib3fv(color, col1);
col_set = true;
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index eb92f17544f..c5f16d6fb14 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -50,19 +50,30 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off
/* find nearest */
-typedef struct NearestHit {
+typedef struct UvNearestHit {
+ /** Always set if we have a hit. */
struct BMFace *efa;
struct BMLoop *l;
struct MLoopUV *luv, *luv_next;
- int lindex; /* index of loop within face */
-} NearestHit;
-
-void uv_find_nearest_vert(
- struct Scene *scene, struct Image *ima, struct Object *obedit, struct BMEditMesh *em,
- const float co[2], const float penalty[2], struct NearestHit *hit);
-void uv_find_nearest_edge(
- struct Scene *scene, struct Image *ima, struct Object *obedit, struct BMEditMesh *em,
- const float co[2], struct NearestHit *hit);
+ /** Index of loop within face. */
+ int lindex;
+ /** Needs to be set before calling nearest functions. */
+ float dist_sq;
+} UvNearestHit;
+
+#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, }
+
+bool uv_find_nearest_vert(
+ struct Scene *scene, struct Image *ima, struct Object *obedit,
+ const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_edge(
+ struct Scene *scene, struct Image *ima, struct Object *obedit,
+ const float co[2], struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_face(
+ struct Scene *scene, struct Image *ima, struct Object *obedit,
+ const float co[2], struct UvNearestHit *hit_final);
/* utility tool functions */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index f66c9ee9951..9df0c7c89ed 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -93,7 +93,9 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
-/************************* state testing ************************/
+/* -------------------------------------------------------------------- */
+/** \name State Testing
+ * \{ */
bool ED_uvedit_test(Object *obedit)
{
@@ -134,15 +136,21 @@ static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
return 0;
}
-/**************************** object active image *****************************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Active Image
+ * \{ */
static bool is_image_texture_node(bNode *node)
{
return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
}
-bool ED_object_get_active_image(Object *ob, int mat_nr,
- Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
+bool ED_object_get_active_image(
+ Object *ob, int mat_nr,
+ Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
{
Material *ma = give_current_material(ob, mat_nr);
bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
@@ -175,7 +183,11 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
}
}
-/************************* assign image ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Assign Image
+ * \{ */
//#define USE_SWITCH_ASPECT
@@ -266,7 +278,11 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
}
-/*********************** space conversion *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Space Conversion
+ * \{ */
static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
{
@@ -284,7 +300,26 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
dist[1] = pixeldist / height;
}
-/*************** visibility and selection utilities **************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Visibility and Selection Utilities
+ * \{ */
+
+static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset)
+{
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+}
bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
{
@@ -309,8 +344,9 @@ bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *
}
}
-bool uvedit_face_select_test(Scene *scene, BMFace *efa,
- const int cd_loop_uv_offset)
+bool uvedit_face_select_test(
+ Scene *scene, BMFace *efa,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -331,8 +367,9 @@ bool uvedit_face_select_test(Scene *scene, BMFace *efa,
}
}
-bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
- const bool do_history, const int cd_loop_uv_offset)
+bool uvedit_face_select_set(
+ struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
+ const bool do_history, const int cd_loop_uv_offset)
{
if (select) {
return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
@@ -342,8 +379,9 @@ bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct B
}
}
-bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history,
- const int cd_loop_uv_offset)
+bool uvedit_face_select_enable(
+ Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -369,8 +407,9 @@ bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const
return false;
}
-bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa,
- const int cd_loop_uv_offset)
+bool uvedit_face_select_disable(
+ Scene *scene, BMEditMesh *em, BMFace *efa,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -393,8 +432,9 @@ bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa,
return false;
}
-bool uvedit_edge_select_test(Scene *scene, BMLoop *l,
- const int cd_loop_uv_offset)
+bool uvedit_edge_select_test(
+ Scene *scene, BMLoop *l,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -420,8 +460,9 @@ bool uvedit_edge_select_test(Scene *scene, BMLoop *l,
}
}
-void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
- const bool do_history, const int cd_loop_uv_offset)
+void uvedit_edge_select_set(
+ BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
+ const bool do_history, const int cd_loop_uv_offset)
{
if (select) {
@@ -432,8 +473,9 @@ void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool
}
}
-void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history,
- const int cd_loop_uv_offset)
+void uvedit_edge_select_enable(
+ BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -463,8 +505,9 @@ void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bo
}
}
-void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
- const int cd_loop_uv_offset)
+void uvedit_edge_select_disable(
+ BMEditMesh *em, Scene *scene, BMLoop *l,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -490,8 +533,9 @@ void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
}
}
-bool uvedit_uv_select_test(Scene *scene, BMLoop *l,
- const int cd_loop_uv_offset)
+bool uvedit_uv_select_test(
+ Scene *scene, BMLoop *l,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -507,8 +551,9 @@ bool uvedit_uv_select_test(Scene *scene, BMLoop *l,
}
}
-void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
- const bool do_history, const int cd_loop_uv_offset)
+void uvedit_uv_select_set(
+ BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
+ const bool do_history, const int cd_loop_uv_offset)
{
if (select) {
uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
@@ -518,8 +563,9 @@ void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool se
}
}
-void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l,
- const bool do_history, const int cd_loop_uv_offset)
+void uvedit_uv_select_enable(
+ BMEditMesh *em, Scene *scene, BMLoop *l,
+ const bool do_history, const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -539,8 +585,9 @@ void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l,
}
}
-void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
- const int cd_loop_uv_offset)
+void uvedit_uv_select_disable(
+ BMEditMesh *em, Scene *scene, BMLoop *l,
+ const int cd_loop_uv_offset)
{
ToolSettings *ts = scene->toolsettings;
@@ -556,7 +603,11 @@ void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
}
}
-/*********************** live unwrap utilities ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Live Unwrap Utilities
+ * \{ */
void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
{
@@ -567,7 +618,12 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
}
}
-/*********************** geometric utilities ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometric Utilities
+ * \{ */
+
void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
{
BMLoop *l;
@@ -690,82 +746,100 @@ bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], c
return changed;
}
-/************************** find nearest ****************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Find Nearest Elements
+ * \{ */
-void uv_find_nearest_edge(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float co[2], NearestHit *hit)
+bool uv_find_nearest_edge(
+ Scene *scene, Image *ima, Object *obedit, const float co[2],
+ UvNearestHit *hit)
{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv, *luv_next;
- float mindist_squared, dist_squared;
int i;
+ bool found = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- mindist_squared = 1e10f;
- memset(hit, 0, sizeof(*hit));
-
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
-
+ }
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- dist_squared = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+ const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
- if (dist_squared < mindist_squared) {
+ if (dist_test_sq < hit->dist_sq) {
hit->efa = efa;
-
+
hit->l = l;
hit->luv = luv;
hit->luv_next = luv_next;
hit->lindex = i;
- mindist_squared = dist_squared;
+ hit->dist_sq = dist_test_sq;
+ found = true;
}
}
}
+ return found;
}
-static void uv_find_nearest_face(
- Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float co[2], NearestHit *hit)
+bool uv_find_nearest_face(
+ Scene *scene, Image *ima, Object *obedit, const float co[2],
+ UvNearestHit *hit_final)
{
- BMFace *efa;
- BMIter iter;
- float mindist, dist, cent[2];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool found = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- mindist = 1e10f;
- memset(hit, 0, sizeof(*hit));
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
- /*this will fill in hit.vert1 and hit.vert2*/
- uv_find_nearest_edge(scene, ima, obedit, em, co, hit);
- hit->l = NULL;
- hit->luv = hit->luv_next = NULL;
+ BMIter iter;
+ BMFace *efa;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
- uv_poly_center(efa, cent, cd_loop_uv_offset);
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
- dist = len_manhattan_v2v2(co, cent);
+ const float dist_test_sq = len_squared_v2v2(co, cent);
- if (dist < mindist) {
- hit->efa = efa;
- mindist = dist;
+ if (dist_test_sq < hit.dist_sq) {
+ hit.efa = efa;
+ hit.dist_sq = dist_test_sq;
+ found = true;
+ }
}
}
+ if (found) {
+ *hit_final = hit;
+ }
+ return found;
}
-static bool uv_nearest_between(const BMLoop *l, const float co[2],
- const int cd_loop_uv_offset)
+static bool uv_nearest_between(
+ const BMLoop *l, const float co[2],
+ const int cd_loop_uv_offset)
{
const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
@@ -775,57 +849,73 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2],
(line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
}
-void uv_find_nearest_vert(
- Scene *scene, Image *ima, Object *obedit, BMEditMesh *em,
- float const co[2], const float penalty[2], NearestHit *hit)
+bool uv_find_nearest_vert(
+ Scene *scene, Image *ima, Object *obedit,
+ float const co[2], const float penalty_dist, UvNearestHit *hit_final)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- float mindist, dist;
- int i;
+ bool found = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
- /*this will fill in hit.vert1 and hit.vert2*/
- uv_find_nearest_edge(scene, ima, obedit, em, co, hit);
- hit->l = NULL;
- hit->luv = hit->luv_next = NULL;
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
- mindist = 1e10f;
- memset(hit, 0, sizeof(*hit));
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (penalty && uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- dist = len_manhattan_v2v2(co, luv->uv) + len_manhattan_v2(penalty);
- else
- dist = len_manhattan_v2v2(co, luv->uv);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (dist <= mindist) {
- if (dist == mindist) {
- if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
- continue;
- }
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ int i;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ float dist_test_sq;
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
+ dist_test_sq = SQUARE(dist_test_sq);
+ }
+ else {
+ dist_test_sq = len_squared_v2v2(co, luv->uv);
}
- mindist = dist;
+ if (dist_test_sq <= hit.dist_sq) {
+ if (dist_test_sq == hit.dist_sq) {
+ if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
+ continue;
+ }
+ }
- hit->l = l;
- hit->luv = luv;
- hit->luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- hit->efa = efa;
- hit->lindex = i;
+ hit.dist_sq = dist_test_sq;
+
+ hit.l = l;
+ hit.luv = luv;
+ hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ hit.efa = efa;
+ hit.lindex = i;
+ found = true;
+ }
}
}
}
+
+ if (found) {
+ *hit_final = hit;
+ }
+
+ return found;
}
bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
@@ -863,7 +953,11 @@ bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float
return found;
}
-/*********************** loop select ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select
+ * \{ */
static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
{
@@ -949,7 +1043,7 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1,
}
static int uv_select_edgeloop(
- Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, NearestHit *hit,
+ Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, UvNearestHit *hit,
const float limit[2], const bool extend)
{
BMFace *efa;
@@ -1047,11 +1141,15 @@ static int uv_select_edgeloop(
return (select) ? 1 : -1;
}
-/*********************** linked select ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked
+ * \{ */
static void uv_select_linked(
- Scene *scene, Image *ima, Object *obedit, BMEditMesh *em,
- const float limit[2], NearestHit *hit, bool extend, bool select_faces)
+ Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2],
+ UvNearestHit *hit_final, bool extend, bool select_faces)
{
BMFace *efa;
BMLoop *l;
@@ -1081,7 +1179,8 @@ static void uv_select_linked(
stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
- if (!hit) {
+ if (hit_final == NULL) {
+ /* Use existing selection */
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
if (select_faces) {
@@ -1109,7 +1208,7 @@ static void uv_select_linked(
}
else {
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (efa == hit->efa) {
+ if (efa == hit_final->efa) {
stack[stacksize] = a;
stacksize++;
flag[a] = 1;
@@ -1261,6 +1360,12 @@ static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEdi
return NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operator
+ * \{ */
+
static int uv_select_more_less(bContext *C, const bool select)
{
Scene *scene = CTX_data_scene(C);
@@ -1291,9 +1396,7 @@ static int uv_select_more_less(bContext *C, const bool select)
if (ts->uv_selectmode == UV_SELECT_FACE) {
/* clear tags */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- }
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
/* mark loops to be selected */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
@@ -1398,7 +1501,11 @@ static void UV_OT_select_less(wmOperatorType *ot)
ot->poll = ED_operator_uvedit_space_image;
}
-/* ******************** align operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Align Operator
+ * \{ */
static void uv_weld_align(bContext *C, int tool)
{
@@ -1485,9 +1592,7 @@ static void uv_weld_align(bContext *C, int tool)
BMIter iter, liter, eiter;
/* clear tag */
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
- }
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
/* tag verts with a selected UV */
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
@@ -1504,8 +1609,10 @@ static void uv_weld_align(bContext *C, int tool)
/* flush vertex tags to edges */
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(eed, BM_ELEM_TAG, (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
- BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
+ BM_elem_flag_set(
+ eed, BM_ELEM_TAG,
+ (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
+ BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
}
/* find a vertex with only one tagged edge */
@@ -1556,13 +1663,13 @@ static void uv_weld_align(bContext *C, int tool)
}
/* now we have all verts, make into a line */
- if (BLI_array_count(eve_line) > 2) {
+ if (BLI_array_len(eve_line) > 2) {
/* we know the returns from these must be valid */
const float *uv_start = uv_sel_co_from_eve(
scene, obedit, ima, em, eve_line[0]);
const float *uv_end = uv_sel_co_from_eve(
- scene, obedit, ima, em, eve_line[BLI_array_count(eve_line) - 1]);
+ scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
/* For t & u modes */
float a = 0.0f;
@@ -1580,7 +1687,7 @@ static void uv_weld_align(bContext *C, int tool)
}
/* go over all verts except for endpoints */
- for (i = 0; i < BLI_array_count(eve_line); i++) {
+ for (i = 0; i < BLI_array_len(eve_line); i++) {
BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
continue;
@@ -1651,7 +1758,12 @@ static void UV_OT_align(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
}
-/* ******************** weld near operator **************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Doubles Operator
+ * \{ */
typedef struct UVvert {
MLoopUV *uv_loop;
@@ -1689,7 +1801,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
MLoopUV **loop_arr = NULL;
BLI_array_declare(loop_arr);
- /* TODO, use qsort as with MESH_OT_remove_doubles, this isn't optimal */
+ /* TODO, use kd-tree as with MESH_OT_remove_doubles, this isn't optimal */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
@@ -1706,7 +1818,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
}
}
- for (uv_a_index = 0; uv_a_index < BLI_array_count(vert_arr); uv_a_index++) {
+ for (uv_a_index = 0; uv_a_index < BLI_array_len(vert_arr); uv_a_index++) {
if (vert_arr[uv_a_index].weld == false) {
float uv_min[2];
float uv_max[2];
@@ -1720,7 +1832,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
copy_v2_v2(uv_min, uv_a);
vert_arr[uv_a_index].weld = true;
- for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_count(vert_arr); uv_b_index++) {
+ for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_len(vert_arr); uv_b_index++) {
uv_b = vert_arr[uv_b_index].uv_loop->uv;
if ((vert_arr[uv_b_index].weld == false) &&
(len_manhattan_v2v2(uv_a, uv_b) < threshold))
@@ -1730,10 +1842,10 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
vert_arr[uv_b_index].weld = true;
}
}
- if (BLI_array_count(loop_arr)) {
+ if (BLI_array_len(loop_arr)) {
float uv_mid[2];
mid_v2_v2v2(uv_mid, uv_min, uv_max);
- for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr); uv_b_index++) {
+ for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr); uv_b_index++) {
copy_v2_v2(loop_arr[uv_b_index]->uv, uv_mid);
}
}
@@ -1767,12 +1879,12 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
}
}
- for (uv_a_index = 0; uv_a_index < BLI_array_count(loop_arr); uv_a_index++) {
+ for (uv_a_index = 0; uv_a_index < BLI_array_len(loop_arr); uv_a_index++) {
float dist_best = FLT_MAX, dist;
const float *uv_best = NULL;
uv_a = loop_arr[uv_a_index]->uv;
- for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr_unselected); uv_b_index++) {
+ for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr_unselected); uv_b_index++) {
uv_b = loop_arr_unselected[uv_b_index]->uv;
dist = len_manhattan_v2v2(uv_a, uv_b);
if ((dist < threshold) && (dist < dist_best)) {
@@ -1812,7 +1924,12 @@ static void UV_OT_remove_doubles(wmOperatorType *ot)
"Merge Distance", "Maximum distance between welded vertices", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
}
-/* ******************** weld operator **************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Near Operator
+ * \{ */
static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1834,8 +1951,11 @@ static void UV_OT_weld(wmOperatorType *ot)
ot->poll = ED_operator_uvedit;
}
+/** \} */
-/* ******************** (de)select all operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action)
{
@@ -1938,9 +2058,13 @@ static void UV_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/* ******************** mouse select operator **************** */
+/** \} */
-static bool uv_sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
+/* -------------------------------------------------------------------- */
+/** \name Mouse Select Operator
+ * \{ */
+
+static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
{
int i;
@@ -1975,12 +2099,11 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
- NearestHit hit;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
int i, selectmode, sticky, sync, *hitv = NULL;
bool select = true;
int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
float limit[2], **hituv = NULL;
- float penalty[2];
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
@@ -1990,8 +2113,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
* shift-selecting can consider an adjacent point close enough to add to
* the selection rather than de-selecting the closest. */
- uvedit_pixel_to_float(sima, limit, 0.05f);
- uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
+ float penalty_dist;
+ {
+ float penalty[2];
+ uvedit_pixel_to_float(sima, limit, 0.05f);
+ uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
+ penalty_dist = len_v2(penalty);
+ }
/* retrieve operation mode */
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -2015,8 +2143,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* find nearest element */
if (loop) {
/* find edge */
- uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2024,8 +2151,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_VERTEX) {
/* find vertex */
- uv_find_nearest_vert(scene, ima, obedit, em, co, penalty, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2041,8 +2167,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_EDGE) {
/* find edge */
- uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2060,11 +2185,10 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_FACE) {
/* find face */
- uv_find_nearest_face(scene, ima, obedit, em, co, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_face(scene, ima, obedit, co, &hit)) {
return OPERATOR_CANCELLED;
}
-
+
/* make active */
BM_mesh_active_face_set(em->bm, hit.efa);
@@ -2081,9 +2205,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
hitlen = hit.efa->len;
}
else if (selectmode == UV_SELECT_ISLAND) {
- uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
-
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2261,7 +2383,11 @@ static void UV_OT_select(wmOperatorType *ot)
"Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
}
-/* ******************** loop select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select Operator
+ * \{ */
static int uv_select_loop_exec(bContext *C, wmOperator *op)
{
@@ -2306,7 +2432,11 @@ static void UV_OT_select_loop(wmOperatorType *ot)
"Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
}
-/* ******************** linked select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick)
{
@@ -2320,7 +2450,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
int extend;
bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
- NearestHit hit, *hit_p = NULL;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
@@ -2345,11 +2475,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
RNA_float_get_array(op->ptr, "location", co);
}
- uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
- hit_p = &hit;
+ if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
}
- uv_select_linked(scene, ima, obedit, em, limit, hit_p, extend, select_faces);
+ uv_select_linked(scene, ima, obedit, em, limit, pick ? &hit : NULL, extend, select_faces);
DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -2513,17 +2644,21 @@ static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short s
}
}
-
+/** \} */
/* -------------------------------------------------------------------- */
-/* Utility functions to flush the uv-selection from tags */
+/** \name Select/Tag Flushing Utils
+ *
+ * Utility functions to flush the uv-selection from tags.
+ * \{ */
/**
* helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
*/
-static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, BMEditMesh *em, UvVertMap *vmap,
- const unsigned int efa_index, BMLoop *l,
- const bool select, const int cd_loop_uv_offset)
+static void uv_select_flush_from_tag_sticky_loc_internal(
+ Scene *scene, BMEditMesh *em, UvVertMap *vmap,
+ const unsigned int efa_index, BMLoop *l,
+ const bool select, const int cd_loop_uv_offset)
{
UvMapVert *start_vlist = NULL, *vlist_iter;
BMFace *efa_vlist;
@@ -2587,12 +2722,8 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
/* Tag all verts as untouched, then touch the ones that have a face center
* in the loop and select all MLoopUV's that use a touched vert. */
- BMVert *eve;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
- }
-
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2630,8 +2761,9 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
/* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l,
- select, cd_loop_uv_offset);
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l,
+ select, cd_loop_uv_offset);
}
}
}
@@ -2677,11 +2809,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
/* Tag all verts as untouched, then touch the ones that have a face center
* in the loop and select all MLoopUV's that use a touched vert. */
- BMVert *eve;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
- }
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2720,8 +2848,9 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l,
- select, cd_loop_uv_offset);
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l,
+ select, cd_loop_uv_offset);
}
}
}
@@ -2739,7 +2868,11 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
}
}
-/* ******************** border select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Border Select Operator
+ * \{ */
static int uv_border_select_exec(bContext *C, wmOperator *op)
{
@@ -2756,9 +2889,10 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
MLoopUV *luv;
rctf rectf;
bool changed, pinned, select, extend;
- const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE);
+ const bool use_face_center = (
+ (ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
@@ -2802,7 +2936,8 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
else {
/* other selection modes */
changed = true;
-
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
@@ -2814,15 +2949,21 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
/* UV_SYNC_SELECTION - can't do pinned selection */
if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
}
}
else if (pinned) {
if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
}
}
}
}
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
}
if (changed) {
@@ -2861,7 +3002,11 @@ static void UV_OT_select_border(wmOperatorType *ot)
WM_operator_properties_gesture_border_select(ot);
}
-/* ******************** circle select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Select Operator
+ * \{ */
static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
{
@@ -2872,19 +3017,6 @@ static int uv_inside_circle(const float uv[2], const float offset[2], const floa
return ((x * x + y * y) < 1.0f);
}
-static bool uv_select_inside_ellipse(BMEditMesh *em, Scene *scene, const bool select,
- const float offset[2], const float ellipse[2], BMLoop *l, MLoopUV *luv,
- const int cd_loop_uv_offset)
-{
- if (uv_inside_circle(luv->uv, offset, ellipse)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- return true;
- }
- else {
- return false;
- }
-}
-
static int uv_circle_select_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -2901,9 +3033,10 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
float zoomx, zoomy, offset[2], ellipse[2];
const bool select = !RNA_boolean_get(op->ptr, "deselect");
bool changed = false;
- const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE);
+ const bool use_face_center = (
+ (ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
@@ -2944,12 +3077,22 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
}
}
else {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- changed |= uv_select_inside_ellipse(em, scene, select, offset, ellipse, l, luv, cd_loop_uv_offset);
+ if (uv_inside_circle(luv->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
}
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
}
if (changed) {
@@ -2982,11 +3125,15 @@ static void UV_OT_circle_select(wmOperatorType *ot)
WM_operator_properties_gesture_circle_select(ot);
}
+/** \} */
-/* ******************** lasso select operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name Lasso Select Operator
+ * \{ */
-static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves,
- const bool select, const bool extend)
+static bool do_lasso_select_mesh_uv(
+ bContext *C, const int mcords[][2], short moves,
+ const bool select, const bool extend)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
@@ -3040,24 +3187,32 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
}
}
else { /* Vert Sel */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UI_view2d_view_to_region_clip(&ar->v2d,
- luv->uv[0], luv->uv[1],
- &screen_uv[0], &screen_uv[1]) &&
+ if (UI_view2d_view_to_region_clip(
+ &ar->v2d,
+ luv->uv[0], luv->uv[1],
+ &screen_uv[0], &screen_uv[1]) &&
BLI_rcti_isect_pt_v(&rect, screen_uv) &&
BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
{
uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
}
}
}
}
}
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
}
if (changed) {
@@ -3111,9 +3266,11 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
WM_operator_properties_gesture_lasso_select(ot);
}
+/** \} */
-
-/* ******************** snap cursor operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor Operator
+ * \{ */
static void uv_snap_to_pixel(float uvco[2], float w, float h)
{
@@ -3181,7 +3338,11 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
}
-/* ******************** snap selection operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection Operator
+ * \{ */
static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
{
@@ -3390,7 +3551,11 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
}
-/* ******************** pin operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pin UV's Operator
+ * \{ */
static int uv_pin_exec(bContext *C, wmOperator *op)
{
@@ -3445,7 +3610,11 @@ static void UV_OT_pin(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
}
-/******************* select pinned operator ***************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Pinned UV's Operator
+ * \{ */
static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3490,15 +3659,20 @@ static void UV_OT_select_pinned(wmOperatorType *ot)
ot->poll = ED_operator_uvedit;
}
-/********************** hide operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
/* check if we are selected or unselected based on 'bool_test' arg,
* needed for select swap support */
#define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
/* is every UV vert selected or unselected depending on bool_test */
-static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test,
- const int cd_loop_uv_offset)
+static bool bm_face_is_all_uv_sel(
+ BMFace *f, bool select_test,
+ const int cd_loop_uv_offset)
{
BMLoop *l_iter;
BMLoop *l_first;
@@ -3624,7 +3798,11 @@ static void UV_OT_hide(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
-/****************** reveal operator ******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reveal Operator
+ * \{ */
static int uv_reveal_exec(bContext *C, wmOperator *op)
{
@@ -3759,7 +3937,11 @@ static void UV_OT_reveal(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
-/******************** set 3d cursor operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set 2D Cursor Operator
+ * \{ */
static int uv_set_2d_cursor_poll(bContext *C)
{
@@ -3822,6 +4004,12 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
"Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Seam from UV Islands Operator
+ * \{ */
+
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
{
UvVertMap *vmap;
@@ -3956,6 +4144,12 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Seam Operator
+ * \{ */
+
static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
@@ -3966,17 +4160,14 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *loop;
BMIter iter, liter;
- bool clear = RNA_boolean_get(op->ptr, "clear");
+ bool flag_set = !RNA_boolean_get(op->ptr, "clear");
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- if (clear)
- BM_elem_flag_disable(loop->e, BM_ELEM_SEAM);
- else
- BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
+ BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
}
}
}
@@ -4031,8 +4222,11 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
}
+/** \} */
-/* ************************** registration **********************************/
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration & Keymap
+ * \{ */
void ED_operatortypes_uvedit(void)
{
@@ -4166,3 +4360,4 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE);
}
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 9cd34c46874..4c205818329 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -2127,16 +2127,16 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc
{
/* add uv under mouse to processed uv's */
float co[2];
- NearestHit hit;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
ARegion *ar = CTX_wm_region(C);
Image *ima = CTX_data_edit_image(C);
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
if (state->mode == STITCH_VERT) {
- uv_find_nearest_vert(scene, ima, state->obedit, state->em, co, NULL, &hit);
-
- if (hit.efa) {
+ if (uv_find_nearest_vert(
+ scene, ima, state->obedit, co, 0.0f, &hit))
+ {
/* Add vertex to selection, deselect all common uv's of vert other
* than selected and update the preview. This behavior was decided so that
* you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
@@ -2148,9 +2148,9 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc
}
}
else {
- uv_find_nearest_edge(scene, ima, state->obedit, state->em, co, &hit);
-
- if (hit.efa) {
+ if (uv_find_nearest_edge(
+ scene, ima, state->obedit, co, &hit))
+ {
UvEdge *edge = uv_edge_get(hit.l, state);
stitch_select_edge(edge, state, false);
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 977bca66731..62be648bba3 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -217,11 +217,11 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
}
// Make sure we don't have any bases which might reference freed objects.
- FOREACH_SCENE_COLLECTION(freestyle_scene, sc)
+ FOREACH_SCENE_COLLECTION_BEGIN(freestyle_scene, sc)
{
BLI_freelistN(&sc->objects);
}
- FOREACH_SCENE_COLLECTION_END
+ FOREACH_SCENE_COLLECTION_END;
BLI_freelistN(&view_layer->object_bases);
// release materials
@@ -966,7 +966,6 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render)
Render *freestyle_render = RE_NewSceneRender(freestyle_scene);
ViewLayer *view_layer = (ViewLayer *)freestyle_scene->view_layers.first;
DEG_graph_relations_update(freestyle_depsgraph, freestyle_bmain, freestyle_scene, view_layer);
- freestyle_render->depsgraph = freestyle_depsgraph;
RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene,
render && get_stroke_count() > 0);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 189ca8e6a33..5c0115d967a 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -150,6 +150,7 @@ data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC)
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index d2f3409dc07..fda24018150 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -32,6 +32,7 @@
#define __GPU_BATCH_H__
#include "../../../intern/gawain/gawain/gwn_batch.h"
+#include "../../../intern/gawain/gawain/gwn_batch_private.h"
struct rctf;
@@ -58,11 +59,14 @@ void gpu_batch_init(void);
void gpu_batch_exit(void);
/* gpu_batch_presets.c */
+/* Only use by draw manager. Use the presets function instead for interface. */
+Gwn_Batch *gpu_batch_sphere(int lat_res, int lon_res) ATTR_WARN_UNUSED_RESULT;
/* 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_reset(void);
void gpu_batch_presets_exit(void);
#endif /* __GPU_BATCH_H__ */
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index e2f40ff5c54..1d2b234e7f3 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -110,7 +110,8 @@ typedef enum GPUBuiltin {
GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
GPU_OBJECT_INFO = (1 << 15),
GPU_VOLUME_DENSITY = (1 << 16),
- GPU_VOLUME_FLAME = (1 << 17)
+ GPU_VOLUME_FLAME = (1 << 17),
+ GPU_VOLUME_TEMPERATURE = (1 << 18)
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -135,14 +136,19 @@ typedef enum GPUBlendMode {
typedef struct GPUNodeStack {
GPUType type;
- const char *name;
float vec[4];
struct GPUNodeLink *link;
bool hasinput;
bool hasoutput;
short sockettype;
+ bool end;
} GPUNodeStack;
+typedef enum GPUMaterialStatus {
+ GPU_MAT_FAILED = 0,
+ GPU_MAT_QUEUED,
+ GPU_MAT_SUCCESS,
+} GPUMaterialStatus;
#define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000)
@@ -244,9 +250,11 @@ GPUMaterial *GPU_material_from_nodetree_find(
struct ListBase *gpumaterials, const void *engine_type, int options);
GPUMaterial *GPU_material_from_nodetree(
struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options,
- const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines);
+ const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, bool deferred);
GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
+void GPU_material_generate_pass(
+ GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines);
void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
@@ -262,6 +270,8 @@ bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
GPUMatType GPU_Material_get_type(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
+struct ListBase *GPU_material_get_inputs(GPUMaterial *material);
+GPUMaterialStatus GPU_material_status(GPUMaterial *mat);
struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material);
void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs);
@@ -368,6 +378,9 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
struct DerivedMesh *dm);
#endif
+void GPU_pass_cache_garbage_collect(void);
+void GPU_pass_cache_free(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 0617d58f3b6..f1342a1f6b8 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -47,6 +47,7 @@ enum {
void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
bool GPU_select_load_id(unsigned int id);
+void GPU_select_finalize(void);
unsigned int GPU_select_end(void);
bool GPU_select_query_check_active(void);
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index ca6e8343401..def0b0bfbc7 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -134,6 +134,7 @@ typedef enum GPUBuiltinShader {
GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR,
GPU_SHADER_3D_IMAGE_MODULATE_ALPHA,
GPU_SHADER_3D_IMAGE_DEPTH,
+ GPU_SHADER_3D_IMAGE_DEPTH_COPY,
/* stereo 3d */
GPU_SHADER_2D_IMAGE_INTERLACE,
/* points */
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 1b64d66469b..0fde0edcf2b 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -70,6 +70,7 @@ typedef enum GPUTextureFormat {
GPU_RG16I,
GPU_R32F,
GPU_R16F,
+ GPU_R16I,
GPU_RG8,
GPU_R8,
#if 0
@@ -88,7 +89,6 @@ typedef enum GPUTextureFormat {
GPU_RG8UI,
GPU_R32I,
GPU_R32UI,
- GPU_R16I,
GPU_R16UI,
GPU_R16,
GPU_R8I,
@@ -197,6 +197,7 @@ int GPU_texture_target(const GPUTexture *tex);
int GPU_texture_width(const GPUTexture *tex);
int GPU_texture_height(const GPUTexture *tex);
int GPU_texture_format(const GPUTexture *tex);
+int GPU_texture_samples(const GPUTexture *tex);
bool GPU_texture_depth(const GPUTexture *tex);
bool GPU_texture_stencil(const GPUTexture *tex);
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index dff7e278ae1..20d468459e6 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -46,7 +46,7 @@ typedef struct GPUViewport GPUViewport;
/* Contains memory pools informations */
typedef struct ViewportMemoryPool {
struct BLI_mempool *calls;
- struct BLI_mempool *calls_generate;
+ struct BLI_mempool *states;
struct BLI_mempool *shgroups;
struct BLI_mempool *uniforms;
struct BLI_mempool *passes;
@@ -83,7 +83,6 @@ typedef struct ViewportEngineData {
/* Profiling data */
double init_time;
- double cache_time;
double render_time;
double background_time;
} ViewportEngineData;
@@ -114,6 +113,9 @@ void *GPU_viewport_texture_list_get(GPUViewport *viewport);
void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]);
void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]);
+/* Profiling */
+double *GPU_viewport_cache_time_get(GPUViewport *viewport);
+
void GPU_viewport_tag_update(GPUViewport *viewport);
bool GPU_viewport_do_update(GPUViewport *viewport);
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index 9db04832a51..696143a3857 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_threads.h"
#include "GPU_batch.h"
#include "gpu_shader_private.h"
@@ -50,7 +51,7 @@ static struct {
struct {
uint pos, nor;
} attr_id;
-} g_presets_3d = {0};
+} g_presets_3d = {{0}};
/* We may want 2D presets later. */
@@ -71,7 +72,7 @@ static void batch_sphere_lat_lon_vert(
}
/* Replacement for gluSphere */
-static Gwn_Batch *batch_sphere(int lat_res, int lon_res)
+Gwn_Batch *gpu_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;
@@ -146,6 +147,7 @@ static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res)
Gwn_Batch *GPU_batch_preset_sphere(int lod)
{
BLI_assert(lod >= 0 && lod <= 2);
+ BLI_assert(BLI_thread_is_main());
if (lod == 0) {
return g_presets_3d.batch.sphere_low;
@@ -161,6 +163,7 @@ Gwn_Batch *GPU_batch_preset_sphere(int lod)
Gwn_Batch *GPU_batch_preset_sphere_wire(int lod)
{
BLI_assert(lod >= 0 && lod <= 1);
+ BLI_assert(BLI_thread_is_main());
if (lod == 0) {
return g_presets_3d.batch.sphere_wire_low;
@@ -182,14 +185,25 @@ void gpu_batch_presets_init(void)
}
/* 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_low = gpu_batch_sphere(8, 16);
+ g_presets_3d.batch.sphere_med = gpu_batch_sphere(16, 10);
+ g_presets_3d.batch.sphere_high = gpu_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_reset(void)
+{
+ /* Reset vao caches for these every time we switch opengl context.
+ * This way they will draw correctly for each window. */
+ gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_low);
+ gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_med);
+ gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_high);
+ gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_wire_low);
+ gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_wire_med);
+}
+
void gpu_batch_presets_exit(void)
{
GWN_batch_discard(g_presets_3d.batch.sphere_low);
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 9e4daa2a036..7cd403d2721 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -39,10 +39,14 @@
#include "DNA_node_types.h"
#include "BLI_blenlib.h"
+#include "BLI_hash_mm2a.h"
+#include "BLI_linklist.h"
#include "BLI_utildefines.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
+#include "PIL_time.h"
+
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_material.h"
@@ -64,6 +68,50 @@ extern char datatoc_gpu_shader_geometry_glsl[];
static char *glsl_material_library = NULL;
+/* -------------------- GPUPass Cache ------------------ */
+/**
+ * Internal shader cache: This prevent the shader recompilation / stall when
+ * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
+ * same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
+ **/
+
+static LinkNode *pass_cache = NULL; /* GPUPass */
+
+static uint32_t gpu_pass_hash(const char *vert, const char *geom, const char *frag, const char *defs)
+{
+ BLI_HashMurmur2A hm2a;
+ BLI_hash_mm2a_init(&hm2a, 0);
+ BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag, strlen(frag));
+ BLI_hash_mm2a_add(&hm2a, (unsigned char *)vert, strlen(vert));
+ if (defs)
+ BLI_hash_mm2a_add(&hm2a, (unsigned char *)defs, strlen(defs));
+ if (geom)
+ BLI_hash_mm2a_add(&hm2a, (unsigned char *)geom, strlen(geom));
+
+ return BLI_hash_mm2a_end(&hm2a);
+}
+
+/* Search by hash then by exact string match. */
+static GPUPass *gpu_pass_cache_lookup(
+ const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash)
+{
+ for (LinkNode *ln = pass_cache; ln; ln = ln->next) {
+ GPUPass *pass = (GPUPass *)ln->link;
+ if (pass->hash == hash) {
+ /* Note: Could be made faster if that becomes a real bottleneck. */
+ if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ }
+ else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ }
+ else if ((strcmp(pass->fragmentcode, frag) == 0) &&
+ (strcmp(pass->vertexcode, vert) == 0))
+ {
+ return pass;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* -------------------- GPU Codegen ------------------ */
/* type definitions and constants */
@@ -427,6 +475,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "sampdensity";
else if (builtin == GPU_VOLUME_FLAME)
return "sampflame";
+ else if (builtin == GPU_VOLUME_TEMPERATURE)
+ return "unftemperature";
else
return "";
}
@@ -1173,15 +1223,13 @@ GPUShader *GPU_pass_shader(GPUPass *pass)
return pass->shader;
}
-static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes)
+static void gpu_nodes_extract_dynamic_inputs_new(GPUShader *shader, ListBase *inputs, ListBase *nodes)
{
- GPUShader *shader = pass->shader;
GPUNode *node;
GPUInput *next, *input;
- ListBase *inputs = &pass->inputs;
int extract, z;
- memset(inputs, 0, sizeof(*inputs));
+ BLI_listbase_clear(inputs);
if (!shader)
return;
@@ -1234,15 +1282,13 @@ static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes)
GPU_shader_unbind();
}
-static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
+static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes)
{
- GPUShader *shader = pass->shader;
GPUNode *node;
GPUInput *next, *input;
- ListBase *inputs = &pass->inputs;
int extract, z;
- memset(inputs, 0, sizeof(*inputs));
+ BLI_listbase_clear(inputs);
if (!shader)
return;
@@ -1320,11 +1366,10 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
GPU_shader_unbind();
}
-void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
+void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap)
{
GPUInput *input;
GPUShader *shader = pass->shader;
- ListBase *inputs = &pass->inputs;
if (!shader)
return;
@@ -1349,11 +1394,10 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
}
}
-void GPU_pass_update_uniforms(GPUPass *pass)
+void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs)
{
GPUInput *input;
GPUShader *shader = pass->shader;
- ListBase *inputs = &pass->inputs;
if (!shader)
return;
@@ -1374,11 +1418,10 @@ void GPU_pass_update_uniforms(GPUPass *pass)
}
}
-void GPU_pass_unbind(GPUPass *pass)
+void GPU_pass_unbind(GPUPass *pass, ListBase *inputs)
{
GPUInput *input;
GPUShader *shader = pass->shader;
- ListBase *inputs = &pass->inputs;
if (!shader)
return;
@@ -1677,7 +1720,7 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin
BLI_addtail(&node->outputs, output);
}
-static void gpu_inputs_free(ListBase *inputs)
+void GPU_inputs_free(ListBase *inputs)
{
GPUInput *input;
@@ -1695,7 +1738,7 @@ static void gpu_node_free(GPUNode *node)
{
GPUOutput *output;
- gpu_inputs_free(&node->inputs);
+ GPU_inputs_free(&node->inputs);
for (output = node->outputs.first; output; output = output->next)
if (output->link) {
@@ -1718,7 +1761,7 @@ static void gpu_nodes_free(ListBase *nodes)
/* vertex attributes */
-static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs)
+void GPU_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs)
{
GPUNode *node;
GPUInput *input;
@@ -1958,16 +2001,20 @@ bool GPU_stack_link(GPUMaterial *material, bNode *bnode, const char *name, GPUNo
totout = 0;
if (in) {
- for (i = 0; in[i].type != GPU_NONE; i++) {
- gpu_node_input_socket(material, bnode, node, &in[i], i);
- totin++;
+ for (i = 0; !in[i].end; i++) {
+ if (in[i].type != GPU_NONE) {
+ gpu_node_input_socket(material, bnode, node, &in[i], i);
+ totin++;
+ }
}
}
if (out) {
- for (i = 0; out[i].type != GPU_NONE; i++) {
- gpu_node_output(node, out[i].type, &out[i].link);
- totout++;
+ for (i = 0; !out[i].end; i++) {
+ if (out[i].type != GPU_NONE) {
+ gpu_node_output(node, out[i].type, &out[i].link);
+ totout++;
+ }
}
}
@@ -2046,7 +2093,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
gpu_nodes_tag(input->link);
}
-static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
+void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
{
GPUNode *node, *next;
@@ -2066,79 +2113,83 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
}
GPUPass *GPU_generate_pass_new(
- struct GPUMaterial *material,
- ListBase *nodes, struct GPUNodeLink *frag_outlink,
- GPUVertexAttribs *attribs,
+ GPUMaterial *material,
+ GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs,
+ ListBase *nodes, ListBase *inputs,
const char *vert_code, const char *geom_code,
const char *frag_lib, const char *defines)
{
+ char *vertexcode, *geometrycode, *fragmentcode;
GPUShader *shader;
GPUPass *pass;
- char *vertexgen, *fragmentgen, *tmp;
- char *vertexcode, *geometrycode, *fragmentcode;
/* prune unused nodes */
- gpu_nodes_prune(nodes, frag_outlink);
+ GPU_nodes_prune(nodes, frag_outlink);
- gpu_nodes_get_vertex_attributes(nodes, attribs);
+ GPU_nodes_get_vertex_attributes(nodes, attribs);
- /* generate code and compile with opengl */
- fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true);
- vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL));
+ /* generate code */
+ char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true);
+ char *tmp = BLI_strdupcat(frag_lib, glsl_material_library);
- tmp = BLI_strdupcat(frag_lib, glsl_material_library);
+ vertexcode = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL));
+ geometrycode = (geom_code) ? code_generate_geometry_new(nodes, geom_code) : NULL;
fragmentcode = BLI_strdupcat(tmp, fragmentgen);
- vertexcode = BLI_strdup(vertexgen);
-
- if (geom_code) {
- geometrycode = code_generate_geometry_new(nodes, geom_code);
- }
- else {
- geometrycode = NULL;
- }
-
- shader = GPU_shader_create(vertexcode,
- fragmentcode,
- geometrycode,
- NULL,
- defines);
+ MEM_freeN(fragmentgen);
MEM_freeN(tmp);
- /* failed? */
+ /* Cache lookup: Reuse shaders already compiled */
+ uint32_t hash = gpu_pass_hash(vertexcode, geometrycode, fragmentcode, defines);
+ pass = gpu_pass_cache_lookup(vertexcode, geometrycode, fragmentcode, defines, hash);
+ if (pass) {
+ /* Cache hit. Reuse the same GPUPass and GPUShader. */
+ shader = pass->shader;
+ pass->refcount += 1;
+
+ MEM_SAFE_FREE(vertexcode);
+ MEM_SAFE_FREE(fragmentcode);
+ MEM_SAFE_FREE(geometrycode);
+ }
+ else {
+ /* Cache miss. (Re)compile the shader. */
+ shader = GPU_shader_create(vertexcode,
+ fragmentcode,
+ geometrycode,
+ NULL,
+ defines);
+
+ /* We still create a pass even if shader compilation
+ * fails to avoid trying to compile again and again. */
+ pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
+ pass->shader = shader;
+ pass->refcount = 1;
+ pass->hash = hash;
+ pass->vertexcode = vertexcode;
+ pass->fragmentcode = fragmentcode;
+ pass->geometrycode = geometrycode;
+ pass->libcode = glsl_material_library;
+ pass->defines = (defines) ? BLI_strdup(defines) : NULL;
+
+ BLI_linklist_prepend(&pass_cache, pass);
+ }
+
+ /* did compilation failed ? */
if (!shader) {
- if (fragmentcode)
- MEM_freeN(fragmentcode);
- if (vertexcode)
- MEM_freeN(vertexcode);
- if (geometrycode)
- MEM_freeN(geometrycode);
- MEM_freeN(fragmentgen);
- MEM_freeN(vertexgen);
gpu_nodes_free(nodes);
+ /* Pass will not be used. Don't increment refcount. */
+ pass->refcount--;
return NULL;
}
-
- /* create pass */
- pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
- pass->shader = shader;
- pass->fragmentcode = fragmentcode;
- pass->geometrycode = geometrycode;
- pass->vertexcode = vertexcode;
- pass->libcode = glsl_material_library;
-
- /* extract dynamic inputs and throw away nodes */
- gpu_nodes_extract_dynamic_inputs_new(pass, nodes);
- gpu_nodes_free(nodes);
-
- MEM_freeN(fragmentgen);
- MEM_freeN(vertexgen);
-
- return pass;
+ else {
+ gpu_nodes_extract_dynamic_inputs_new(shader, inputs, nodes);
+ return pass;
+ }
}
+/* TODO(fclem) Remove for 2.8 */
GPUPass *GPU_generate_pass(
- ListBase *nodes, GPUNodeLink *outlink,
+ ListBase *nodes, ListBase *inputs, GPUNodeLink *outlink,
GPUVertexAttribs *attribs, int *builtins,
const GPUMatType type, const char *UNUSED(name),
const bool use_opensubdiv,
@@ -2156,9 +2207,9 @@ GPUPass *GPU_generate_pass(
#endif
/* prune unused nodes */
- gpu_nodes_prune(nodes, outlink);
+ GPU_nodes_prune(nodes, outlink);
- gpu_nodes_get_vertex_attributes(nodes, attribs);
+ GPU_nodes_get_vertex_attributes(nodes, attribs);
gpu_nodes_get_builtin_flag(nodes, builtins);
/* generate code and compile with opengl */
@@ -2194,30 +2245,36 @@ GPUPass *GPU_generate_pass(
/* create pass */
pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
-
+ pass->refcount = 1;
pass->shader = shader;
pass->fragmentcode = fragmentcode;
pass->geometrycode = geometrycode;
pass->vertexcode = vertexcode;
pass->libcode = glsl_material_library;
+ BLI_linklist_prepend(&pass_cache, pass);
+
/* extract dynamic inputs and throw away nodes */
- gpu_nodes_extract_dynamic_inputs(pass, nodes);
+ gpu_nodes_extract_dynamic_inputs(shader, inputs, nodes);
gpu_nodes_free(nodes);
return pass;
}
-void GPU_pass_free(GPUPass *pass)
+void GPU_pass_release(GPUPass *pass)
+{
+ BLI_assert(pass->refcount > 0);
+ pass->refcount--;
+}
+
+static void gpu_pass_free(GPUPass *pass)
{
+ BLI_assert(pass->refcount == 0);
GPU_shader_free(pass->shader);
- gpu_inputs_free(&pass->inputs);
- if (pass->fragmentcode)
- MEM_freeN(pass->fragmentcode);
- if (pass->geometrycode)
- MEM_freeN(pass->geometrycode);
- if (pass->vertexcode)
- MEM_freeN(pass->vertexcode);
+ MEM_SAFE_FREE(pass->fragmentcode);
+ MEM_SAFE_FREE(pass->geometrycode);
+ MEM_SAFE_FREE(pass->vertexcode);
+ MEM_SAFE_FREE(pass->defines);
MEM_freeN(pass);
}
@@ -2226,3 +2283,34 @@ void GPU_pass_free_nodes(ListBase *nodes)
gpu_nodes_free(nodes);
}
+void GPU_pass_cache_garbage_collect(void)
+{
+ static int lasttime = 0;
+ const int shadercollectrate = 60; /* hardcoded for now. */
+ int ctime = (int)PIL_check_seconds_timer();
+
+ if (ctime < shadercollectrate + lasttime)
+ return;
+
+ lasttime = ctime;
+
+ LinkNode *next, **prev_ln = &pass_cache;
+ for (LinkNode *ln = pass_cache; ln; ln = next) {
+ GPUPass *pass = (GPUPass *)ln->link;
+ next = ln->next;
+ if (pass->refcount == 0) {
+ gpu_pass_free(pass);
+ /* Remove from list */
+ MEM_freeN(ln);
+ *prev_ln = next;
+ }
+ else {
+ prev_ln = &ln->next;
+ }
+ }
+}
+
+void GPU_pass_cache_free(void)
+{
+ BLI_linklist_free(pass_cache, (LinkNodeFreeFP)gpu_pass_free);
+}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 14e07a6e012..dab0bc3f8b1 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -157,25 +157,27 @@ typedef struct GPUInput {
} GPUInput;
struct GPUPass {
- ListBase inputs;
struct GPUShader *shader;
char *fragmentcode;
char *geometrycode;
char *vertexcode;
+ char *defines;
const char *libcode;
+ unsigned int refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */
+ uint32_t hash; /* Identity hash generated from all GLSL code. */
};
typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass_new(
- struct GPUMaterial *material,
- ListBase *nodes, struct GPUNodeLink *frag_outlink,
- struct GPUVertexAttribs *attribs,
+ GPUMaterial *material,
+ GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs,
+ ListBase *nodes, ListBase *inputs,
const char *vert_code, const char *geom_code,
const char *frag_lib, const char *defines);
GPUPass *GPU_generate_pass(
- ListBase *nodes, struct GPUNodeLink *outlink,
+ ListBase *nodes, ListBase *inputs, struct GPUNodeLink *outlink,
struct GPUVertexAttribs *attribs, int *builtin,
const GPUMatType type, const char *name,
const bool use_opensubdiv,
@@ -183,13 +185,18 @@ GPUPass *GPU_generate_pass(
struct GPUShader *GPU_pass_shader(GPUPass *pass);
-void GPU_pass_bind(GPUPass *pass, double time, int mipmap);
-void GPU_pass_update_uniforms(GPUPass *pass);
-void GPU_pass_unbind(GPUPass *pass);
+void GPU_nodes_get_vertex_attributes(ListBase *nodes, struct GPUVertexAttribs *attribs);
+void GPU_nodes_prune(ListBase *nodes, struct GPUNodeLink *outlink);
+
+void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap);
+void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs);
+void GPU_pass_unbind(GPUPass *pass, ListBase *inputs);
-void GPU_pass_free(GPUPass *pass);
+void GPU_pass_release(GPUPass *pass);
void GPU_pass_free_nodes(ListBase *nodes);
+void GPU_inputs_free(ListBase *inputs);
+
void gpu_codegen_init(void);
void gpu_codegen_exit(void);
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 6bf330179d3..73e86c1b391 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -149,7 +149,7 @@ void gpu_extensions_init(void)
else
GG.max_anisotropy = 1.0f;
- glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &GG.maxubobinds);
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize);
#ifndef NDEBUG
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 2d7b9415030..a408a41513a 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -68,6 +68,8 @@
#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
+#include "DRW_engine.h"
+
#include "gpu_codegen.h"
#include "gpu_lamp_private.h"
@@ -103,6 +105,7 @@ struct GPUMaterial {
/* material for mesh surface, worlds or something else.
* some code generation is done differently depending on the use case */
int type; /* DEPRECATED */
+ GPUMaterialStatus status;
const void *engine_type; /* attached engine type */
int options; /* to identify shader variations (shadow, probe, world background...) */
@@ -113,6 +116,7 @@ struct GPUMaterial {
/* for binding the material */
GPUPass *pass;
+ ListBase inputs; /* GPUInput */
GPUVertexAttribs attribs;
int builtins;
int alpha, obcolalpha;
@@ -142,7 +146,10 @@ struct GPUMaterial {
*/
int domain;
+ /* Used by 2.8 pipeline */
GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
+
+ /* Eevee SSS */
GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
float *sss_radii; /* UBO containing SSS profile. */
@@ -215,12 +222,14 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam
{
if (material->outlink) {
GPUNodeLink *outlink = material->outlink;
- material->pass = GPU_generate_pass(&material->nodes, outlink,
+ material->pass = GPU_generate_pass(&material->nodes, &material->inputs, outlink,
&material->attribs, &material->builtins, material->type,
passname,
material->is_opensubdiv,
GPU_material_use_new_shading_nodes(material));
+ material->status = (material->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED;
+
if (!material->pass)
return 0;
@@ -270,8 +279,14 @@ void GPU_material_free(ListBase *gpumaterial)
for (LinkData *link = gpumaterial->first; link; link = link->next) {
GPUMaterial *material = link->data;
+ /* Cancel / wait any pending lazy compilation. */
+ DRW_deferred_shader_remove(material);
+
+ GPU_pass_free_nodes(&material->nodes);
+ GPU_inputs_free(&material->inputs);
+
if (material->pass)
- GPU_pass_free(material->pass);
+ GPU_pass_release(material->pass);
if (material->ubo != NULL) {
GPU_uniformbuffer_free(material->ubo);
@@ -343,7 +358,7 @@ void GPU_material_bind(
}
/* note material must be bound before setting uniforms */
- GPU_pass_bind(material->pass, time, mipmap);
+ GPU_pass_bind(material->pass, &material->inputs, time, mipmap);
/* handle per material built-ins */
if (material->builtins & GPU_VIEW_MATRIX) {
@@ -363,7 +378,7 @@ void GPU_material_bind(
}
}
- GPU_pass_update_uniforms(material->pass);
+ GPU_pass_update_uniforms(material->pass, &material->inputs);
material->bound = 1;
}
@@ -436,7 +451,7 @@ void GPU_material_unbind(GPUMaterial *material)
{
if (material->pass) {
material->bound = 0;
- GPU_pass_unbind(material->pass);
+ GPU_pass_unbind(material->pass, &material->inputs);
}
}
@@ -460,6 +475,11 @@ GPUPass *GPU_material_get_pass(GPUMaterial *material)
return material->pass;
}
+ListBase *GPU_material_get_inputs(GPUMaterial *material)
+{
+ return &material->inputs;
+}
+
GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material)
{
return material->ubo;
@@ -829,6 +849,12 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
BLI_addtail(&material->nodes, node);
}
+/* Return true if the material compilation has not yet begin or begin. */
+GPUMaterialStatus GPU_material_status(GPUMaterial *mat)
+{
+ return mat->status;
+}
+
/* Code generation */
bool GPU_material_do_color_management(GPUMaterial *mat)
@@ -2490,10 +2516,8 @@ GPUMaterial *GPU_material_from_nodetree_find(
*/
GPUMaterial *GPU_material_from_nodetree(
Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
- const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
+ const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, bool deferred)
{
- GPUMaterial *mat;
- GPUNodeLink *outlink;
LinkData *link;
bool has_volume_output, has_surface_output;
@@ -2501,7 +2525,7 @@ GPUMaterial *GPU_material_from_nodetree(
BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
/* allocate material */
- mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */
+ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");;
mat->scene = scene;
mat->engine_type = engine_type;
mat->options = options;
@@ -2516,11 +2540,15 @@ GPUMaterial *GPU_material_from_nodetree(
mat->domain |= GPU_DOMAIN_VOLUME;
}
- /* Let Draw manager finish the construction. */
- if (mat->outlink) {
- outlink = mat->outlink;
- mat->pass = GPU_generate_pass_new(
- mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines);
+ if (!deferred) {
+ GPU_material_generate_pass(mat, vert_code, geom_code, frag_lib, defines);
+ }
+ else if (mat->outlink) {
+ /* Prune the unused nodes and extract attribs before compiling so the
+ * generated VBOs are ready to accept the future shader. */
+ GPU_nodes_prune(&mat->nodes, mat->outlink);
+ GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs);
+ mat->status = GPU_MAT_QUEUED;
}
/* note that even if building the shader fails in some way, we still keep
@@ -2534,6 +2562,21 @@ GPUMaterial *GPU_material_from_nodetree(
return mat;
}
+/* Calls this function if /a mat was created with deferred compilation. */
+void GPU_material_generate_pass(
+ GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
+{
+ BLI_assert(mat->pass == NULL); /* Only run once! */
+ if (mat->outlink) {
+ mat->pass = GPU_generate_pass_new(
+ mat, mat->outlink, &mat->attribs, &mat->nodes, &mat->inputs, vert_code, geom_code, frag_lib, defines);
+ mat->status = (mat->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED;
+ }
+ else {
+ mat->status = GPU_MAT_FAILED;
+ }
+}
+
GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
{
GPUMaterial *mat;
@@ -2696,7 +2739,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
if (pass && pass->fragmentcode && pass->vertexcode) {
shader = MEM_callocN(sizeof(GPUShaderExport), "GPUShaderExport");
- for (input = pass->inputs.first; input; input = input->next) {
+ for (input = mat->inputs.first; input; input = input->next) {
GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
if (input->ima) {
@@ -2873,7 +2916,7 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
{
GPUPass *pass = gpu_material->pass;
GPUShader *shader = (pass != NULL ? pass->shader : NULL);
- ListBase *inputs = (pass != NULL ? &pass->inputs : NULL);
+ ListBase *inputs = (pass != NULL ? &gpu_material->inputs : NULL);
GPUInput *input;
if (shader == NULL) {
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 153cf5f1e97..7023e44d289 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -73,7 +73,7 @@ static GPUSelectState g_select_state = {0};
/**
* initialize and provide buffer for results
*/
-void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *input, char mode, int oldhits)
+void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
{
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
/* In the case hits was '-1', don't start the second pass since it's not going to give useful results.
@@ -108,12 +108,12 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *in
case ALGO_GL_QUERY:
{
g_select_state.use_cache = false;
- gpu_select_query_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode, oldhits);
+ gpu_select_query_begin((uint (*)[4])buffer, bufsize / 4, input, mode, oldhits);
break;
}
default: /* ALGO_GL_PICK */
{
- gpu_select_pick_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode);
+ gpu_select_pick_begin((uint (*)[4])buffer, bufsize / 4, input, mode);
break;
}
}
@@ -126,7 +126,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *in
*
* \warning We rely on the order of object rendering on passes to be the same for this to work.
*/
-bool GPU_select_load_id(unsigned int id)
+bool GPU_select_load_id(uint id)
{
/* if no selection mode active, ignore */
if (!g_select_state.select_is_active)
@@ -154,9 +154,9 @@ bool GPU_select_load_id(unsigned int id)
* Return number of hits and hits in buffer.
* if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
*/
-unsigned int GPU_select_end(void)
+uint GPU_select_end(void)
{
- unsigned int hits = 0;
+ uint hits = 0;
switch (g_select_state.algorithm) {
case ALGO_GL_LEGACY:
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index f1d311890e6..4aef80934ad 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -62,14 +62,14 @@
/* For looping over a sub-region of a rect, could be moved into 'rct.c'*/
typedef struct SubRectStride {
- unsigned int start; /* start here */
- unsigned int span; /* read these */
- unsigned int span_len; /* len times (read span 'len' times). */
- unsigned int skip; /* skip those */
+ uint start; /* start here */
+ uint span; /* read these */
+ uint span_len; /* len times (read span 'len' times). */
+ uint skip; /* skip those */
} SubRectStride;
/* we may want to change back to float if uint isn't well supported */
-typedef unsigned int depth_t;
+typedef uint depth_t;
/**
* Calculate values needed for looping over a sub-region (smaller buffer within a larger buffer).
@@ -89,10 +89,10 @@ static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRect
src->ymax >= dst->ymax && src->ymax >= dst->ymax);
BLI_assert(x >= 0 && y >= 0);
- r_sub->start = (unsigned int)((src_x * y) + x);
- r_sub->span = (unsigned int)dst_x;
- r_sub->span_len = (unsigned int)dst_y;
- r_sub->skip = (unsigned int)(src_x - dst_x);
+ r_sub->start = (uint)((src_x * y) + x);
+ r_sub->span = (uint)dst_x;
+ r_sub->span_len = (uint)dst_y;
+ r_sub->skip = (uint)(src_x - dst_x);
}
/**
@@ -114,11 +114,11 @@ BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
/* store result of glReadPixels */
typedef struct DepthBufCache {
struct DepthBufCache *next, *prev;
- unsigned int id;
+ uint id;
depth_t buf[0];
} DepthBufCache;
-static DepthBufCache *depth_buf_malloc(unsigned int rect_len)
+static DepthBufCache *depth_buf_malloc(uint rect_len)
{
DepthBufCache *rect = MEM_mallocN(sizeof(DepthBufCache) + sizeof(depth_t) * rect_len, __func__);
rect->id = SELECT_ID_NONE;
@@ -127,10 +127,10 @@ static DepthBufCache *depth_buf_malloc(unsigned int rect_len)
static bool depth_buf_rect_depth_any(
const DepthBufCache *rect_depth,
- unsigned int rect_len)
+ uint rect_len)
{
const depth_t *curr = rect_depth->buf;
- for (unsigned int i = 0; i < rect_len; i++, curr++) {
+ for (uint i = 0; i < rect_len; i++, curr++) {
if (*curr != DEPTH_MAX) {
return true;
}
@@ -143,7 +143,7 @@ static bool depth_buf_subrect_depth_any(
const SubRectStride *sub_rect)
{
const depth_t *curr = rect_depth->buf + sub_rect->start;
- for (unsigned int i = 0; i < sub_rect->span_len; i++) {
+ for (uint i = 0; i < sub_rect->span_len; i++) {
const depth_t *curr_end = curr + sub_rect->span;
for (; curr < curr_end; curr++, curr++) {
if (*curr != DEPTH_MAX) {
@@ -157,14 +157,14 @@ static bool depth_buf_subrect_depth_any(
static bool depth_buf_rect_depth_any_filled(
const DepthBufCache *rect_prev, const DepthBufCache *rect_curr,
- unsigned int rect_len)
+ uint rect_len)
{
#if 0
return memcmp(rect_depth_a->buf, rect_depth_b->buf, rect_len * sizeof(depth_t)) != 0;
#else
const depth_t *prev = rect_prev->buf;
const depth_t *curr = rect_curr->buf;
- for (unsigned int i = 0; i < rect_len; i++, curr++, prev++) {
+ for (uint i = 0; i < rect_len; i++, curr++, prev++) {
if (depth_is_filled(prev, curr)) {
return true;
}
@@ -183,7 +183,7 @@ static bool depth_buf_subrect_depth_any_filled(
/* same as above but different rect sizes */
const depth_t *prev = rect_src->buf + sub_rect->start;
const depth_t *curr = rect_dst->buf + sub_rect->start;
- for (unsigned int i = 0; i < sub_rect->span_len; i++) {
+ for (uint i = 0; i < sub_rect->span_len; i++) {
const depth_t *curr_end = curr + sub_rect->span;
for (; curr < curr_end; prev++, curr++) {
if (depth_is_filled(prev, curr)) {
@@ -203,7 +203,7 @@ static bool depth_buf_subrect_depth_any_filled(
*/
typedef struct DepthID {
- unsigned int id;
+ uint id;
depth_t depth;
} DepthID;
@@ -238,10 +238,10 @@ static int depth_cmp(const void *v1, const void *v2)
/* depth sorting */
typedef struct GPUPickState {
/* cache on initialization */
- unsigned int (*buffer)[4];
+ uint (*buffer)[4];
/* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
- unsigned int bufsize;
+ uint bufsize;
/* mode of operation */
char mode;
@@ -257,14 +257,14 @@ typedef struct GPUPickState {
/* Set after first draw */
bool is_init;
- unsigned int prev_id;
+ uint prev_id;
} gl;
/* src: data stored in 'cache' and 'gl',
* dst: use when cached region is smaller (where src -> dst isn't 1:1) */
struct {
rcti clip_rect;
- unsigned int rect_len;
+ uint rect_len;
} src, dst;
/* Store cache between `GPU_select_cache_begin/end` */
@@ -284,13 +284,13 @@ typedef struct GPUPickState {
/* GPU_SELECT_PICK_ALL */
struct {
DepthID *hits;
- unsigned int hits_len;
- unsigned int hits_len_alloc;
+ uint hits_len;
+ uint hits_len_alloc;
} all;
/* GPU_SELECT_PICK_NEAREST */
struct {
- unsigned int *rect_id;
+ uint *rect_id;
} nearest;
};
} GPUPickState;
@@ -299,7 +299,7 @@ typedef struct GPUPickState {
static GPUPickState g_pick_state = {0};
void gpu_select_pick_begin(
- unsigned int (*buffer)[4], unsigned int bufsize,
+ uint (*buffer)[4], uint bufsize,
const rcti *input, char mode)
{
GPUPickState *ps = &g_pick_state;
@@ -312,7 +312,7 @@ void gpu_select_pick_begin(
ps->buffer = buffer;
ps->mode = mode;
- const unsigned int rect_len = (unsigned int)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
+ const uint rect_len = (uint)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
ps->dst.clip_rect = *input;
ps->dst.rect_len = rect_len;
@@ -327,6 +327,9 @@ void gpu_select_pick_begin(
glDepthMask(GL_TRUE);
if (mode == GPU_SELECT_PICK_ALL) {
+ /* Note that other depth settings (such as #GL_LEQUAL) work too,
+ * since the depth is always cleared.
+ * Noting this for cases when depth picking is used where drawing calls change depth settings. */
glDepthFunc(GL_ALWAYS);
}
else {
@@ -358,7 +361,7 @@ void gpu_select_pick_begin(
#if 0
glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth->buf);
#else
- for (unsigned int i = 0; i < rect_len; i++) {
+ for (uint i = 0; i < rect_len; i++) {
ps->gl.rect_depth->buf[i] = DEPTH_MAX;
}
#endif
@@ -381,8 +384,8 @@ void gpu_select_pick_begin(
}
else {
/* Set to 0xff for SELECT_ID_NONE */
- ps->nearest.rect_id = MEM_mallocN(sizeof(unsigned int) * ps->dst.rect_len, __func__);
- memset(ps->nearest.rect_id, 0xff, sizeof(unsigned int) * ps->dst.rect_len);
+ ps->nearest.rect_id = MEM_mallocN(sizeof(uint) * ps->dst.rect_len, __func__);
+ memset(ps->nearest.rect_id, 0xff, sizeof(uint) * ps->dst.rect_len);
}
}
@@ -393,7 +396,7 @@ void gpu_select_pick_begin(
static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
{
GPUPickState *ps = &g_pick_state;
- const unsigned int id = rect_curr->id;
+ const uint id = rect_curr->id;
/* find the best depth for this pass and store in 'all.hits' */
depth_t depth_best = DEPTH_MAX;
@@ -405,15 +408,15 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
if (ps->is_cached == false) {
const depth_t *curr = rect_curr->buf;
BLI_assert(ps->src.rect_len == ps->dst.rect_len);
- const unsigned int rect_len = ps->src.rect_len;
- for (unsigned int i = 0; i < rect_len; i++, curr++) {
+ const uint rect_len = ps->src.rect_len;
+ for (uint i = 0; i < rect_len; i++, curr++) {
EVAL_TEST();
}
}
else {
/* same as above but different rect sizes */
const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
- for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) {
+ for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) {
const depth_t *curr_end = curr + ps->cache.sub_rect.span;
for (; curr < curr_end; curr++) {
EVAL_TEST();
@@ -437,10 +440,10 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, const DepthBufCache *rect_curr)
{
GPUPickState *ps = &g_pick_state;
- const unsigned int id = rect_curr->id;
+ const uint id = rect_curr->id;
/* keep track each pixels ID in 'nearest.rect_id' */
if (id != SELECT_ID_NONE) {
- unsigned int *id_ptr = ps->nearest.rect_id;
+ uint *id_ptr = ps->nearest.rect_id;
/* Check against DEPTH_MAX because XRAY will clear the buffer,
* so previously set values will become unset.
@@ -454,8 +457,8 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons
const depth_t *prev = rect_prev->buf;
const depth_t *curr = rect_curr->buf;
BLI_assert(ps->src.rect_len == ps->dst.rect_len);
- const unsigned int rect_len = ps->src.rect_len;
- for (unsigned int i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) {
+ const uint rect_len = ps->src.rect_len;
+ for (uint i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) {
EVAL_TEST();
}
}
@@ -463,7 +466,7 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons
/* same as above but different rect sizes */
const depth_t *prev = rect_prev->buf + ps->cache.sub_rect.start;
const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
- for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) {
+ for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) {
const depth_t *curr_end = curr + ps->cache.sub_rect.span;
for (; curr < curr_end; prev++, curr++, id_ptr++) {
EVAL_TEST();
@@ -478,11 +481,11 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons
}
-bool gpu_select_pick_load_id(unsigned int id)
+bool gpu_select_pick_load_id(uint id)
{
GPUPickState *ps = &g_pick_state;
if (ps->gl.is_init) {
- const unsigned int rect_len = ps->src.rect_len;
+ const uint rect_len = ps->src.rect_len;
glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth_test->buf);
/* perform initial check since most cases the array remains unchanged */
@@ -524,7 +527,7 @@ bool gpu_select_pick_load_id(unsigned int id)
return true;
}
-unsigned int gpu_select_pick_end(void)
+uint gpu_select_pick_end(void)
{
GPUPickState *ps = &g_pick_state;
@@ -537,7 +540,6 @@ unsigned int gpu_select_pick_end(void)
/* force finishing last pass */
gpu_select_pick_load_id(ps->gl.prev_id);
}
-
gpuPopAttrib();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
@@ -559,9 +561,9 @@ unsigned int gpu_select_pick_end(void)
rect_depth_final = ps->gl.rect_depth;
}
- unsigned int maxhits = g_pick_state.bufsize;
+ uint maxhits = g_pick_state.bufsize;
DepthID *depth_data;
- unsigned int depth_data_len = 0;
+ uint depth_data_len = 0;
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
depth_data = ps->all.hits;
@@ -575,7 +577,7 @@ unsigned int gpu_select_pick_end(void)
/* GPU_SELECT_PICK_NEAREST */
/* Over alloc (unlikely we have as many depths as pixels) */
- unsigned int depth_data_len_first_pass = 0;
+ uint depth_data_len_first_pass = 0;
depth_data = MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__);
/* Partially de-duplicating copy,
@@ -584,7 +586,7 @@ unsigned int gpu_select_pick_end(void)
#define EVAL_TEST(i_src, i_dst) \
{ \
- const unsigned int id = ps->nearest.rect_id[i_dst]; \
+ const uint id = ps->nearest.rect_id[i_dst]; \
if (id != SELECT_ID_NONE) { \
const depth_t depth = rect_depth_final->buf[i_src]; \
if (depth_last == NULL || depth_last->id != id) { \
@@ -601,15 +603,15 @@ unsigned int gpu_select_pick_end(void)
{
DepthID *depth_last = NULL;
if (ps->is_cached == false) {
- for (unsigned int i = 0; i < ps->src.rect_len; i++) {
+ for (uint i = 0; i < ps->src.rect_len; i++) {
EVAL_TEST(i, i);
}
}
else {
/* same as above but different rect sizes */
- unsigned int i_src = ps->cache.sub_rect.start, i_dst = 0;
- for (unsigned int j = 0; j < ps->cache.sub_rect.span_len; j++) {
- const unsigned int i_src_end = i_src + ps->cache.sub_rect.span;
+ uint i_src = ps->cache.sub_rect.start, i_dst = 0;
+ for (uint j = 0; j < ps->cache.sub_rect.span_len; j++) {
+ const uint i_src_end = i_src + ps->cache.sub_rect.span;
for (; i_src < i_src_end; i_src++, i_dst++) {
EVAL_TEST(i_src, i_dst);
}
@@ -626,7 +628,7 @@ unsigned int gpu_select_pick_end(void)
depth_data_len = 0;
{
DepthID *depth_last = NULL;
- for (unsigned int i = 0; i < depth_data_len_first_pass; i++) {
+ for (uint i = 0; i < depth_data_len_first_pass; i++) {
if (depth_last == NULL || depth_last->id != depth_data[i].id) {
depth_last = &depth_data[depth_data_len++];
*depth_last = depth_data[i];
@@ -640,16 +642,16 @@ unsigned int gpu_select_pick_end(void)
/* Finally sort each unique (id, depth) pair by depth
* so the final hit-list is sorted by depth (nearest first) */
- unsigned int hits = 0;
+ uint hits = 0;
if (depth_data_len > maxhits) {
- hits = (unsigned int)-1;
+ hits = (uint)-1;
}
else {
/* leave sorting up to the caller */
qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
- for (unsigned int i = 0; i < depth_data_len; i++) {
+ for (uint i = 0; i < depth_data_len; i++) {
#ifdef DEBUG_PRINT
printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
#endif
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c
index e3bd20f3776..b8c3e164055 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.c
+++ b/source/blender/gpu/intern/gpu_select_sample_query.c
@@ -54,20 +54,20 @@ typedef struct GPUQueryState {
/* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
bool query_issued;
/* array holding the OpenGL query identifiers */
- unsigned int *queries;
+ uint *queries;
/* array holding the id corresponding to each query */
- unsigned int *id;
+ uint *id;
/* number of queries in *queries and *id */
- unsigned int num_of_queries;
+ uint num_of_queries;
/* index to the next query to start */
- unsigned int active_query;
+ uint active_query;
/* cache on initialization */
- unsigned int (*buffer)[4];
+ uint (*buffer)[4];
/* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
- unsigned int bufsize;
+ uint bufsize;
/* mode of operation */
char mode;
- unsigned int index;
+ uint index;
int oldhits;
} GPUQueryState;
@@ -75,7 +75,7 @@ static GPUQueryState g_query_state = {0};
void gpu_select_query_begin(
- unsigned int (*buffer)[4], unsigned int bufsize,
+ uint (*buffer)[4], uint bufsize,
const rcti *input, char mode,
int oldhits)
{
@@ -126,7 +126,7 @@ void gpu_select_query_begin(
}
}
-bool gpu_select_query_load_id(unsigned int id)
+bool gpu_select_query_load_id(uint id)
{
if (g_query_state.query_issued) {
glEndQuery(GL_SAMPLES_PASSED);
@@ -161,19 +161,19 @@ bool gpu_select_query_load_id(unsigned int id)
return true;
}
-unsigned int gpu_select_query_end(void)
+uint gpu_select_query_end(void)
{
int i;
- unsigned int hits = 0;
- const unsigned int maxhits = g_query_state.bufsize;
+ uint hits = 0;
+ const uint maxhits = g_query_state.bufsize;
if (g_query_state.query_issued) {
glEndQuery(GL_SAMPLES_PASSED);
}
for (i = 0; i < g_query_state.active_query; i++) {
- unsigned int result;
+ uint result;
glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
if (result > 0) {
if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index c25d03dff2f..b06ee56c21f 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -77,6 +77,7 @@ extern char datatoc_gpu_shader_image_interlace_frag_glsl[];
extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[];
extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[];
+extern char datatoc_gpu_shader_image_depth_copy_frag_glsl[];
extern char datatoc_gpu_shader_3D_vert_glsl[];
extern char datatoc_gpu_shader_3D_normal_vert_glsl[];
extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[];
@@ -712,6 +713,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
datatoc_gpu_shader_image_modulate_alpha_frag_glsl },
[GPU_SHADER_3D_IMAGE_DEPTH] = { datatoc_gpu_shader_3D_image_vert_glsl,
datatoc_gpu_shader_image_depth_linear_frag_glsl },
+ [GPU_SHADER_3D_IMAGE_DEPTH_COPY] = { datatoc_gpu_shader_3D_image_vert_glsl,
+ datatoc_gpu_shader_image_depth_copy_frag_glsl },
[GPU_SHADER_2D_IMAGE_INTERLACE] = { datatoc_gpu_shader_2D_image_vert_glsl,
datatoc_gpu_shader_image_interlace_frag_glsl },
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index d6b641af225..bd25dd03f13 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -67,6 +67,7 @@ struct GPUTexture {
unsigned int bytesize; /* number of byte for one pixel */
int format; /* GPUTextureFormat */
int components; /* number of color/alpha channels */
+ int samples; /* number of samples for multisamples textures. 0 if not multisample target */
};
/* ------ Memory Management ------- */
@@ -135,7 +136,7 @@ static GLenum gpu_texture_get_format(
*is_stencil = false;
/* Integer formats */
- if (ELEM(data_type, GPU_RG16I)) {
+ if (ELEM(data_type, GPU_RG16I, GPU_R16I)) {
*data_format = GL_INT;
switch (components) {
@@ -184,6 +185,7 @@ static GLenum gpu_texture_get_format(
break;
case GPU_DEPTH_COMPONENT16:
case GPU_R16F:
+ case GPU_R16I:
case GPU_RG8:
*bytesize = 2;
break;
@@ -208,6 +210,7 @@ static GLenum gpu_texture_get_format(
case GPU_RGBA8: return GL_RGBA8;
case GPU_R32F: return GL_R32F;
case GPU_R16F: return GL_R16F;
+ case GPU_R16I: return GL_R16I;
case GPU_RG8: return GL_RG8;
case GPU_R8: return GL_R8;
/* Special formats texture & renderbuffer */
@@ -340,6 +343,7 @@ static GPUTexture *GPU_texture_create_nD(
tex->w = w;
tex->h = h;
tex->d = d;
+ tex->samples = samples;
tex->number = -1;
tex->refcount = 1;
tex->fb_attachment = -1;
@@ -483,6 +487,7 @@ static GPUTexture *GPU_texture_cube_create(
tex->w = w;
tex->h = w;
tex->d = d;
+ tex->samples = 0;
tex->number = -1;
tex->refcount = 1;
tex->fb_attachment = -1;
@@ -576,6 +581,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
tex->fromblender = 1;
tex->format = -1;
tex->components = -1;
+ tex->samples = 0;
ima->gputexture[gputt] = tex;
@@ -1014,6 +1020,11 @@ int GPU_texture_format(const GPUTexture *tex)
return tex->format;
}
+int GPU_texture_samples(const GPUTexture *tex)
+{
+ return tex->samples;
+}
+
bool GPU_texture_depth(const GPUTexture *tex)
{
return tex->depth;
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index fc045805874..2ad89bd1345 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -87,6 +87,9 @@ struct GPUViewport {
struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */
ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */
+
+ /* Profiling data */
+ double cache_time;
};
enum {
@@ -97,6 +100,7 @@ static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, Texture
static void gpu_viewport_storage_free(StorageList *stl, int stl_len);
static void gpu_viewport_passes_free(PassList *psl, int psl_len);
static void gpu_viewport_texture_pool_free(GPUViewport *viewport);
+static void gpu_viewport_default_fb_create(GPUViewport *viewport);
void GPU_viewport_tag_update(GPUViewport *viewport)
{
@@ -125,9 +129,26 @@ GPUViewport *GPU_viewport_create(void)
GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs)
{
GPUViewport *viewport = GPU_viewport_create();
- GPU_offscreen_viewport_data_get(ofs, &viewport->fbl->default_fb, &viewport->txl->color, &viewport->txl->depth);
+ GPUTexture *color, *depth;
+ GPUFrameBuffer *fb;
viewport->size[0] = GPU_offscreen_width(ofs);
viewport->size[1] = GPU_offscreen_height(ofs);
+
+ GPU_offscreen_viewport_data_get(ofs, &fb, &color, &depth);
+
+ if (GPU_texture_samples(color)) {
+ viewport->txl->multisample_color = color;
+ viewport->txl->multisample_depth = depth;
+ viewport->fbl->multisample_fb = fb;
+ gpu_viewport_default_fb_create(viewport);
+ GPU_framebuffer_slots_bind(viewport->fbl->default_fb, 0);
+ }
+ else {
+ viewport->fbl->default_fb = fb;
+ viewport->txl->color = color;
+ viewport->txl->depth = depth;
+ }
+
return viewport;
}
/**
@@ -135,9 +156,23 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs)
*/
void GPU_viewport_clear_from_offscreen(GPUViewport *viewport)
{
- viewport->fbl->default_fb = NULL;
- viewport->txl->color = NULL;
- viewport->txl->depth = NULL;
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ DefaultTextureList *dtxl = viewport->txl;
+
+ if (dfbl->multisample_fb) {
+ /* GPUViewport expect the final result to be in default_fb but
+ * GPUOffscreen wants it in its multisample_fb, so we sync it back. */
+ GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, false, false);
+ GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, true, false);
+ dfbl->multisample_fb = NULL;
+ dtxl->multisample_color = NULL;
+ dtxl->multisample_depth = NULL;
+ }
+ else {
+ viewport->fbl->default_fb = NULL;
+ dtxl->color = NULL;
+ dtxl->depth = NULL;
+ }
}
void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type)
@@ -243,6 +278,11 @@ void GPU_viewport_size_set(GPUViewport *viewport, const int size[2])
viewport->size[1] = size[1];
}
+double *GPU_viewport_cache_time_get(GPUViewport *viewport)
+{
+ return &viewport->cache_time;
+}
+
/**
* Try to find a texture coresponding to params into the texture pool.
* If no texture was found, create one and add it to the pool.
@@ -335,6 +375,65 @@ void GPU_viewport_cache_release(GPUViewport *viewport)
}
}
+static void gpu_viewport_default_fb_create(GPUViewport *viewport)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ DefaultTextureList *dtxl = viewport->txl;
+ int *size = viewport->size;
+ bool ok = true;
+
+ dfbl->default_fb = GPU_framebuffer_create();
+ if (!dfbl->default_fb) {
+ ok = false;
+ goto cleanup;
+ }
+
+ /* Color */
+ dtxl->color = GPU_texture_create_2D(size[0], size[1], NULL, NULL);
+ if (!dtxl->color) {
+ ok = false;
+ goto cleanup;
+ }
+
+ if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) {
+ ok = false;
+ goto cleanup;
+ }
+
+ /* Depth */
+ dtxl->depth = GPU_texture_create_depth_with_stencil(size[0], size[1], NULL);
+
+ if (dtxl->depth) {
+ /* Define texture parameters */
+ GPU_texture_bind(dtxl->depth, 0);
+ GPU_texture_compare_mode(dtxl->depth, false);
+ GPU_texture_filter_mode(dtxl->depth, true);
+ GPU_texture_unbind(dtxl->depth);
+ }
+ else {
+ ok = false;
+ goto cleanup;
+ }
+
+ if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) {
+ ok = false;
+ goto cleanup;
+ }
+ else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) {
+ ok = false;
+ goto cleanup;
+ }
+
+cleanup:
+ if (!ok) {
+ GPU_viewport_free(viewport);
+ DRW_opengl_context_disable();
+ return;
+ }
+
+ GPU_framebuffer_restore();
+}
+
void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
{
DefaultFramebufferList *dfbl = viewport->fbl;
@@ -345,6 +444,8 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
int rect_w = BLI_rcti_size_x(rect) + 1;
int rect_h = BLI_rcti_size_y(rect) + 1;
+ DRW_opengl_context_enable();
+
if (dfbl->default_fb) {
if (rect_w != viewport->size[0] || rect_h != viewport->size[1] || U.ogl_multisamples != viewport->samples) {
gpu_viewport_buffers_free(
@@ -361,6 +462,9 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
}
}
+ viewport->size[0] = rect_w;
+ viewport->size[1] = rect_h;
+
gpu_viewport_texture_pool_clear_users(viewport);
/* Multisample Buffer */
@@ -408,67 +512,13 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
cleanup_multisample:
if (!ok) {
GPU_viewport_free(viewport);
- MEM_freeN(viewport);
return;
}
}
}
if (!dfbl->default_fb) {
- bool ok = true;
- viewport->size[0] = rect_w;
- viewport->size[1] = rect_h;
-
- dfbl->default_fb = GPU_framebuffer_create();
- if (!dfbl->default_fb) {
- ok = false;
- goto cleanup;
- }
-
- /* Color */
- dtxl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL);
- if (!dtxl->color) {
- ok = false;
- goto cleanup;
- }
-
- if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) {
- ok = false;
- goto cleanup;
- }
-
- /* Depth */
- dtxl->depth = GPU_texture_create_depth_with_stencil(rect_w, rect_h, NULL);
-
- if (dtxl->depth) {
- /* Define texture parameters */
- GPU_texture_bind(dtxl->depth, 0);
- GPU_texture_compare_mode(dtxl->depth, false);
- GPU_texture_filter_mode(dtxl->depth, true);
- GPU_texture_unbind(dtxl->depth);
- }
- else {
- ok = false;
- goto cleanup;
- }
-
- if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) {
- ok = false;
- goto cleanup;
- }
- else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) {
- ok = false;
- goto cleanup;
- }
-
-cleanup:
- if (!ok) {
- GPU_viewport_free(viewport);
- MEM_freeN(viewport);
- return;
- }
-
- GPU_framebuffer_restore();
+ gpu_viewport_default_fb_create(viewport);
}
GPU_framebuffer_slots_bind(dfbl->default_fb, 0);
@@ -523,7 +573,11 @@ void GPU_viewport_unbind(GPUViewport *viewport)
if (dfbl->default_fb) {
GPU_framebuffer_texture_unbind(NULL, NULL);
GPU_framebuffer_restore();
+ }
+ DRW_opengl_context_disable();
+
+ if (dfbl->default_fb) {
glEnable(GL_SCISSOR_TEST);
glDisable(GL_DEPTH_TEST);
}
@@ -581,6 +635,7 @@ static void gpu_viewport_passes_free(PassList *psl, int psl_len)
}
}
+/* Must be executed inside Drawmanager Opengl Context. */
void GPU_viewport_free(GPUViewport *viewport)
{
gpu_viewport_engines_data_free(viewport);
@@ -597,8 +652,8 @@ void GPU_viewport_free(GPUViewport *viewport)
if (viewport->vmempool.calls != NULL) {
BLI_mempool_destroy(viewport->vmempool.calls);
}
- if (viewport->vmempool.calls_generate != NULL) {
- BLI_mempool_destroy(viewport->vmempool.calls_generate);
+ if (viewport->vmempool.states != NULL) {
+ BLI_mempool_destroy(viewport->vmempool.states);
}
if (viewport->vmempool.shgroups != NULL) {
BLI_mempool_destroy(viewport->vmempool.shgroups);
@@ -614,6 +669,8 @@ void GPU_viewport_free(GPUViewport *viewport)
MEM_freeN(viewport->idatalist);
GPU_viewport_debug_depth_free(viewport);
+
+ MEM_freeN(viewport);
}
/****************** debug ********************/
diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl
new file mode 100644
index 00000000000..10f4dfd5a87
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl
@@ -0,0 +1,12 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+
+void main()
+{
+ float depth = texture(image, texCoord_interp).r;
+ fragColor = vec4(depth);
+ gl_FragDepth = depth;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 7acd9aa1fd5..d3bc1f0ef8e 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1,16 +1,9 @@
-uniform mat4 ModelViewMatrix;
-#ifndef EEVEE_ENGINE
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrixInverse;
-uniform mat4 ViewMatrix;
-#endif
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+uniform mat4 ModelViewMatrix;
uniform mat4 ModelViewMatrixInverse;
-uniform mat4 ProjectionMatrixInverse;
uniform mat3 NormalMatrix;
-uniform vec4 CameraTexCoFactors;
/* Old glsl mode compat. */
@@ -2697,7 +2690,6 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
{
#ifdef EEVEE_ENGINE
vec3 out_spec, ssr_spec;
- roughness = sqrt(roughness);
eevee_closure_glossy(N, vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
vec3 vN = normalize(mat3(ViewMatrix) * N);
result = CLOSURE_DEFAULT;
@@ -2719,7 +2711,8 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
vec3 light_specular = glLightSource[i].specular.rgb;
/* we mix in some diffuse so low roughness still shows up */
- float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
+ float r2 = roughness * roughness;
+ float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / r2);
bsdf += 0.5 * max(dot(N, light_position), 0.0);
L += light_specular * bsdf;
}
@@ -2739,7 +2732,6 @@ void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_i
{
#ifdef EEVEE_ENGINE
vec3 out_spec, out_refr, ssr_spec;
- roughness = sqrt(roughness);
vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : color.rgb; /* Simulate 2 transmission event */
eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
out_refr *= refr_color;
@@ -2978,7 +2970,6 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl
#ifdef EEVEE_ENGINE
vec3 out_refr;
color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
- roughness = sqrt(roughness);
eevee_closure_refraction(N, roughness, ior, out_refr);
vec3 vN = normalize(mat3(ViewMatrix) * N);
result = CLOSURE_DEFAULT;
@@ -3075,6 +3066,86 @@ void node_volume_absorption(vec4 color, float density, out Closure result)
#endif
}
+void node_blackbody(float temperature, sampler2D spectrummap, out vec4 color)
+{
+ if(temperature >= 12000.0) {
+ color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
+ }
+ else if(temperature < 965.0) {
+ color = vec4(4.70366907, 0.0, 0.0, 1.0);
+ }
+ else {
+ float t = (temperature - 965.0) / (12000.0 - 965.0);
+ color = vec4(texture(spectrummap, vec2(t, 0.0)).rgb, 1.0);
+ }
+}
+
+void node_volume_principled(
+ vec4 color,
+ float density,
+ float anisotropy,
+ vec4 absorption_color,
+ float emission_strength,
+ vec4 emission_color,
+ float blackbody_intensity,
+ vec4 blackbody_tint,
+ float temperature,
+ float density_attribute,
+ vec4 color_attribute,
+ float temperature_attribute,
+ sampler2D spectrummap,
+ out Closure result)
+{
+#ifdef VOLUMETRICS
+ vec3 absorption_coeff = vec3(0.0);
+ vec3 scatter_coeff = vec3(0.0);
+ vec3 emission_coeff = vec3(0.0);
+
+ /* Compute density. */
+ density = max(density, 0.0);
+
+ if(density > 1e-5) {
+ density = max(density * density_attribute, 0.0);
+ }
+
+ if(density > 1e-5) {
+ /* Compute scattering and absorption coefficients. */
+ vec3 scatter_color = color.rgb * color_attribute.rgb;
+
+ scatter_coeff = scatter_color * density;
+ absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0));
+ absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) * density;
+ }
+
+ /* Compute emission. */
+ emission_strength = max(emission_strength, 0.0);
+
+ if(emission_strength > 1e-5) {
+ emission_coeff += emission_strength * emission_color.rgb;
+ }
+
+ if(blackbody_intensity > 1e-3) {
+ /* Add temperature from attribute. */
+ float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
+
+ /* Stefan-Boltzman law. */
+ float T4 = (T * T) * (T * T);
+ float sigma = 5.670373e-8 * 1e-6 / M_PI;
+ float intensity = sigma * mix(1.0, T4, blackbody_intensity);
+
+ if(intensity > 1e-5) {
+ vec4 bb;
+ node_blackbody(T, spectrummap, bb);
+ emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
+ }
+ }
+
+ result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
+
/* closures */
void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
@@ -3153,7 +3224,13 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
#else
vec3 cos = vec3(0.0);
#endif
- outvec = texture(tex, cos).rgb;
+
+ vec4 value = texture(tex, cos).rgba;
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (value.a > 1e-8)
+ value.rgb /= value.a;
+
+ outvec = value.rgb;
outcol = vec4(outvec, 1.0);
outf = dot(vec3(1.0 / 3.0), outvec);
}
@@ -3165,9 +3242,23 @@ void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec
#else
vec3 cos = vec3(0.0);
#endif
- outvec = texture(tex, cos).rrr;
- outcol = vec4(outvec, 1.0);
- outf = dot(vec3(1.0 / 3.0), outvec);
+ outf = texture(tex, cos).r;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
+void node_attribute_volume_temperature(sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ float flame = texture(tex, cos).r;
+
+ outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x): 0.0;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
}
void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 5472cae3ef2..a770b34ecc6 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -511,7 +511,7 @@ static int startffmpeg(struct anim *anim)
return -1;
}
- frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
+ frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
}
@@ -989,7 +989,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
v_st = anim->pFormatCtx->streams[anim->videoStream];
- frame_rate = av_q2d(av_get_r_frame_rate_compat(v_st));
+ frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
st_time = anim->pFormatCtx->start_time;
pts_time_base = av_q2d(v_st->time_base);
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 009258079ee..eaf4dfd84b4 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -909,7 +909,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
stream_size = avio_size(context->iFormatCtx->pb);
- context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iStream));
+ context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
context->pts_time_base = av_q2d(context->iStream->time_base);
while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 539b9fa45b4..4e85d70d382 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1290,7 +1290,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
return 1;
}
- /* last token is single character channel identifier */
+ /* last token is channel identifier */
len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
@@ -1319,10 +1319,30 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
ok = true;
}
}
+ else if (BLI_strcaseeq(token, "red")) {
+ echan->chan_id = 'R';
+ ok = true;
+ }
+ else if (BLI_strcaseeq(token, "green")) {
+ echan->chan_id = 'G';
+ ok = true;
+ }
+ else if (BLI_strcaseeq(token, "blue")) {
+ echan->chan_id = 'B';
+ ok = true;
+ }
+ else if (BLI_strcaseeq(token, "alpha")) {
+ echan->chan_id = 'A';
+ ok = true;
+ }
+ else if (BLI_strcaseeq(token, "depth")) {
+ echan->chan_id = 'Z';
+ ok = true;
+ }
if (ok == false) {
BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
- printf("multilayer read: channel token too long: %s\n", tokenbuf);
+ printf("multilayer read: unknown channel token: %s\n", tokenbuf);
return 0;
}
}
@@ -1601,14 +1621,13 @@ static bool exr_has_alpha(MultiPartInputFile& file)
static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
{
- const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
const ChannelList& channels = file.header(0).channels();
std::set <std::string> layerNames;
/* will not include empty layer names */
channels.layers(layerNames);
- if (comments || layerNames.size() > 1)
+ if (layerNames.size() > 1)
return true;
if (layerNames.size()) {
@@ -1647,7 +1666,7 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
}
else {
*r_singlelayer = false;
- *r_multilayer = true;
+ *r_multilayer = (layerNames.size() > 1);
*r_multiview = false;
return;
}
diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h
index 58f9e29297f..524c85948f3 100644
--- a/source/blender/makesdna/DNA_object_enums.h
+++ b/source/blender/makesdna/DNA_object_enums.h
@@ -46,4 +46,7 @@ typedef enum eObjectMode {
/* Any mode that uses Object.sculpt. */
#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)
+/* Any mode that has data we need to free when switching modes, see: #ED_object_mode_generic_exit */
+#define OB_MODE_ALL_MODE_DATA (OB_MODE_EDIT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT)
+
#endif /* __DNA_OBJECT_ENUMS_H__ */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1642da25481..bc3fd46e1a9 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -243,6 +243,7 @@ typedef enum eScenePassType {
SCE_PASS_SUBSURFACE_DIRECT = (1 << 28),
SCE_PASS_SUBSURFACE_INDIRECT = (1 << 29),
SCE_PASS_SUBSURFACE_COLOR = (1 << 30),
+ SCE_PASS_ROUGHNESS = (1 << 31),
} eScenePassType;
#define RE_PASSNAME_COMBINED "Combined"
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 9932e16e988..c1565bde882 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -217,6 +217,9 @@ typedef struct SmokeDomainSettings {
char use_coba;
char coba_field; /* simulation field used for the color mapping */
char pad2;
+
+ float clipping;
+ float pad3;
} SmokeDomainSettings;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 003e7eb6e46..59d5df76c35 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -180,6 +180,7 @@ typedef struct wmWindow {
struct wmWindow *next, *prev;
void *ghostwin; /* don't want to include ghost.h stuff */
+ void *gwnctx; /* don't want to include gawin stuff */
struct Scene *scene; /* The scene displayed in this window. */
struct Scene *new_scene; /* temporary when switching */
@@ -315,13 +316,16 @@ typedef struct wmKeyMap {
char idname[64]; /* global editor keymaps, or for more per space/region */
short spaceid; /* same IDs as in DNA_space_types.h */
short regionid; /* see above */
+ char owner_id[64]; /* optional, see: #wmOwnerID */
short flag; /* general flags */
short kmi_id; /* last kmi id */
/* runtime */
- int (*poll)(struct bContext *); /* verify if enabled in the current context */
- const void *modal_items; /* for modal, EnumPropertyItem for now */
+ /** Verify if enabled in the current context, use #WM_keymap_poll instead of direct calls. */
+ int (*poll)(struct bContext *);
+ /** For modal, #EnumPropertyItem for now. */
+ const void *modal_items;
} wmKeyMap;
/* wmKeyMap.flag */
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index dbcc278ea15..894119b1e72 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -77,6 +77,12 @@ typedef struct WorkSpaceLayout {
char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */
} WorkSpaceLayout;
+/** Optional tags, which features to use, aligned with #bAddon names by convention. */
+typedef struct wmOwnerID {
+ struct wmOwnerID *next, *prev;
+ char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */
+} wmOwnerID;
+
typedef struct WorkSpace {
ID id;
@@ -86,6 +92,9 @@ typedef struct WorkSpace {
ListBase hook_layout_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */
ListBase scene_viewlayer_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */
+ /* Feature tagging (use for addons) */
+ ListBase owner_ids DNA_PRIVATE_WORKSPACE_READ_WRITE; /* wmOwnerID */
+
/* Custom transform orientations */
ListBase transform_orientations DNA_PRIVATE_WORKSPACE;
@@ -154,6 +163,7 @@ typedef struct WorkSpaceInstanceHook {
typedef enum eWorkSpaceFlags {
WORKSPACE_USE_SCENE_SETTINGS = (1 << 0),
+ WORKSPACE_USE_FILTER_BY_ORIGIN = (1 << 1),
} eWorkSpaceFlags;
#endif /* __DNA_WORKSPACE_TYPES_H__ */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 199bb75d099..c9385f98584 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -57,7 +57,7 @@
* \section dna_genfile Overview
*
* - please note: no builtin security to detect input of double structs
- * - if you want a struct not to be in DNA file: add two hash marks above it (#<enter>#<enter>)
+ * - if you want a struct not to be in DNA file: add two hash marks above it `(#<enter>#<enter>)`.
*
* Structure DNA data is added to each blender file and to each executable, this to detect
* in .blend files new variables in structs, changed array sizes, etc. It's also used for
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 816a472559f..1058099e9ef 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -719,6 +719,7 @@ extern StructRNA RNA_WipeSequence;
extern StructRNA RNA_WireframeModifier;
extern StructRNA RNA_WoodTexture;
extern StructRNA RNA_WorkSpace;
+extern StructRNA RNA_wmOwnerIDs;
extern StructRNA RNA_World;
extern StructRNA RNA_WorldAmbientOcclusion;
extern StructRNA RNA_WorldLighting;
@@ -1277,6 +1278,13 @@ typedef enum eRNAOverrideMatchResult {
RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 1,
} eRNAOverrideMatchResult;
+typedef enum eRNAOverrideStatus {
+ RNA_OVERRIDE_STATUS_OVERRIDABLE = 1 << 0, /* The property is overridable. */
+ RNA_OVERRIDE_STATUS_OVERRIDDEN = 1 << 1, /* The property is overridden. */
+ RNA_OVERRIDE_STATUS_MANDATORY = 1 << 2, /* Overriding this property is mandatory when creating an override. */
+ RNA_OVERRIDE_STATUS_LOCKED = 1 << 3, /* The override status of this property is locked. */
+} eRNAOverrideStatus;
+
bool RNA_struct_override_matches(
struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, const char *root_path,
struct IDOverrideStatic *override, const eRNAOverrideMatch flags,
@@ -1299,9 +1307,11 @@ struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operati
PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
const bool strict, bool *r_strict, bool *r_created);
-void RNA_property_override_status(
- PointerRNA *ptr, PropertyRNA *prop, const int index,
- bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked);
+eRNAOverrideStatus RNA_property_override_status(PointerRNA *ptr, PropertyRNA *prop, const int index);
+
+void RNA_struct_state_owner_set(const char *name);
+const char *RNA_struct_state_owner_get(void);
+
#ifdef __cplusplus
}
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 2a9b9ebe376..57eeb9e11e0 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -505,7 +505,6 @@ typedef struct ExtensionRNA {
StructRNA *srna;
StructCallbackFunc call;
StructFreeFunc free;
-
} ExtensionRNA;
#ifdef __cplusplus
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 1750c50b9da..b63cebbdde2 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -451,8 +451,9 @@ static void *rna_idproperty_check_ex(PropertyRNA **prop, PointerRNA *ptr, const
return idprop;
}
- else
+ else {
return return_rnaprop ? *prop : NULL;
+ }
}
{
@@ -7149,10 +7150,13 @@ bool RNA_struct_equals(PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mod
* 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).
+ *
+ * \note When there is no equality, but we cannot determine an order (greater than/lesser than), we return 1.
*/
static int rna_property_override_diff(
- 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)
+ 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)
{
if (prop != NULL) {
BLI_assert(prop_a == NULL && prop_b == NULL);
@@ -7678,29 +7682,30 @@ IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
}
-void RNA_property_override_status(
- PointerRNA *ptr, PropertyRNA *prop, const int index,
- bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked)
+eRNAOverrideStatus RNA_property_override_status(PointerRNA *ptr, PropertyRNA *prop, const int index)
{
-#define SET_RET(_name, _val) if (_name != NULL) *_name = (_val)
-
- SET_RET(r_overridable, false);
- SET_RET(r_overridden, false);
- SET_RET(r_mandatory, false);
- SET_RET(r_locked, false);
+ int override_status = 0;
if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) {
- return;
+ return override_status;
}
- SET_RET(r_overridable, (prop->flag & PROP_OVERRIDABLE_STATIC) && (prop->flag & PROP_EDITABLE));
+ if ((prop->flag & PROP_OVERRIDABLE_STATIC) && (prop->flag & PROP_EDITABLE)) {
+ override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
+ }
- if (r_overridden || r_mandatory || r_locked) {
- IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL);
- SET_RET(r_overridden, opop != NULL);
- SET_RET(r_mandatory, (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) != 0);
- SET_RET(r_locked, (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) != 0);
+ IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL);
+ if (opop != NULL) {
+ override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
+ if (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) {
+ override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
+ }
+ if (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) {
+ override_status |= RNA_OVERRIDE_STATUS_LOCKED;
+ }
}
+
+ return override_status;
}
@@ -7723,3 +7728,22 @@ bool RNA_path_resolved_create(
return false;
}
}
+
+static char rna_struct_state_owner[64];
+void RNA_struct_state_owner_set(const char *name)
+{
+ if (name) {
+ BLI_strncpy(rna_struct_state_owner, name, sizeof(rna_struct_state_owner));
+ }
+ else {
+ rna_struct_state_owner[0] = '\0';
+ }
+}
+
+const char *RNA_struct_state_owner_get(void)
+{
+ if (rna_struct_state_owner[0]) {
+ return rna_struct_state_owner;
+ }
+ return NULL;
+}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 3d11e7bb723..3c940e3dcbf 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -520,7 +520,7 @@ static void rna_KeyingSet_paths_clear(KeyingSet *keyingset, ReportList *reports)
/* needs wrapper function to push notifier */
static NlaTrack *rna_NlaTrack_new(AnimData *adt, bContext *C, NlaTrack *track)
{
- NlaTrack *new_track = add_nlatrack(adt, track);
+ NlaTrack *new_track = BKE_nlatrack_add(adt, track);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, NULL);
@@ -536,7 +536,7 @@ static void rna_NlaTrack_remove(AnimData *adt, bContext *C, ReportList *reports,
return;
}
- free_nlatrack(&adt->nla_tracks, track);
+ BKE_nlatrack_free(&adt->nla_tracks, track);
RNA_POINTER_INVALIDATE(track_ptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_REMOVED, NULL);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index aa37c9ffa88..ca8abdc8b48 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -441,7 +441,6 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
br->id.icon_id = 0;
if (br->flag & BRUSH_CUSTOM_ICON) {
- BKE_previewimg_id_ensure(&br->id);
BKE_icon_changed(BKE_icon_id_ensure(&br->id));
}
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index e6e1c714008..bb20fcb271f 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -34,10 +34,11 @@
#include "rna_internal.h"
-#include "DEG_depsgraph.h"
-
#include "DNA_object_types.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#define STATS_MAX_SIZE 16384
#ifdef RNA_RUNTIME
@@ -240,6 +241,13 @@ static ID *rna_Depsgraph_evaluated_id_get(Depsgraph *depsgraph, ID *id_orig)
return DEG_get_evaluated_id(depsgraph, id_orig);
}
+static PointerRNA rna_Depsgraph_view_layer_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = (Depsgraph *)ptr->data;
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer);
+}
+
#else
static void rna_def_depsgraph_iter(BlenderRNA *brna)
@@ -358,6 +366,11 @@ static void rna_def_depsgraph(BlenderRNA *brna)
"rna_Depsgraph_duplis_end",
"rna_Depsgraph_duplis_get",
NULL, NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Depsgraph_view_layer_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Scene layer", "");
}
void RNA_def_depsgraph(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index b973e0f27ee..466a01a7271 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -723,11 +723,11 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_WAVE_OPEN_BORDERS);
RNA_def_property_ui_text(prop, "Open Borders", "Pass waves through mesh edges");
-
/* cache */
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
+ RNA_def_property_struct_type(prop, "PointCache");
RNA_def_property_ui_text(prop, "Point Cache", "");
/* is cache used */
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 7a1c1710a87..9992ab06211 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -911,18 +911,19 @@ 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_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)
+ DEG_OBJECT_ITER_BEGIN(
+ 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. */
UNUSED_VARS(ob);
}
- DEG_OBJECT_ITER_END
+ DEG_OBJECT_ITER_END;
}
static void rna_ObjectBase_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index a14508ecb18..1301762a4bc 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -370,7 +370,7 @@ static FCurve *rna_NlaStrip_fcurve_find(NlaStrip *strip, ReportList *reports, co
static NlaStrip *rna_NlaStrip_new(NlaTrack *track, bContext *C, ReportList *reports, const char *UNUSED(name),
int start, bAction *action)
{
- NlaStrip *strip = add_nlastrip(action);
+ NlaStrip *strip = BKE_nlastrip_new(action);
if (strip == NULL) {
BKE_report(reports, RPT_ERROR, "Unable to create new strip");
@@ -383,7 +383,7 @@ static NlaStrip *rna_NlaStrip_new(NlaTrack *track, bContext *C, ReportList *repo
if (BKE_nlastrips_add_strip(&track->strips, strip) == 0) {
BKE_report(reports, RPT_ERROR,
"Unable to add strip (the track does not have any space to accommodate this new strip)");
- free_nlastrip(NULL, strip);
+ BKE_nlastrip_free(NULL, strip);
return NULL;
}
@@ -424,7 +424,7 @@ static void rna_NlaStrip_remove(NlaTrack *track, bContext *C, ReportList *report
return;
}
- free_nlastrip(&track->strips, strip);
+ BKE_nlastrip_free(&track->strips, strip);
RNA_POINTER_INVALIDATE(strip_ptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_REMOVED, NULL);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index a148efb859d..55ae7fdb6af 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2306,9 +2306,15 @@ static void rna_NodeSocketStandard_vector_range(PointerRNA *ptr, float *min, flo
static void rna_NodeSocket_value_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ bNodeSocket *sock = ptr->data;
+
if (ntree->type == NTREE_SHADER) {
- DEG_id_tag_update_ex(bmain, ptr->id.data, DEG_TAG_SHADING_UPDATE);
+ DEG_id_tag_update_ex(bmain, &ntree->id, DEG_TAG_SHADING_UPDATE);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, NULL);
+
+ if (sock->type == SOCK_STRING) {
+ rna_NodeSocket_update(bmain, scene, ptr);
+ }
}
else {
rna_NodeSocket_update(bmain, scene, ptr);
@@ -3128,16 +3134,22 @@ static int point_density_vertex_color_source_from_shader(NodeShaderTexPointDensi
}
void rna_ShaderNodePointDensity_density_cache(bNode *self,
- Scene *scene,
- ViewLayer *view_layer,
+ Depsgraph *depsgraph,
int settings)
{
NodeShaderTexPointDensity *shader_point_density = self->storage;
PointDensity *pd = &shader_point_density->pd;
- if (scene == NULL) {
+
+ if (depsgraph == NULL) {
return;
}
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init_from_depsgraph(&eval_ctx,
+ depsgraph,
+ settings == 1 ? DAG_EVAL_RENDER :
+ DAG_EVAL_VIEWPORT);
+
/* Make sure there's no cached data. */
BKE_texture_pointdensity_free_data(pd);
RE_point_density_free(pd);
@@ -3166,14 +3178,12 @@ void rna_ShaderNodePointDensity_density_cache(bNode *self,
shader_point_density->cached_resolution = shader_point_density->resolution;
/* Single-threaded sampling of the voxel domain. */
- RE_point_density_cache(scene,
- view_layer, pd,
- settings == 1);
+ RE_point_density_cache(&eval_ctx,
+ pd);
}
void rna_ShaderNodePointDensity_density_calc(bNode *self,
- Scene *scene,
- ViewLayer *view_layer,
+ Depsgraph *depsgraph,
int settings,
int *length,
float **values)
@@ -3182,11 +3192,17 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
PointDensity *pd = &shader_point_density->pd;
const int resolution = shader_point_density->cached_resolution;
- if (scene == NULL) {
+ if (depsgraph == NULL) {
*length = 0;
return;
}
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init_from_depsgraph(&eval_ctx,
+ depsgraph,
+ settings == 1 ? DAG_EVAL_RENDER :
+ DAG_EVAL_VIEWPORT);
+
/* TODO(sergey): Will likely overflow, but how to pass size_t via RNA? */
*length = 4 * resolution * resolution * resolution;
@@ -3195,9 +3211,9 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
}
/* Single-threaded sampling of the voxel domain. */
- RE_point_density_sample(scene, view_layer, pd,
+ RE_point_density_sample(&eval_ctx,
+ pd,
resolution,
- settings == 1,
*values);
/* We're done, time to clean up. */
@@ -3207,20 +3223,27 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
}
void rna_ShaderNodePointDensity_density_minmax(bNode *self,
- Scene *scene,
- ViewLayer *view_layer,
+ Depsgraph *depsgraph,
int settings,
float r_min[3],
float r_max[3])
{
NodeShaderTexPointDensity *shader_point_density = self->storage;
PointDensity *pd = &shader_point_density->pd;
- if (scene == NULL) {
+
+ if (depsgraph == NULL) {
zero_v3(r_min);
zero_v3(r_max);
return;
}
- RE_point_density_minmax(scene, view_layer, pd, settings == 1, r_min, r_max);
+
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init_from_depsgraph(&eval_ctx,
+ depsgraph,
+ settings == 1 ? DAG_EVAL_RENDER :
+ DAG_EVAL_VIEWPORT);
+
+ RE_point_density_minmax(&eval_ctx, pd, r_min, r_max);
}
#else
@@ -4210,14 +4233,12 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
func = RNA_def_function(srna, "cache_point_density", "rna_ShaderNodePointDensity_density_cache");
RNA_def_function_ui_description(func, "Cache point density data for later calculation");
- RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_pointer(func, "view_layer", "ViewLayer", "", "");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc");
RNA_def_function_ui_description(func, "Calculate point density");
- RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_pointer(func, "view_layer", "ViewLayer", "", "");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
/* TODO, See how array size of 0 works, this shouldnt be used. */
parm = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
@@ -4226,8 +4247,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
func = RNA_def_function(srna, "calc_point_density_minmax", "rna_ShaderNodePointDensity_density_minmax");
RNA_def_function_ui_description(func, "Calculate point density");
- RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_pointer(func, "view_layer", "ViewLayer", "", "");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS);
RNA_def_property_array(parm, 3);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index e37446028be..aa78b9e614d 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -45,6 +45,7 @@
#include "BKE_camera.h"
#include "BKE_paint.h"
+#include "BKE_editlattice.h"
#include "BKE_editmesh.h"
#include "BKE_group.h" /* needed for BKE_group_object_exists() */
#include "BKE_object_deform.h"
@@ -301,16 +302,18 @@ void rna_Object_internal_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene),
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ptr->id.data);
}
-static void rna_Object_active_shape_update(bContext *C, Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr)
{
Object *ob = ptr->id.data;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
if (CTX_data_edit_object(C) == ob) {
/* exit/enter editmode to get new shape */
switch (ob->type) {
case OB_MESH:
EDBM_mesh_load(ob);
- EDBM_mesh_make(scene->toolsettings, ob, true);
+ EDBM_mesh_make(ob, scene->toolsettings->selectmode, true);
DEG_id_tag_update(ob->data, 0);
@@ -323,8 +326,8 @@ static void rna_Object_active_shape_update(bContext *C, Main *bmain, Scene *scen
ED_curve_editnurb_make(ob);
break;
case OB_LATTICE:
- ED_lattice_editlatt_load(ob);
- ED_lattice_editlatt_make(ob);
+ BKE_editlattice_load(ob);
+ BKE_editlattice_make(ob);
break;
}
}
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 17f19bfc38c..6b631ca0ecf 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -148,7 +148,7 @@ static int rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports)
}
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
-static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
+static void rna_Object_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
float *mat, float *mat_ret, int from, int to)
{
copy_m4_m4((float (*)[4])mat_ret, (float (*)[4])mat);
@@ -585,7 +585,7 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_return(func, parm);
/* Matrix space conversion */
- func = RNA_def_function(srna, "convert_space", "rna_Scene_mat_convert_space");
+ func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space");
RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "pose_bone", "PoseBone", "",
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 8fc6b2b1a58..649cb523e92 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -609,11 +609,11 @@ static void rna_EffectorWeight_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
if (id && GS(id->name) == ID_SCE) {
Scene *scene = (Scene *)id;
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
else {
DEG_id_tag_update(id, OB_RECALC_DATA | PSYS_RECALC_RESET);
@@ -772,31 +772,8 @@ static const EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), Poi
#else
-/* ptcache.point_caches */
-static void rna_def_ptcache_point_caches(BlenderRNA *brna, PropertyRNA *cprop)
+static void rna_def_pointcache_common(StructRNA *srna)
{
- StructRNA *srna;
- PropertyRNA *prop;
-
- /* FunctionRNA *func; */
- /* PropertyRNA *parm; */
-
- RNA_def_property_srna(cprop, "PointCaches");
- srna = RNA_def_struct(brna, "PointCaches", NULL);
- RNA_def_struct_sdna(srna, "PointCache");
- RNA_def_struct_ui_text(srna, "Point Caches", "Collection of point caches");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Cache_active_point_cache_index_get",
- "rna_Cache_active_point_cache_index_set",
- "rna_Cache_active_point_cache_index_range");
- RNA_def_property_ui_text(prop, "Active Point Cache Index", "");
- RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_change");
-}
-
-static void rna_def_pointcache(BlenderRNA *brna)
-{
- StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem point_cache_compress_items[] = {
@@ -806,16 +783,12 @@ static void rna_def_pointcache(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- srna = RNA_def_struct(brna, "PointCache", NULL);
- RNA_def_struct_ui_text(srna, "Point Cache", "Point cache for physics simulations");
- RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
-
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "startframe");
RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1);
RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts");
-
+
prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "endframe");
RNA_def_property_range(prop, 1, MAXFRAME);
@@ -896,13 +869,59 @@ static void rna_def_pointcache(BlenderRNA *brna)
"Use this file's path for the disk cache when library linked into another file "
"(for local bakes per scene file, disable this option)");
RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_idname_change");
+}
+
+static void rna_def_ptcache_point_caches(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* FunctionRNA *func; */
+ /* PropertyRNA *parm; */
+
+ RNA_def_property_srna(cprop, "PointCaches");
+ srna = RNA_def_struct(brna, "PointCaches", NULL);
+ RNA_def_struct_sdna(srna, "PointCache");
+ RNA_def_struct_ui_text(srna, "Point Caches", "Collection of point caches");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Cache_active_point_cache_index_get",
+ "rna_Cache_active_point_cache_index_set",
+ "rna_Cache_active_point_cache_index_range");
+ RNA_def_property_ui_text(prop, "Active Point Cache Index", "");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_change");
+
+ /* And define another RNA type for those collection items. */
+ srna = RNA_def_struct(brna, "PointCacheItem", NULL);
+ RNA_def_struct_sdna(srna, "PointCache");
+ RNA_def_struct_ui_text(srna, "Point Cache", "point cache for physics simulations");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+
+ rna_def_pointcache_common(srna);
+}
+
+static void rna_def_pointcache_active(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "PointCache", NULL);
+ RNA_def_struct_ui_text(srna, "Active Point Cache", "Active point cache for physics simulations");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+
+ rna_def_pointcache_common(srna);
+ /* This first-level RNA pointer also has list of all caches from owning ID.
+ * Those caches items have exact same content as 'active' one, except for that collection,
+ * to prevent ugly recursive layout pattern.
+ * Note: This shall probably be redone from scratch in a proper way at some poitn, but for now that will do,
+ * and shall not break anything in the API. */
prop = RNA_def_property(srna, "point_caches", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop, "rna_Cache_list_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
- RNA_def_property_struct_type(prop, "PointCache");
- RNA_def_property_ui_text(prop, "Point Cache List", "Point cache list");
+ RNA_def_property_struct_type(prop, "PointCacheItem");
+ RNA_def_property_ui_text(prop, "Point Cache List", "");
rna_def_ptcache_point_caches(brna, prop);
}
@@ -1882,7 +1901,7 @@ static void rna_def_softbody(BlenderRNA *brna)
void RNA_def_object_force(BlenderRNA *brna)
{
- rna_def_pointcache(brna);
+ rna_def_pointcache_active(brna);
rna_def_collision(brna);
rna_def_effector_weight(brna);
rna_def_field(brna);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 15487082217..ae774f8d41a 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -91,6 +91,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
{SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
{SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{SCE_PASS_UV, "UV", 0, "UV", ""},
+ {SCE_PASS_ROUGHNESS, "ROUGHNESS", 0, "ROUGHNESS", ""},
{SCE_PASS_EMIT, "EMIT", 0, "Emit", ""},
{SCE_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
{SCE_PASS_DIFFUSE_COLOR, "DIFFUSE", 0, "Diffuse", ""},
@@ -147,7 +148,7 @@ static void engine_unbind_display_space_shader(RenderEngine *UNUSED(engine))
IMB_colormanagement_finish_glsl_draw();
}
-static void engine_update(RenderEngine *engine, Main *bmain, Depsgraph *graph, Scene *scene)
+static void engine_update(RenderEngine *engine, Main *bmain, Scene *scene)
{
extern FunctionRNA rna_RenderEngine_update_func;
PointerRNA ptr;
@@ -159,14 +160,13 @@ static void engine_update(RenderEngine *engine, Main *bmain, Depsgraph *graph, S
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "data", &bmain);
- RNA_parameter_set_lookup(&list, "depsgraph", &graph);
RNA_parameter_set_lookup(&list, "scene", &scene);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
-static void engine_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
+static void engine_render_to_image(RenderEngine *engine, Depsgraph *depsgraph)
{
extern FunctionRNA rna_RenderEngine_render_to_image_func;
PointerRNA ptr;
@@ -183,7 +183,7 @@ static void engine_render_to_image(RenderEngine *engine, struct Depsgraph *depsg
RNA_parameter_list_free(&list);
}
-static void engine_bake(RenderEngine *engine, struct Scene *scene,
+static void engine_bake(RenderEngine *engine, struct Depsgraph *depsgraph, struct Scene *scene,
struct Object *object, const int pass_type, const int pass_filter,
const int object_id, const struct BakePixel *pixel_array,
const int num_pixels, const int depth, void *result)
@@ -197,6 +197,7 @@ static void engine_bake(RenderEngine *engine, struct Scene *scene,
func = &rna_RenderEngine_bake_func;
RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
@@ -398,16 +399,6 @@ static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
}
}
-static PointerRNA rna_RenderEngine_view_layer_get(PointerRNA *ptr)
-{
- RenderEngine *engine = (RenderEngine *)ptr->data;
- if (engine->re != NULL) {
- ViewLayer *view_layer = RE_engine_get_view_layer(engine->re);
- return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer);
- }
- return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, NULL);
-}
-
static PointerRNA rna_RenderEngine_camera_override_get(PointerRNA *ptr)
{
RenderEngine *engine = (RenderEngine *)ptr->data;
@@ -512,17 +503,19 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Export scene data for render");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "data", "BlendData", "", "");
- RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
RNA_def_pointer(func, "scene", "Scene", "", "");
func = RNA_def_function(srna, "render_to_image", NULL);
RNA_def_function_ui_description(func, "Render scene into an image");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- RNA_def_pointer(func, "desgraph", "Depsgraph", "", "");
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "bake", NULL);
RNA_def_function_ui_description(func, "Bake passes");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "scene", "Scene", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "Object", "", "");
@@ -769,11 +762,6 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_enum(func, "type", render_pass_type_items, SOCK_FLOAT, "Type", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "ViewLayer");
- RNA_def_property_pointer_funcs(prop, "rna_RenderEngine_view_layer_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Scene layer", "");
-
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index bc85e9c6503..ae325651a31 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -802,6 +802,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
+ RNA_def_property_struct_type(prop, "PointCache");
RNA_def_property_ui_text(prop, "Point Cache", "");
/* effector weights */
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 8cf9bc7d39c..9c043c3563a 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1458,6 +1458,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
if (propname != NULL) {
propname_a = RNA_property_string_get_alloc(&iter_a.ptr, propname, propname_buff_a, sizeof(propname_buff_a), NULL);
propname_b = RNA_property_string_get_alloc(&iter_b.ptr, propname, propname_buff_b, sizeof(propname_buff_b), NULL);
+ }
+ /* There may be a propname defined in some cases, while no actual name set
+ * (e.g. happens with point cache), in that case too we want to fall back to index. */
+ if ((propname_a != NULL && propname_a[0] != '\0') || (propname_b != NULL && propname_b[0] != '\0')) {
if (!STREQ(propname_a, propname_b)) {
/* Same as above, not same structs. */
equals = false;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 2c3f90d718b..955cc5cc884 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -1469,11 +1469,11 @@ static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr)
static void rna_Physics_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- FOREACH_SCENE_OBJECT(scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value)
@@ -1545,11 +1545,11 @@ static void rna_Scene_use_simplify_update(Main *UNUSED(bmain), Scene *UNUSED(sce
Scene *sce_iter;
Base *base;
- FOREACH_SCENE_OBJECT(sce, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
{
object_simplify_update(ob);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
for (SETLOOPER_SET_ONLY(sce, sce_iter, base)) {
object_simplify_update(base->object);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index f99803a1d99..212578cf3f0 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -290,70 +290,6 @@ static void rna_Scene_alembic_export(
#endif
-#ifdef WITH_COLLADA
-/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
-#include "../../collada/collada.h"
-
-/* Note: This definition must match to the generated function call */
-static void rna_Scene_collada_export(
- Scene *scene,
- bContext *C,
- const char *filepath,
- int apply_modifiers,
-
- int export_mesh_type,
- int selected,
- int include_children,
- int include_armatures,
- int include_shapekeys,
- int deform_bones_only,
- int active_uv_only,
- int include_material_textures,
- int use_texture_copies,
- int triangulate,
- int use_object_instantiation,
- int use_blender_profile,
- int sort_by_name,
- int export_transformation_type,
- int open_sim,
- int limit_precision,
- int keep_bind_info)
-{
- EvaluationContext eval_ctx;
-
- CTX_data_eval_ctx(C, &eval_ctx);
-
- collada_export(&eval_ctx,
- scene,
- CTX_data_view_layer(C),
- filepath,
-
- apply_modifiers,
- export_mesh_type,
-
- selected,
- include_children,
- include_armatures,
- include_shapekeys,
- deform_bones_only,
-
- active_uv_only,
- include_material_textures,
- use_texture_copies,
-
- triangulate,
- use_object_instantiation,
- use_blender_profile,
- sort_by_name,
-
- export_transformation_type,
- open_sim,
- limit_precision,
- keep_bind_info);
-}
-
-#endif
-
#else
void RNA_api_scene(StructRNA *srna)
@@ -412,67 +348,6 @@ void RNA_api_scene(StructRNA *srna)
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_function_output(func, parm);
-#ifdef WITH_COLLADA
- /* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
- func = RNA_def_function(srna, "collada_export", "rna_Scene_collada_export");
- parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Collada file");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
-
- RNA_def_boolean(func, "apply_modifiers", false,
- "Apply Modifiers", "Apply modifiers to exported mesh (non destructive))");
-
- RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
- "Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
-
- RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements");
-
- RNA_def_boolean(func, "include_children", false,
- "Include Children", "Export all children of selected objects (even if not selected)");
-
- RNA_def_boolean(func, "include_armatures", false,
- "Include Armatures", "Export related armatures (even if not selected)");
-
- RNA_def_boolean(func, "include_shapekeys", true, "Include Shape Keys", "Export all Shape Keys from Mesh Objects");
-
- RNA_def_boolean(func, "deform_bones_only", false,
- "Deform Bones only", "Only export deforming bones with armatures");
-
- RNA_def_boolean(func, "active_uv_only", false, "Only Selected UV Map", "Export only the selected UV Map");
-
- RNA_def_boolean(func, "include_material_textures", false,
- "Include Material Textures", "Export textures assigned to the object Materials");
-
- RNA_def_boolean(func, "use_texture_copies", true,
- "Copy", "Copy textures to same folder where the .dae file is exported");
-
- RNA_def_boolean(func, "triangulate", true, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
-
- RNA_def_boolean(func, "use_object_instantiation", true,
- "Use Object Instances", "Instantiate multiple Objects from same Data");
-
- RNA_def_boolean(func, "use_blender_profile", true, "Use Blender Profile",
- "Export additional Blender specific information (for material, shaders, bones, etc.)");
-
- RNA_def_boolean(func, "sort_by_name", false, "Sort by Object name", "Sort exported data by Object name");
-
- RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
- "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
-
- RNA_def_boolean(func, "open_sim", false,
- "Export to SL/OpenSim", "Compatibility mode for SL, OpenSim and other compatible online worlds");
-
- RNA_def_boolean(func, "limit_precision", false,
- "Limit Precision",
- "Reduce the precision of the exported data to 6 digits");
-
- RNA_def_boolean(func, "keep_bind_info", false,
- "Keep Bind Info",
- "Store bind pose information in custom bone properties for later use during Collada export");
-
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-
-#endif
#ifdef WITH_ALEMBIC
/* XXX Deprecated, will be removed in 2.8 in favour of calling the export operator. */
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 1d0fa7a311c..cfd6d0c6db3 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -75,6 +75,7 @@ const EnumPropertyItem rna_enum_sequence_modifier_type_items[] = {
#include "BKE_report.h"
#include "BKE_idprop.h"
+#include "BKE_movieclip.h"
#include "WM_api.h"
@@ -1085,6 +1086,13 @@ static void rna_Sequence_modifier_clear(Sequence *seq, bContext *C)
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
+static float rna_Sequence_fps_get(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ Sequence *seq = (Sequence *)(ptr->data);
+ return BKE_sequence_get_fps(scene, seq);
+}
+
#else
static void rna_def_strip_element(BlenderRNA *brna)
@@ -1840,6 +1848,16 @@ static void rna_def_color_management(StructRNA *srna)
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
}
+static void rna_def_movie_types(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "fps", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "FPS", "Frames per second");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_Sequence_fps_get", NULL, NULL);
+}
+
static void rna_def_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1939,6 +1957,7 @@ static void rna_def_scene(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
+ rna_def_movie_types(srna);
}
static void rna_def_movie(BlenderRNA *brna)
@@ -1999,6 +2018,7 @@ static void rna_def_movie(BlenderRNA *brna)
rna_def_proxy(srna);
rna_def_input(srna);
rna_def_color_management(srna);
+ rna_def_movie_types(srna);
}
static void rna_def_movieclip(BlenderRNA *brna)
@@ -2024,6 +2044,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_input(srna);
+ rna_def_movie_types(srna);
}
static void rna_def_mask(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 4c5c584b16b..8fe97885f49 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -364,6 +364,42 @@ static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values)
#endif
}
+static void rna_SmokeModifier_temperature_grid_get(PointerRNA *ptr, float *values)
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_SmokeModifier_grid_get_length(ptr, length);
+ float *flame;
+
+ BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
+ flame = smoke_turbulence_get_flame(sds->wt);
+ }
+ else {
+ flame = smoke_get_flame(sds->fluid);
+ }
+
+ if (flame) {
+ /* Output is such that 0..1 maps to 0..1000K */
+ float offset = sds->flame_ignition;
+ float scale = sds->flame_max_temp - sds->flame_ignition;
+
+ for (int i = 0; i < size; i++) {
+ values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+#else
+ UNUSED_VARS(ptr, values);
+#endif
+}
+
static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
@@ -588,6 +624,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]");
+ RNA_def_property_struct_type(prop, "PointCache");
RNA_def_property_ui_text(prop, "Point Cache", "");
prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE);
@@ -679,6 +716,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SmokeModifier_heat_grid_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
+ prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_SmokeModifier_temperature_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K");
+
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
@@ -856,6 +901,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorRamp");
RNA_def_property_ui_text(prop, "Color Ramp", "");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clipping");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Clipping",
+ "Value under which voxels are considered empty space to optimize caching or rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index e88f79eda18..bb4f6719fbc 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -267,6 +267,13 @@ static StructRNA *rna_Panel_register(
else
BLI_addtail(&art->paneltypes, pt);
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(pt->owner_id, owner_id, sizeof(pt->owner_id));
+ }
+ }
+
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -774,6 +781,13 @@ static StructRNA *rna_Menu_register(
mt->poll = (have_function[0]) ? menu_poll : NULL;
mt->draw = (have_function[1]) ? menu_draw : NULL;
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(mt->owner_id, owner_id, sizeof(mt->owner_id));
+ }
+ }
+
WM_menutype_add(mt);
/* update while blender is running */
@@ -1024,6 +1038,10 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "type->category");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
@@ -1299,6 +1317,10 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
RNA_define_verify_sdna(1);
}
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index dca4fa3822d..5110f4cc27a 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -785,11 +785,10 @@ static void rna_Window_view_layer_update(struct bContext *C, PointerRNA *ptr)
Scene *scene = WM_window_get_active_scene(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
- Object *obedit = CTX_data_edit_object(C);
-
+ Object *obact = OBACT(view_layer);
eObjectMode object_mode = workspace->object_mode;
- if (obedit) {
- ED_object_editmode_exit(C, EM_FREEDATA);
+ if (obact && (object_mode & OB_MODE_EDIT)) {
+ ED_object_editmode_exit_ex(NULL, workspace, scene, obact, EM_FREEDATA);
}
workspace->object_mode = object_mode;
ED_object_base_activate(C, view_layer->basact);
@@ -2254,6 +2253,10 @@ static void rna_def_keyconfig(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "Name of the key map");
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "owner_id");
+ RNA_def_property_ui_text(prop, "Owner", "Internal owner");
+
prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spaceid");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c
index d6de12407b0..bb40a12f5d5 100644
--- a/source/blender/makesrna/intern/rna_wm_manipulator.c
+++ b/source/blender/makesrna/intern/rna_wm_manipulator.c
@@ -806,6 +806,13 @@ static StructRNA *rna_ManipulatorGroup_register(
wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_append_ptr(
BPY_RNA_manipulatorgroup_wrapper, (void *)&dummywgt);
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(wgt->owner_id, owner_id, sizeof(wgt->owner_id));
+ }
+ }
+
if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) {
WM_manipulator_group_type_add_ptr_ex(wgt, mmap_type);
@@ -1204,6 +1211,10 @@ static void rna_def_manipulatorgroup(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Region Type", "The region where the panel is going to be used in");
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
/* bl_options */
static EnumPropertyItem manipulatorgroup_flag_items[] = {
{WM_MANIPULATORGROUPTYPE_3D, "3D", 0, "3D",
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 5e0a4b97981..7ac4134f02b 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -52,6 +52,10 @@
#include "RNA_access.h"
+static void rna_window_update_all(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_WINDOW, NULL);
+}
void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
@@ -79,8 +83,94 @@ static PointerRNA rna_workspace_transform_orientations_item_get(CollectionProper
return rna_pointer_inherit_refine(&iter->parent, &RNA_TransformOrientation, transform_orientation);
}
+/* workspace.owner_ids */
+
+static wmOwnerID *rna_WorkSpace_owner_ids_new(
+ WorkSpace *workspace, const char *name)
+{
+ wmOwnerID *owner_id = MEM_callocN(sizeof(*owner_id), __func__);
+ BLI_addtail(&workspace->owner_ids, owner_id);
+ BLI_strncpy(owner_id->name, name, sizeof(owner_id->name));
+ WM_main_add_notifier(NC_WINDOW, NULL);
+ return owner_id;
+}
+
+static void rna_WorkSpace_owner_ids_remove(
+ WorkSpace *workspace, ReportList *reports, PointerRNA *wstag_ptr)
+{
+ wmOwnerID *owner_id = wstag_ptr->data;
+ if (BLI_remlink_safe(&workspace->owner_ids, owner_id) == false) {
+ BKE_reportf(reports, RPT_ERROR,
+ "wmOwnerID '%s' not in workspace '%s'",
+ owner_id->name, workspace->id.name + 2);
+ return;
+ }
+
+ MEM_freeN(owner_id);
+ RNA_POINTER_INVALIDATE(wstag_ptr);
+
+ WM_main_add_notifier(NC_WINDOW, NULL);
+}
+
+static void rna_WorkSpace_owner_ids_clear(
+ WorkSpace *workspace)
+{
+ BLI_freelistN(&workspace->owner_ids);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace);
+}
+
#else /* RNA_RUNTIME */
+static void rna_def_workspace_owner(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "wmOwnerID", NULL);
+ RNA_def_struct_sdna(srna, "wmOwnerID");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Work Space UI Tag", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_struct_name_property(srna, prop);
+}
+
+static void rna_def_workspace_owner_ids(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "wmOwnerIDs");
+ srna = RNA_def_struct(brna, "wmOwnerIDs", NULL);
+ RNA_def_struct_sdna(srna, "WorkSpace");
+ RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", "");
+
+ /* add owner_id */
+ func = RNA_def_function(srna, "new", "rna_WorkSpace_owner_ids_new");
+ RNA_def_function_ui_description(func, "Add ui tag");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the tag");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "");
+ RNA_def_function_return(func, parm);
+
+ /* remove owner_id */
+ func = RNA_def_function(srna, "remove", "rna_WorkSpace_owner_ids_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove ui tag");
+ /* owner_id to remove */
+ parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "Tag to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* clear all modifiers */
+ func = RNA_def_function(srna, "clear", "rna_WorkSpace_owner_ids_clear");
+ RNA_def_function_ui_description(func, "Remove all tags");
+}
+
static void rna_def_workspace(BlenderRNA *brna)
{
StructRNA *srna;
@@ -121,6 +211,11 @@ static void rna_def_workspace(BlenderRNA *brna)
"rna_workspace_transform_orientations_item_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Transform Orientations", "");
+ prop = RNA_def_property(srna, "owner_ids", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "wmOwnerID");
+ RNA_def_property_ui_text(prop, "UI Tags", "");
+ rna_def_workspace_owner_ids(brna, prop);
+
prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Object interaction mode used in this window");
@@ -138,6 +233,13 @@ static void rna_def_workspace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scene Settings",
"Use scene settings instead of workspace settings");
RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_by_owner", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", WORKSPACE_USE_FILTER_BY_ORIGIN);
+ RNA_def_property_ui_text(prop, "Use UI Tags",
+ "Filter the UI by tags");
+ RNA_def_property_update(prop, 0, "rna_window_update_all");
}
static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -160,6 +262,7 @@ static void rna_def_transform_orientation(BlenderRNA *brna)
void RNA_def_workspace(BlenderRNA *brna)
{
+ rna_def_workspace_owner(brna);
rna_def_workspace(brna);
rna_def_transform_orientation(brna);
}
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 60c7998853e..f6640704a83 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -97,16 +97,12 @@ static void foreachObjectLink(
walk(userData, ob, &amd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ArmatureModifierData *amd = (ArmatureModifierData *)md;
if (amd->object != NULL) {
- DEG_add_object_relation(node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
- DEG_add_object_relation(node, amd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier");
+ DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
+ DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 91501e539c0..f598667f96d 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -51,6 +51,7 @@
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
+#include "BKE_object_deform.h"
#include "MOD_util.h"
@@ -96,26 +97,22 @@ static void foreachObjectLink(
walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ArrayModifierData *amd = (ArrayModifierData *)md;
if (amd->start_cap != NULL) {
- DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
+ DEG_add_object_relation(ctx->node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
}
if (amd->end_cap != NULL) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
+ DEG_add_object_relation(ctx->node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
}
if (amd->curve_ob) {
- struct Depsgraph *depsgraph = DEG_get_graph_from_handle(node);
- DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
+ struct Depsgraph *depsgraph = DEG_get_graph_from_handle(ctx->node);
+ DEG_add_object_relation(ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
DEG_add_special_eval_flag(depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
}
if (amd->offset_ob != NULL) {
- DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
+ DEG_add_object_relation(ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
}
}
@@ -279,7 +276,7 @@ static void dm_mvert_map_doubles(
static void dm_merge_transform(
DerivedMesh *result, DerivedMesh *cap_dm, float cap_offset[4][4],
unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index,
- int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys)
+ int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys, int *remap, int remap_len)
{
int *index_orig;
int i;
@@ -287,6 +284,7 @@ static void dm_merge_transform(
MEdge *me;
MLoop *ml;
MPoly *mp;
+ MDeformVert *dvert;
/* needed for subsurf so arrays are allocated */
cap_dm->getVertArray(cap_dm);
@@ -307,6 +305,12 @@ static void dm_merge_transform(
mv->flag = mv->bweight = 0;
}
+ /* remap the vertex groups if necessary */
+ dvert = DM_get_vert_data(result, cap_verts_index, CD_MDEFORMVERT);
+ if (dvert != NULL) {
+ BKE_object_defgroup_index_map_apply(dvert, cap_nverts, remap, remap_len);
+ }
+
/* adjust cap edge vertex indices */
me = CDDM_get_edges(result) + cap_edges_index;
for (i = 0; i < cap_nedges; i++, me++) {
@@ -383,6 +387,11 @@ static DerivedMesh *arrayModifier_doArray(
DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL;
+ int *vgroup_start_cap_remap = NULL;
+ int vgroup_start_cap_remap_len = 0;
+ int *vgroup_end_cap_remap = NULL;
+ int vgroup_end_cap_remap_len = 0;
+
chunk_nverts = dm->getNumVerts(dm);
chunk_nedges = dm->getNumEdges(dm);
chunk_nloops = dm->getNumLoops(dm);
@@ -391,6 +400,8 @@ static DerivedMesh *arrayModifier_doArray(
count = amd->count;
if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) {
+ vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(amd->start_cap, ob, &vgroup_start_cap_remap_len);
+
start_cap_dm = get_dm_for_modifier(amd->start_cap, flag);
if (start_cap_dm) {
start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm);
@@ -400,6 +411,8 @@ static DerivedMesh *arrayModifier_doArray(
}
}
if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) {
+ vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(amd->end_cap, ob, &vgroup_end_cap_remap_len);
+
end_cap_dm = get_dm_for_modifier(amd->end_cap, flag);
if (end_cap_dm) {
end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm);
@@ -656,7 +669,8 @@ static DerivedMesh *arrayModifier_doArray(
result_nedges - start_cap_nedges - end_cap_nedges,
result_nloops - start_cap_nloops - end_cap_nloops,
result_npolys - start_cap_npolys - end_cap_npolys,
- start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys);
+ start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys,
+ vgroup_start_cap_remap, vgroup_start_cap_remap_len);
/* Identify doubles with first chunk */
if (use_merge) {
dm_mvert_map_doubles(
@@ -680,7 +694,8 @@ static DerivedMesh *arrayModifier_doArray(
result_nedges - end_cap_nedges,
result_nloops - end_cap_nloops,
result_npolys - end_cap_npolys,
- end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys);
+ end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys,
+ vgroup_end_cap_remap, vgroup_end_cap_remap_len);
/* Identify doubles with last chunk */
if (use_merge) {
dm_mvert_map_doubles(
@@ -728,6 +743,13 @@ static DerivedMesh *arrayModifier_doArray(
result->dirty |= DM_DIRTY_NORMALS;
}
+ if (vgroup_start_cap_remap) {
+ MEM_freeN(vgroup_start_cap_remap);
+ }
+ if (vgroup_end_cap_remap) {
+ MEM_freeN(vgroup_end_cap_remap);
+ }
+
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 7f79c941770..c9d762a7fbe 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -95,19 +95,15 @@ static void foreachObjectLink(
walk(userData, ob, &bmd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
if (bmd->object != NULL) {
- DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
- DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
+ DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+ DEG_add_object_relation(ctx->node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
}
/* We need own transformation as well. */
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
}
static DerivedMesh *get_quick_derivedMesh(
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 93a5b9607bf..bf86377960a 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -102,16 +102,12 @@ static void foreachObjectLink(
walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *object,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
CastModifierData *cmd = (CastModifierData *)md;
if (cmd->object != NULL) {
- DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
- DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index b234cc63228..0c55d8f8beb 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -114,18 +114,14 @@ static void deformVerts(ModifierData *md, const struct EvaluationContext *eval_c
dm->release(dm);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *scene,
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ClothModifierData *clmd = (ClothModifierData *)md;
if (clmd != NULL) {
/* Actual code uses get_collisionobjects */
- DEG_add_collision_relations(node, scene, ob, clmd->coll_parms->group, eModifierType_Collision, NULL, true, "Cloth Collision");
+ DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, clmd->coll_parms->group, eModifierType_Collision, NULL, true, "Cloth Collision");
- DEG_add_forcefield_relations(node, scene, ob, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
+ DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
}
}
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 62c9f8796a0..acb69de1e85 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -93,11 +93,7 @@ static void foreachObjectLink(
walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *object,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
CurveModifierData *cmd = (CurveModifierData *)md;
if (cmd->object != NULL) {
@@ -107,12 +103,12 @@ static void updateDepsgraph(ModifierData *md,
/* TODO(sergey): Currently path is evaluated as a part of modifier stack,
* might be changed in the future.
*/
- struct Depsgraph *depsgraph = DEG_get_graph_from_handle(node);
- DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
+ struct Depsgraph *depsgraph = DEG_get_graph_from_handle(ctx->node);
+ DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
DEG_add_special_eval_flag(depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
}
- DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Curve Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Curve Modifier");
}
static void deformVerts(ModifierData *md, const struct EvaluationContext *UNUSED(eval_ctx),
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index e7069937868..a804a35954c 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -125,15 +125,11 @@ static void foreachObjectLink(
walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
if (dtmd->ob_source != NULL) {
- DEG_add_object_relation(node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
+ DEG_add_object_relation(ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 53a77b6fe38..f90e6cc1d36 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -154,21 +154,17 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DisplaceModifierData *dmd = (DisplaceModifierData *)md;
if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ DEG_add_object_relation(ctx->node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
(ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
dmd->space == MOD_DISP_SPACE_GLOBAL))
{
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index da5d9a29be5..914b4101760 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -132,22 +132,18 @@ static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd)
return ((DynamicPaintModifierData *)pmd)->brush != NULL;
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *scene,
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
/* Add relation from canvases to all brush objects. */
if (pmd->canvas != NULL) {
for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- DEG_add_forcefield_relations(node, scene, ob, surface->effector_weights, true, 0, "Dynamic Paint Field");
+ DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, surface->effector_weights, true, 0, "Dynamic Paint Field");
}
/* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */
- DEG_add_collision_relations(node, scene, ob, surface->brush_group, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
+ DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, surface->brush_group, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index 75f57de2a37..403a8706295 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -103,28 +103,24 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
return result ? result : dm;
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *scene,
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
if (fluidmd && fluidmd->fss) {
if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- FOREACH_SCENE_OBJECT(scene, ob1)
+ FOREACH_SCENE_OBJECT_BEGIN(ctx->scene, ob1)
{
- if (ob1 != ob) {
+ if (ob1 != ctx->object) {
FluidsimModifierData *fluidmdtmp =
(FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
/* Only put dependencies from NON-DOMAIN fluids in here. */
if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
- DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
+ DEG_add_object_relation(ctx->node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
}
}
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 25617c84dac..00abcc1c65c 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -116,21 +116,17 @@ static void foreachObjectLink(
walk(userData, ob, &hmd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
HookModifierData *hmd = (HookModifierData *)md;
if (hmd->object != NULL) {
if (hmd->subtarget[0]) {
- DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
+ DEG_add_bone_relation(ctx->node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
}
- DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ DEG_add_object_relation(ctx->node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
/* We need own transformation as well. */
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
struct HookData_cb {
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index cd8b6139d75..4bf52f552ce 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -89,18 +89,14 @@ static void foreachObjectLink(
walk(userData, ob, &lmd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *object,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
LatticeModifierData *lmd = (LatticeModifierData *)md;
if (lmd->object != NULL) {
- DEG_add_object_relation(node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
- DEG_add_object_relation(node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
}
- DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
}
static void deformVerts(ModifierData *md, const struct EvaluationContext *UNUSED(eval_ctx),
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index bcebbc40adb..080dc371508 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -78,18 +78,14 @@ static void foreachObjectLink(
walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MaskModifierData *mmd = (MaskModifierData *)md;
if (mmd->ob_arm) {
bArmature *arm = (bArmature *)mmd->ob_arm->data;
/* Tag relationship in depsgraph, but also on the armature. */
/* TODO(sergey): Is it a proper relation here? */
- DEG_add_object_relation(node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
+ DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
arm->flag |= ARM_HAS_VIZ_DEPS;
}
}
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index e8fc832b597..a2ca9bde124 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -122,16 +122,12 @@ static void foreachObjectLink(
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
if (mmd->object != NULL) {
/* TODO(sergey): Do we need transform component here? */
- DEG_add_object_relation(node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
+ DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index e28459814e2..02021c44749 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -173,19 +173,13 @@ static void foreachIDLink(ModifierData *md, Object *ob,
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *bmain,
- struct Scene *scene,
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
if (mcmd->cache_file != NULL) {
- DEG_add_object_cache_relation(node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
+ DEG_add_object_cache_relation(ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
}
-
- UNUSED_VARS(bmain, scene, ob);
}
ModifierTypeInfo modifierType_MeshSequenceCache = {
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 1b725e335a4..62de2711b3d 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -76,17 +76,13 @@ static void foreachObjectLink(
walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MirrorModifierData *mmd = (MirrorModifierData *)md;
if (mmd->mirror_ob != NULL) {
- DEG_add_object_relation(node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ DEG_add_object_relation(ctx->node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
}
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
}
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 61a5b9bb03e..4fc49234468 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -509,15 +509,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return !is_valid_target(enmd);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
NormalEditModifierData *enmd = (NormalEditModifierData *) md;
if (enmd->target) {
- DEG_add_object_relation(node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
+ DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 09966da13a2..81f52304b8f 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -111,15 +111,11 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
return false;
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
if (pimd->ob != NULL) {
- DEG_add_object_relation(node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier");
+ DEG_add_object_relation(ctx->node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 979dc339e4e..5f30b762275 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -1117,15 +1117,11 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte
return result;
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ScrewModifierData *ltmd = (ScrewModifierData *)md;
if (ltmd->ob_axis != NULL) {
- DEG_add_object_relation(node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
+ DEG_add_object_relation(ctx->node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 8b9a7c42eb2..e1df65dd748 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -142,20 +142,16 @@ static void deformVertsEM(ModifierData *md, const struct EvaluationContext *eval
dm->release(dm);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
if (smd->target != NULL) {
- DEG_add_object_relation(node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
- DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
}
if (smd->auxTarget != NULL) {
- DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
- DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 6116e49d07d..8590deb508a 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -375,15 +375,11 @@ static void foreachObjectLink(
walk(userData, ob, &smd->origin, IDWALK_CB_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
if (smd->origin != NULL) {
- DEG_add_object_relation(node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
+ DEG_add_object_relation(ctx->node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index d2d8da289b7..4afe6ca33e2 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1304,9 +1304,9 @@ static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_f
else if (split_face->len > 4) {
/* Maintain a dynamic vert array containing the split_face's
* vertices, avoids frequent allocs in collapse_face_corners() */
- if (BLI_array_count(vert_buf) < split_face->len) {
+ if (BLI_array_len(vert_buf) < split_face->len) {
BLI_array_grow_items(vert_buf, (split_face->len -
- BLI_array_count(vert_buf)));
+ BLI_array_len(vert_buf)));
}
/* Get split face's verts */
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 9881d7ee9b9..e610ef5f78d 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -131,20 +131,16 @@ static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md)
return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll;
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *scene,
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
SmokeModifierData *smd = (SmokeModifierData *)md;
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
/* Actual code uses get_collisionobjects */
- DEG_add_collision_relations(node, scene, ob, smd->domain->fluid_group, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
- DEG_add_collision_relations(node, scene, ob, smd->domain->coll_group, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
+ DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, smd->domain->fluid_group, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
+ DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, smd->domain->coll_group, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
- DEG_add_forcefield_relations(node, scene, ob, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
+ DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
}
}
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index d0b1d7361cc..8d5217391af 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -63,17 +63,13 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static void updateDepsgraph(ModifierData *UNUSED(md),
- struct Main *UNUSED(bmain),
- struct Scene *scene,
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx)
{
- if (ob->soft) {
+ if (ctx->object->soft) {
/* Actual code uses ccd_build_deflector_hash */
- DEG_add_collision_relations(node, scene, ob, ob->soft->collision_group, eModifierType_Collision, NULL, false, "Softbody Collision");
+ DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, ctx->object->soft->collision_group, eModifierType_Collision, NULL, false, "Softbody Collision");
- DEG_add_forcefield_relations(node, scene, ob, ob->soft->effector_weights, true, 0, "Softbody Field");
+ DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field");
}
}
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 85347288872..e7f283c4a31 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -170,15 +170,11 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
walk(userData, ob, &smd->target, IDWALK_NOP);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
if (smd->target != NULL) {
- DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier");
+ DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 498dd2486f4..02f799fecb9 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -109,17 +109,13 @@ static void foreachIDLink(ModifierData *md, Object *ob,
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
UVProjectModifierData *umd = (UVProjectModifierData *)md;
int i;
for (i = 0; i < umd->num_projectors; ++i) {
if (umd->projectors[i] != NULL) {
- DEG_add_object_relation(node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
+ DEG_add_object_relation(ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 32974d68d9d..8af9fd6cde4 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -232,9 +232,9 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
}
-static void uv_warp_deps_object_bone(struct DepsNodeHandle *node,
- Object *object,
- const char *bonename)
+static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node,
+ Object *object,
+ const char *bonename)
{
if (object != NULL) {
if (bonename[0])
@@ -244,16 +244,12 @@ static void uv_warp_deps_object_bone(struct DepsNodeHandle *node,
}
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- uv_warp_deps_object_bone(node, umd->object_src, umd->bone_src);
- uv_warp_deps_object_bone(node, umd->object_dst, umd->bone_dst);
+ uv_warp_deps_object_bone_new(ctx->node, umd->object_src, umd->bone_src);
+ uv_warp_deps_object_bone_new(ctx->node, umd->object_dst, umd->bone_dst);
}
ModifierTypeInfo modifierType_UVWarp = {
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index be0be2671b9..204e344b8e1 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -137,19 +137,15 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "texture");
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WarpModifierData *wmd = (WarpModifierData *) md;
if (wmd->object_from != NULL && wmd->object_to != NULL) {
- DEG_add_object_relation(node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
- DEG_add_object_relation(node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
+ DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
+ DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
}
if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
- DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
+ DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
}
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 1271cccd719..33b2d904c23 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -127,18 +127,14 @@ static void foreachTexLink(ModifierData *md, Object *ob,
walk(userData, ob, md, "texture");
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WaveModifierData *wmd = (WaveModifierData *)md;
if (wmd->objectcenter != NULL) {
- DEG_add_object_relation(node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
}
if (wmd->map_object != NULL) {
- DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 9aa4bad1707..23f36d3bc4c 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -140,18 +140,14 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index ab1264cc9a0..1947e7e1f0f 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -189,20 +189,16 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
- DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
+ DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
- DEG_add_object_relation(node, ob, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 8a5d0f833a8..87c6a03a536 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -350,24 +350,20 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepsgraph(ModifierData *md,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *ob,
- struct DepsNodeHandle *node)
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
if (wmd->proximity_ob_target != NULL) {
- DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
- DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
- DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
- DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
- DEG_add_object_relation(node, ob, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 230918776dc..ee70fcf510f 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -212,6 +212,7 @@ set(SRC
shader/nodes/node_shader_tex_wave.c
shader/nodes/node_shader_volume_scatter.c
shader/nodes/node_shader_volume_absorption.c
+ shader/nodes/node_shader_volume_principled.c
shader/nodes/node_shader_uvAlongStroke.c
shader/nodes/node_shader_uvmap.c
shader/node_shader_tree.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index bb9f9881e33..a507fdbd787 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -114,6 +114,7 @@ void register_node_type_sh_emission(void);
void register_node_type_sh_holdout(void);
void register_node_type_sh_volume_absorption(void);
void register_node_type_sh_volume_scatter(void);
+void register_node_type_sh_volume_principled(void);
void register_node_type_sh_bsdf_hair(void);
void register_node_type_sh_subsurface_scattering(void);
void register_node_type_sh_mix_shader(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 394e141647e..44713a7a000 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -93,6 +93,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BS
DefNode( ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","")
DefNode( ShaderNode, SH_NODE_VOLUME_ABSORPTION, 0, "VOLUME_ABSORPTION", VolumeAbsorption, "Volume Absorption", "" )
DefNode( ShaderNode, SH_NODE_VOLUME_SCATTER, 0, "VOLUME_SCATTER", VolumeScatter, "Volume Scatter", "" )
+DefNode( ShaderNode, SH_NODE_VOLUME_PRINCIPLED, 0, "PRINCIPLED_VOLUME", VolumePrincipled, "Principled Volume", "" )
DefNode( ShaderNode, SH_NODE_EMISSION, 0, "EMISSION", Emission, "Emission", "" )
DefNode( ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NEW_GEOMETRY", NewGeometry, "Geometry", "" )
DefNode( ShaderNode, SH_NODE_LIGHT_PATH, 0, "LIGHT_PATH", LightPath, "Light Path", "" )
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 8559765e315..22171f28790 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -147,7 +147,6 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
zero_v4(gs->vec);
gs->link = NULL;
gs->type = GPU_NONE;
- gs->name = "";
gs->hasinput = false;
gs->hasoutput = false;
gs->sockettype = type;
@@ -167,7 +166,6 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
else
gs->type = GPU_NONE;
- gs->name = "";
gs->hasinput = ns->hasinput && ns->data;
/* XXX Commented out the ns->data check here, as it seems it's not always set,
* even though there *is* a valid connection/output... But that might need
@@ -193,7 +191,7 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS
for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
- gs[i].type = GPU_NONE;
+ gs[i].end = true;
}
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index 5f3699e52eb..0ea1348df05 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -59,6 +59,11 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecDat
return GPU_stack_link(mat, node, "node_attribute_volume_flame", in, out,
GPU_builtin(GPU_VOLUME_FLAME));
}
+ else if (strcmp(attr->name, "temperature") == 0) {
+ return GPU_stack_link(mat, node, "node_attribute_volume_temperature", in, out,
+ GPU_builtin(GPU_VOLUME_FLAME),
+ GPU_builtin(GPU_VOLUME_TEMPERATURE));
+ }
else {
GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.c
index af89a959554..28019651926 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.c
@@ -38,6 +38,16 @@ static bNodeSocketTemplate sh_node_blackbody_out[] = {
{ -1, 0, "" }
};
+static int node_shader_gpu_blackbody(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ const int size = 256;
+ float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+
+ blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+
+ return GPU_stack_link(mat, node, "node_blackbody", in, out, GPU_texture(size, data));
+}
+
/* node type definition */
void register_node_type_sh_blackbody(void)
{
@@ -49,6 +59,7 @@ void register_node_type_sh_blackbody(void)
node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_blackbody);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index 13e8ac67f63..ee3db99d2ab 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -31,7 +31,7 @@
static bNodeSocketTemplate sh_node_bsdf_anisotropic_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, N_("Roughness"), 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Anisotropy"), 0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
index 35121b2afed..ad9e7730ad1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
@@ -31,7 +31,7 @@
static bNodeSocketTemplate sh_node_bsdf_glossy_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, N_("Roughness"), 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_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_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 1c291cb5b83..b4a83c847be 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -32,8 +32,8 @@
static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
{ SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- { SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f},
- { SOCK_RGBA, 1, N_("Subsurface Color"), 0.7f, 0.1f, 0.1f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f},
+ { SOCK_RGBA, 1, N_("Subsurface Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
@@ -60,7 +60,7 @@ static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->custom1 = SHD_GLOSSY_MULTI_GGX;
+ node->custom1 = SHD_GLOSSY_GGX;
node->custom2 = SHD_SUBSURFACE_BURLEY;
}
@@ -145,7 +145,7 @@ void register_node_type_sh_bsdf_principled(void)
sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, node_shader_init_principled);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index 116825ff0da..4b4f08a8b56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -32,7 +32,7 @@
static bNodeSocketTemplate sh_node_subsurface_scattering_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- { SOCK_VECTOR, 1, N_("Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f},
+ { SOCK_VECTOR, 1, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f},
{ SOCK_FLOAT, 1, N_("Sharpness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Texture Blur"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
new file mode 100644
index 00000000000..e51833e4474
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
@@ -0,0 +1,165 @@
+/*
+ * ***** 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_volume_principled_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { SOCK_STRING, 1, N_("Color Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_STRING, 1, N_("Density Attribute"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, N_("Absorption Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Emission Strength"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1000.0f},
+ { SOCK_RGBA, 1, N_("Emission Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Blackbody Intensity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, N_("Blackbody Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Temperature"), 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6500.0f},
+ { SOCK_STRING, 1, N_("Temperature Attribute"),0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_volume_principled_out[] = {
+ { SOCK_SHADER, 0, N_("Volume")},
+ { -1, 0, "" }
+};
+
+static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Density Attribute")) {
+ strcpy(((bNodeSocketValueString *)sock->default_value)->value, "density");
+ }
+ else if (STREQ(sock->name, "Temperature Attribute")) {
+ strcpy(((bNodeSocketValueString *)sock->default_value)->value, "temperature");
+ }
+ }
+}
+
+static void node_shader_gpu_volume_attribute(GPUMaterial *mat, const char *name, GPUNodeLink **outcol, GPUNodeLink **outvec, GPUNodeLink **outf)
+{
+ if (strcmp(name, "density") == 0) {
+ GPU_link(mat, "node_attribute_volume_density",
+ GPU_builtin(GPU_VOLUME_DENSITY),
+ outcol, outvec, outf);
+ }
+ else if (strcmp(name, "color") == 0) {
+ GPU_link(mat, "node_attribute_volume_color",
+ GPU_builtin(GPU_VOLUME_DENSITY),
+ outcol, outvec, outf);
+ }
+ else if (strcmp(name, "flame") == 0) {
+ GPU_link(mat, "node_attribute_volume_flame",
+ GPU_builtin(GPU_VOLUME_FLAME),
+ outcol, outvec, outf);
+ }
+ else if (strcmp(name, "temperature") == 0) {
+ GPU_link(mat, "node_attribute_volume_temperature",
+ GPU_builtin(GPU_VOLUME_FLAME),
+ GPU_builtin(GPU_VOLUME_TEMPERATURE),
+ outcol, outvec, outf);
+ }
+ else {
+ *outcol = *outvec = *outf = NULL;
+ }
+}
+
+static int node_shader_gpu_volume_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ /* Test if blackbody intensity is enabled. */
+ bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f);
+
+ /* Get volume attributes. */
+ GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL;
+
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (sock->typeinfo->type != SOCK_STRING) {
+ continue;
+ }
+
+ bNodeSocketValueString *value = sock->default_value;
+ GPUNodeLink *outcol, *outvec, *outf;
+
+ if (STREQ(sock->name, "Density Attribute")) {
+ node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &density);
+ }
+ else if (STREQ(sock->name, "Color Attribute")) {
+ node_shader_gpu_volume_attribute(mat, value->value, &color, &outvec, &outf);
+ }
+ else if (use_blackbody && STREQ(sock->name, "Temperature Attribute")) {
+ node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &temperature);
+ }
+ }
+
+ /* Default values if attributes not found. */
+ if (!density) {
+ static float one = 1.0f;
+ density = GPU_uniform(&one);
+ }
+ if (!color) {
+ static float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ color = GPU_uniform(white);
+ }
+ if (!temperature) {
+ static float one = 1.0f;
+ temperature = GPU_uniform(&one);
+ }
+
+ /* Create blackbody spectrum. */
+ GPUNodeLink *spectrummap;
+ if (use_blackbody) {
+ const int size = 256;
+ float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+ spectrummap = GPU_texture(size, data);
+ }
+ else {
+ float *data = MEM_callocN(sizeof(float) * 4, "blackbody black");
+ spectrummap = GPU_texture(1, data);
+ }
+
+ return GPU_stack_link(mat, node, "node_volume_principled", in, out, density, color, temperature, spectrummap);
+}
+
+/* node type definition */
+void register_node_type_sh_volume_principled(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_volume_principled_in, sh_node_volume_principled_out);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, node_shader_init_volume_principled);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_volume_principled);
+
+ nodeRegisterType(&ntype);
+}
+
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
index bce4695af10..dfd7154e6b8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
@@ -32,7 +32,7 @@
static bNodeSocketTemplate sh_node_volume_scatter_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- { SOCK_FLOAT, 1, N_("Anisotropy"),0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Anisotropy"),0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR},
{ -1, 0, "" }
};
diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c
index 4f6b354b7be..3146993d665 100644
--- a/source/blender/python/gawain/gwn_py_types.c
+++ b/source/blender/python/gawain/gwn_py_types.c
@@ -117,7 +117,7 @@ static int bpygwn_ParseVertFetchMode(PyObject *o, void *p)
} \
} ((void)0)
- Gwn_VertCompType mode;
+ Gwn_VertFetchMode mode;
MATCH_ID(FLOAT);
MATCH_ID(INT);
MATCH_ID(INT_TO_FLOAT_UNIT);
@@ -168,7 +168,7 @@ static int bpygwn_ParsePrimType(PyObject *o, void *p)
return 0;
success:
- (*(Gwn_VertFetchMode *)p) = mode;
+ (*(Gwn_PrimType *)p) = mode;
return 1;
}
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 0b791b6acaa..e07fa46424c 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -376,6 +376,9 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, meth_bpy_register_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_register_class, NULL));
PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL));
+ PyModule_AddObject(mod, meth_bpy_owner_id_get.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_get, NULL));
+ PyModule_AddObject(mod, meth_bpy_owner_id_set.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_set, NULL));
+
/* add our own modules dir, this is a python package */
bpy_package_py = bpy_import_test("bpy");
}
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index f44401afd7d..1e2ce372727 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -357,6 +357,11 @@ static PyGetSetDef bpy_app_getsets[] = {
{(char *)"debug_handlers", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_HANDLERS},
{(char *)"debug_wm", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_WM},
{(char *)"debug_depsgraph", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH},
+ {(char *)"debug_depsgraph_build", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_BUILD},
+ {(char *)"debug_depsgraph_eval", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_EVAL},
+ {(char *)"debug_depsgraph_tag", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_TAG},
+ {(char *)"debug_depsgraph_time", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_TIME},
+ {(char *)"debug_depsgraph_pretty", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_PRETTY},
{(char *)"debug_simdata", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA},
{(char *)"debug_gpumem", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM},
diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c
index 945d2a9b6cc..941d6b760dc 100644
--- a/source/blender/python/intern/bpy_msgbus.c
+++ b/source/blender/python/intern/bpy_msgbus.c
@@ -273,7 +273,7 @@ static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args
/* Note: we may want to have a way to pass this in. */
bContext *C = (bContext *)BPy_GetContext();
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- wmMsgParams_RNA msg_key_params = {0};
+ wmMsgParams_RNA msg_key_params = {{{0}}};
wmMsgSubscribeValue msg_val_params = {0};
@@ -349,7 +349,7 @@ static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args,
/* Note: we may want to have a way to pass this in. */
bContext *C = (bContext *)BPy_GetContext();
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- wmMsgParams_RNA msg_key_params = {0};
+ wmMsgParams_RNA msg_key_params = {{{0}}};
if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
return NULL;
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 4ce9ba59a0b..2aff61dc2b8 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -8257,6 +8257,43 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
+/* Access to 'owner_id' internal global. */
+
+static PyObject *pyrna_bl_owner_id_get(PyObject *UNUSED(self))
+{
+ const char *name = RNA_struct_state_owner_get();
+ if (name) {
+ return PyUnicode_FromString(name);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *pyrna_bl_owner_id_set(PyObject *UNUSED(self), PyObject *value)
+{
+ const char *name;
+ if (value == Py_None) {
+ name = NULL;
+ }
+ else if (PyUnicode_Check(value)) {
+ name = _PyUnicode_AsString(value);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "owner_set(...): "
+ "expected None or a string, not '%.200s'", Py_TYPE(value)->tp_name);
+ return NULL;
+ }
+ RNA_struct_state_owner_set(name);
+ Py_RETURN_NONE;
+}
+
+PyMethodDef meth_bpy_owner_id_get = {
+ "_bl_owner_id_get", (PyCFunction)pyrna_bl_owner_id_get, METH_NOARGS, NULL,
+};
+PyMethodDef meth_bpy_owner_id_set = {
+ "_bl_owner_id_set", (PyCFunction)pyrna_bl_owner_id_set, METH_O, NULL,
+};
+
/* currently this is fairly limited, we would need to make some way to split up
* pyrna_callback_classmethod_... if we want more than one callback per type */
typedef struct BPyRNA_CallBack {
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index f666294666e..32a63acde40 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -225,4 +225,8 @@ int pyrna_prop_validity_check(BPy_PropertyRNA *self);
extern PyMethodDef meth_bpy_register_class;
extern PyMethodDef meth_bpy_unregister_class;
+/* bpy.utils._bl_owner_(get/set) */
+extern PyMethodDef meth_bpy_owner_id_set;
+extern PyMethodDef meth_bpy_owner_id_get;
+
#endif
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 924e46a8c00..cc6a5367895 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1710,10 +1710,18 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
/* TODO, different sized matrix */
if (self->num_col == 4 && self->num_row == 4) {
+#ifdef MATH_STANDALONE
+ blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
+#else
interp_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
+#endif
}
else if (self->num_col == 3 && self->num_row == 3) {
+#ifdef MATH_STANDALONE
+ blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
+#else
interp_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
+#endif
}
else {
PyErr_SetString(PyExc_ValueError,
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index fa0d271f7d3..d935949fd8c 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -742,7 +742,7 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
float lambda;
PyObject *ret;
int size = 2;
-
+
if (!PyArg_ParseTuple(
args, "OOO:intersect_point_line",
&py_pt, &py_line_a, &py_line_b))
@@ -760,7 +760,7 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
/* do the calculation */
lambda = closest_to_line_v3(pt_out, pt, line_a, line_b);
-
+
ret = PyTuple_New(2);
PyTuple_SET_ITEMS(ret,
Vector_CreatePyObject(pt_out, size, NULL),
@@ -882,7 +882,7 @@ static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyOb
PyObject *py_pt, *py_quad[4];
float pt[2], quad[4][2];
int i;
-
+
if (!PyArg_ParseTuple(
args, "OOOOO:intersect_point_quad_2d",
&py_pt, UNPACK4_EX(&, py_quad, )))
@@ -954,12 +954,12 @@ PyDoc_STRVAR(M_Geometry_barycentric_transform_doc,
" :type tri_a2: :class:`mathutils.Vector`\n"
" :arg tri_a3: source triangle vertex.\n"
" :type tri_a3: :class:`mathutils.Vector`\n"
-" :arg tri_a1: target triangle vertex.\n"
-" :type tri_a1: :class:`mathutils.Vector`\n"
-" :arg tri_a2: target triangle vertex.\n"
-" :type tri_a2: :class:`mathutils.Vector`\n"
-" :arg tri_a3: target triangle vertex.\n"
-" :type tri_a3: :class:`mathutils.Vector`\n"
+" :arg tri_b1: target triangle vertex.\n"
+" :type tri_b1: :class:`mathutils.Vector`\n"
+" :arg tri_b2: target triangle vertex.\n"
+" :type tri_b2: :class:`mathutils.Vector`\n"
+" :arg tri_b3: target triangle vertex.\n"
+" :type tri_b3: :class:`mathutils.Vector`\n"
" :return: The transformed point\n"
" :rtype: :class:`mathutils.Vector`'s\n"
);
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index f789ab702fe..ad0cb34d382 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -92,9 +92,10 @@ typedef struct RenderEngineType {
char name[64];
int flag;
- void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene);
+ void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene);
void (*render_to_image)(struct RenderEngine *engine, struct Depsgraph *depsgraph);
- void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type,
+ void (*bake)(struct RenderEngine *engine, struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *object, const int pass_type,
const int pass_filter, const int object_id, const struct BakePixel *pixel_array, const int num_pixels,
const int depth, void *result);
@@ -190,9 +191,7 @@ RenderEngineType *RE_engines_find(const char *idname);
rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free);
struct RenderData *RE_engine_get_render_data(struct Render *re);
void RE_bake_engine_set_engine_parameters(
- struct Render *re, struct Main *bmain, struct Depsgraph *graph, struct Scene *scene);
-
-struct ViewLayer *RE_engine_get_view_layer(struct Render *re);
+ struct Render *re, struct Main *bmain, struct Scene *scene);
#endif /* __RE_ENGINE_H__ */
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 0557efccc2f..93ac53cdfcc 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -34,6 +34,7 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+#include "DEG_depsgraph.h"
struct bMovieHandle;
struct bNodeTree;
@@ -121,7 +122,9 @@ typedef struct RenderLayer {
/* optional saved endresult on disk */
void *exrhandle;
-
+
+ struct EvaluationContext eval_ctx;
+
ListBase passes;
} RenderLayer;
@@ -235,6 +238,8 @@ void RE_render_result_rect_from_ibuf(
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname);
+bool RE_HasSingleLayer(struct Render *re);
+
/* add passes for grease pencil */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
@@ -250,7 +255,6 @@ void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
void RE_SetOverrideCamera(struct Render *re, struct Object *camera);
void RE_SetCamera(struct Render *re, struct Object *camera);
-void RE_SetDepsgraph(struct Render *re, struct Depsgraph *graph);
void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend);
void RE_SetWindow(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
@@ -267,7 +271,7 @@ void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
void RE_Database_FromScene(
struct Render *re, struct Main *bmain, struct Scene *scene,
unsigned int lay, int use_camera_view);
-void RE_Database_Preprocess(struct Render *re);
+void RE_Database_Preprocess(struct EvaluationContext *eavl_ctx, struct Render *re);
void RE_Database_Free(struct Render *re);
/* project dbase again, when viewplane/perspective changed */
@@ -368,14 +372,13 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int pas
#define RE_BAKE_VERTEX_COLORS 14
void RE_Database_Baking(
- struct Render *re, struct Main *bmain, struct Scene *scene,
+ struct Render *re, struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
unsigned int lay, const int type, struct Object *actob);
void RE_DataBase_GetView(struct Render *re, float mat[4][4]);
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]);
struct Scene *RE_GetScene(struct Render *re);
-struct EvaluationContext *RE_GetEvalCtx(struct Render *re);
bool RE_force_single_renderlayer(struct Scene *scene);
bool RE_is_rendering_allowed(struct Scene *scene, struct Object *camera_override, struct ReportList *reports);
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index 17b321fd3b4..1a1f455712e 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -38,6 +38,7 @@
/* called by meshtools */
struct DerivedMesh;
+struct EvaluationContext;
struct ImagePool;
struct MTex;
struct Scene;
@@ -55,7 +56,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
void RE_texture_rng_init(void);
void RE_texture_rng_exit(void);
-struct Material *RE_sample_material_init(struct Material *orig_mat, struct Scene *scene);
+struct Material *RE_sample_material_init(const struct EvaluationContext *eval_ctx, struct Material *orig_mat, struct Scene *scene);
void RE_sample_material_free(struct Material *mat);
void RE_sample_material_color(
struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
@@ -71,24 +72,18 @@ void antialias_tagbuf(int xsize, int ysize, char *rectmove);
struct PointDensity;
void RE_point_density_cache(
- struct Scene *scene,
- struct ViewLayer *view_layer,
- struct PointDensity *pd,
- const bool use_render_params);
+ const struct EvaluationContext *eval_ctx,
+ struct PointDensity *pd);
void RE_point_density_minmax(
- struct Scene *scene,
- struct ViewLayer *view_layer,
+ const struct EvaluationContext *eval_ctx,
struct PointDensity *pd,
- const bool use_render_params,
float r_min[3], float r_max[3]);
void RE_point_density_sample(
- struct Scene *scene,
- struct ViewLayer *view_layer,
+ const struct EvaluationContext *eval_ctx,
struct PointDensity *pd,
const int resolution,
- const bool use_render_params,
float *values);
void RE_point_density_free(struct PointDensity *pd);
diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h
index 1d1e808e8d3..f122b3dc4c1 100644
--- a/source/blender/render/intern/include/pointdensity.h
+++ b/source/blender/render/intern/include/pointdensity.h
@@ -37,13 +37,14 @@
* Make point density kd-trees for all point density textures in the scene
*/
+struct EvaluationContext;
struct PointDensity;
struct Render;
struct TexResult;
void free_pointdensity(struct PointDensity *pd);
-void cache_pointdensity(struct Render *re, struct PointDensity *pd);
-void make_pointdensities(struct Render *re);
+void cache_pointdensity(const struct EvaluationContext *eval_ctx, struct Render *re, struct PointDensity *pd);
+void make_pointdensities(const struct EvaluationContext *eval_ctx, struct Render *re);
void free_pointdensities(struct Render *re);
int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 8d293c938c7..03292579d90 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -117,5 +117,28 @@ void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResu
void render_result_views_shallowdelete(struct RenderResult *rr);
bool render_result_has_views(struct RenderResult *rr);
+#define FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re_, iter_) \
+{ \
+ int nr_; \
+ ViewLayer *iter_; \
+ for (nr_ = 0, iter_ = (re_)->view_layers.first; \
+ iter_ != NULL; \
+ iter_ = iter_->next, nr_++) \
+ { \
+ if ((re_)->r.scemode & R_SINGLE_LAYER) { \
+ if (nr_ != re->active_view_layer) { \
+ continue; \
+ } \
+ } \
+ else { \
+ if ((iter_->flag & VIEW_LAYER_RENDER) == 0) { \
+ continue; \
+ } \
+ }
+
+#define FOREACH_VIEW_LAYER_TO_RENDER_END \
+ } \
+} ((void)0)
+
#endif /* __RENDER_RESULT_H__ */
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index d24aae6ac97..2c46138c7ea 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -185,8 +185,6 @@ struct Render {
/* shadow counter, detect shadow-reuse for shaders */
int shadowsamplenr[BLENDER_MAX_THREADS];
-
- struct Depsgraph *depsgraph;
/* main, scene, and its full copy of renderdata and world */
struct Main *main;
@@ -280,7 +278,6 @@ struct Render {
struct ReportList *reports;
struct ImagePool *pool;
- struct EvaluationContext *eval_ctx;
void **movie_ctx_arr;
char viewname[MAX_NAME];
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index b576d69d806..1d1af7092c8 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -40,6 +40,7 @@ extern "C" {
struct Object;
struct VlakRen;
struct VertRen;
+struct EvaluationContext;
struct HaloRen;
struct Main;
struct Material;
@@ -164,7 +165,7 @@ void area_lamp_vectors(struct LampRen *lar);
/* convertblender.c */
void init_render_world(Render *re);
-void RE_Database_FromScene_Vectors(Render *re, struct Main *bmain, struct Scene *sce, unsigned int lay);
+void RE_Database_FromScene_Vectors(struct EvaluationContext *eval_ctx, Render *re, struct Main *bmain, struct Scene *sce, unsigned int lay);
#ifdef __cplusplus
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 503748236f6..0480ffe42d9 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -84,6 +84,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "PIL_time.h"
@@ -1291,9 +1292,9 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int
}
}
}
-static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset)
+static int render_new_particle_system(const EvaluationContext *eval_ctx, Render *re,
+ ObjectRen *obr, ParticleSystem *psys, int timeoffset)
{
- const EvaluationContext *eval_ctx = RE_GetEvalCtx(re);
Object *ob= obr->ob;
// Object *tob=0;
Material *ma = NULL;
@@ -1353,7 +1354,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if (!(psmd->modifier.mode & eModifierMode_Render))
return 0;
- sim.eval_ctx = re->eval_ctx;
+ sim.eval_ctx = eval_ctx;
sim.scene = re->scene;
sim.ob = ob;
sim.psys = psys;
@@ -2178,7 +2179,7 @@ static void displace(Render *re, ObjectRen *obr)
/* Metaball */
/* ------------------------------------------------------------------------- */
-static void init_render_mball(Render *re, ObjectRen *obr)
+static void init_render_mball(const EvaluationContext *eval_ctx, Render *re, ObjectRen *obr)
{
Object *ob= obr->ob;
DispList *dl;
@@ -2204,7 +2205,7 @@ static void init_render_mball(Render *re, ObjectRen *obr)
need_orco= 1;
}
- BKE_displist_make_mball_forRender(re->eval_ctx, re->scene, ob, &dispbase);
+ BKE_displist_make_mball_forRender(eval_ctx, re->scene, ob, &dispbase);
dl= dispbase.first;
if (dl == NULL) return;
@@ -2571,7 +2572,7 @@ static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
}
-static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
+static void init_render_surf(const EvaluationContext *eval_ctx, Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
Nurb *nu = NULL;
@@ -2604,13 +2605,13 @@ static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
if (ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1;
- BKE_displist_make_surf(re->eval_ctx, re->scene, ob, &displist, &dm, 1, 0, 1);
+ BKE_displist_make_surf(eval_ctx, re->scene, ob, &displist, &dm, 1, 0, 1);
if (dm) {
if (need_orco) {
orco = get_object_orco(re, ob);
if (!orco) {
- orco= BKE_displist_make_orco(re->eval_ctx, re->scene, ob, dm, true, true);
+ orco= BKE_displist_make_orco(eval_ctx, re->scene, ob, dm, true, true);
if (orco) {
set_object_orco(re, ob, orco);
}
@@ -2642,7 +2643,7 @@ static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
MEM_freeN(matar);
}
-static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
+static void init_render_curve(const EvaluationContext *eval_ctx, Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
Curve *cu;
@@ -2662,7 +2663,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
if (ob->type==OB_FONT && cu->str==NULL) return;
else if (ob->type==OB_CURVE && cu->nurb.first==NULL) return;
- BKE_displist_make_curveTypes_forRender(re->eval_ctx, re->scene, ob, &disp, &dm, false, true);
+ BKE_displist_make_curveTypes_forRender(eval_ctx, re->scene, ob, &disp, &dm, false, true);
dl= disp.first;
if (dl==NULL) return;
@@ -2689,7 +2690,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
if (need_orco) {
orco = get_object_orco(re, ob);
if (!orco) {
- orco = BKE_displist_make_orco(re->eval_ctx, re->scene, ob, dm, true, true);
+ orco = BKE_displist_make_orco(eval_ctx, re->scene, ob, dm, true, true);
if (orco) {
set_object_orco(re, ob, orco);
}
@@ -2703,7 +2704,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
if (need_orco) {
orco = get_object_orco(re, ob);
if (!orco) {
- orco = BKE_curve_make_orco(re->eval_ctx, re->scene, ob, NULL);
+ orco = BKE_curve_make_orco(eval_ctx, re->scene, ob, NULL);
set_object_orco(re, ob, orco);
}
}
@@ -3114,7 +3115,7 @@ static bool has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
}
#endif
-static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
+static void init_render_mesh(const EvaluationContext *eval_ctx, Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
Mesh *me;
@@ -3203,9 +3204,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
#endif
if (re->r.scemode & R_VIEWPORT_PREVIEW)
- dm= mesh_create_derived_view(re->eval_ctx, re->scene, ob, mask);
+ dm= mesh_create_derived_view(eval_ctx, re->scene, ob, mask);
else
- dm= mesh_create_derived_render(re->eval_ctx, re->scene, ob, mask);
+ dm= mesh_create_derived_render(eval_ctx, re->scene, ob, mask);
if (dm==NULL) return; /* in case duplicated object fails? */
mvert= dm->getVertArray(dm);
@@ -3987,7 +3988,7 @@ static void add_lightgroup(Render *re, Group *group, int exclusive)
#if 0
/* it's a bit too many loops in loops... but will survive */
/* note that 'exclusive' will remove it from the global list */
- FOREACH_GROUP_BASE(group, base)
+ FOREACH_GROUP_BASE_BEGIN(group, base)
{
Object *object = base->object;
@@ -4015,7 +4016,7 @@ static void add_lightgroup(Render *re, Group *group, int exclusive)
}
}
}
- FOREACH_GROUP_BASE_END
+ FOREACH_GROUP_BASE_END;
#else
UNUSED_VARS(re, exclusive);
#endif
@@ -4608,7 +4609,7 @@ static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *d
copy_v2_v2(obi->dupliuv, dob->uv);
}
-static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
+static void init_render_object_data(const EvaluationContext *eval_ctx, Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
ParticleSystem *psys;
@@ -4622,26 +4623,26 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
const CustomDataMask mask = CD_MASK_RENDER_INTERNAL;
if (re->r.scemode & R_VIEWPORT_PREVIEW)
- dm = mesh_create_derived_view(re->eval_ctx, re->scene, ob, mask);
+ dm = mesh_create_derived_view(eval_ctx, re->scene, ob, mask);
else
- dm = mesh_create_derived_render(re->eval_ctx, re->scene, ob, mask);
+ dm = mesh_create_derived_render(eval_ctx, re->scene, ob, mask);
dm->release(dm);
}
for (psys=ob->particlesystem.first, i=0; i<obr->psysindex-1; i++)
psys= psys->next;
- render_new_particle_system(re, obr, psys, timeoffset);
+ render_new_particle_system(eval_ctx, re, obr, psys, timeoffset);
}
else {
if (ELEM(ob->type, OB_FONT, OB_CURVE))
- init_render_curve(re, obr, timeoffset);
+ init_render_curve(eval_ctx, re, obr, timeoffset);
else if (ob->type==OB_SURF)
- init_render_surf(re, obr, timeoffset);
+ init_render_surf(eval_ctx, re, obr, timeoffset);
else if (ob->type==OB_MESH)
- init_render_mesh(re, obr, timeoffset);
+ init_render_mesh(eval_ctx, re, obr, timeoffset);
else if (ob->type==OB_MBALL)
- init_render_mball(re, obr);
+ init_render_mball(eval_ctx, re, obr);
}
finalize_render_object(re, obr, timeoffset);
@@ -4652,7 +4653,8 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
re->totstrand += obr->totstrand;
}
-static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
+static void add_render_object(const EvaluationContext *eval_ctx, Render *re, Object *ob, Object *par, DupliObject *dob,
+ float omat[4][4], int timeoffset)
{
ObjectRen *obr;
ObjectInstanceRen *obi;
@@ -4690,7 +4692,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
obr->flag |= R_INSTANCEABLE;
copy_m4_m4(obr->obmat, ob->obmat);
}
- init_render_object_data(re, obr, timeoffset);
+ init_render_object_data(eval_ctx, re, obr, timeoffset);
/* only add instance for objects that have not been used for dupli */
if (!(ob->transflag & OB_RENDER_DUPLI)) {
@@ -4721,7 +4723,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
}
if (dob)
psys->flag |= PSYS_USE_IMAT;
- init_render_object_data(re, obr, timeoffset);
+ init_render_object_data(eval_ctx, re, obr, timeoffset);
if (!(re->r.scemode & R_VIEWPORT_PREVIEW) && !psys_has_renderdata) {
psys_render_restore(ob, psys);
}
@@ -4740,7 +4742,8 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
/* par = pointer to duplicator parent, needed for object lookup table */
/* index = when duplicater copies same object (particle), the counter */
-static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
+static void init_render_object(const EvaluationContext *eval_ctx, Render *re, Object *ob, Object *par, DupliObject *dob,
+ float omat[4][4], int timeoffset)
{
static double lasttime= 0.0;
double time;
@@ -4749,7 +4752,7 @@ static void init_render_object(Render *re, Object *ob, Object *par, DupliObject
if (ob->type==OB_LAMP)
add_render_lamp(re, ob);
else if (render_object_type(ob->type))
- add_render_object(re, ob, par, dob, omat, timeoffset);
+ add_render_object(eval_ctx, re, ob, par, dob, omat, timeoffset);
else {
mul_m4_m4m4(mat, re->viewmat, ob->obmat);
invert_m4_m4(ob->imat, mat);
@@ -4905,7 +4908,8 @@ static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Obj
(!(dob->type == OB_DUPLIGROUP) || !dob->animated));
}
-static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, int level, int enable)
+static void dupli_render_particle_set(const EvaluationContext *eval_ctx, Render *re, Object *ob,
+ int timeoffset, int level, int enable)
{
/* ugly function, but we need to set particle systems to their render
* settings before calling object_duplilist, to get render level duplis */
@@ -4932,7 +4936,7 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in
/* this is to make sure we get render level duplis in groups:
* the derivedmesh must be created before init_render_mesh,
* since object_duplilist does dupliparticles before that */
- dm = mesh_create_derived_render(re->eval_ctx, re->scene, ob, CD_MASK_RENDER_INTERNAL);
+ dm = mesh_create_derived_render(eval_ctx, re->scene, ob, CD_MASK_RENDER_INTERNAL);
dm->release(dm);
for (psys=ob->particlesystem.first; psys; psys=psys->next)
@@ -4942,11 +4946,11 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in
if (ob->dup_group == NULL) return;
- FOREACH_GROUP_OBJECT(ob->dup_group, object)
+ FOREACH_GROUP_OBJECT_BEGIN(ob->dup_group, object)
{
- dupli_render_particle_set(re, object, timeoffset, level+1, enable);
+ dupli_render_particle_set(eval_ctx, re, object, timeoffset, level+1, enable);
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
static int get_vector_viewlayers(Scene *UNUSED(sce))
@@ -4954,32 +4958,34 @@ static int get_vector_viewlayers(Scene *UNUSED(sce))
return 0;
}
-static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int level)
+static void add_group_render_dupli_obs(const EvaluationContext *eval_ctx, Render *re, Group *group, int nolamps,
+ int onlyselected, Object *actob, int timeoffset, int level)
{
/* Simple preventing of too deep nested groups. */
if (level > MAX_DUPLI_RECUR) return;
/* Recursively go into dupligroups to find objects with OB_RENDER_DUPLI
* that were not created yet. */
- FOREACH_GROUP_OBJECT(group, ob)
+ FOREACH_GROUP_OBJECT_BEGIN(group, ob)
{
if (ob->flag & OB_DONE) {
if (ob->transflag & OB_RENDER_DUPLI) {
if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ init_render_object(eval_ctx, re, ob, NULL, NULL, NULL, timeoffset);
ob->transflag &= ~OB_RENDER_DUPLI;
if (ob->dup_group) {
- add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1);
+ add_group_render_dupli_obs(eval_ctx, re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1);
}
}
}
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
-static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), int nolamps, int onlyselected, Object *actob, int timeoffset)
+static void database_init_objects(const EvaluationContext *eval_ctx, Render *re, unsigned int UNUSED(renderlay),
+ int nolamps, int onlyselected, Object *actob, int timeoffset)
{
Base *base;
Object *ob;
@@ -5032,7 +5038,7 @@ static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), in
* it still needs to create the ObjectRen containing the data */
if (ob->transflag & OB_RENDER_DUPLI) {
if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ init_render_object(eval_ctx, re, ob, NULL, NULL, NULL, timeoffset);
ob->transflag &= ~OB_RENDER_DUPLI;
}
}
@@ -5046,9 +5052,9 @@ static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), in
/* create list of duplis generated by this object, particle
* system need to have render settings set for dupli particles */
- dupli_render_particle_set(re, ob, timeoffset, 0, 1);
- duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
- duplilist_apply_data = duplilist_apply(re->eval_ctx, ob, NULL, duplilist);
+ dupli_render_particle_set(eval_ctx, re, ob, timeoffset, 0, 1);
+ duplilist = object_duplilist(eval_ctx, re->scene, ob);
+ duplilist_apply_data = duplilist_apply(eval_ctx, ob, NULL, duplilist);
/* postpone 'dupli_render_particle_set', since RE_addRenderInstance reads
* index values from 'dob->persistent_id[0]', referencing 'psys->child' which
* may be smaller once the particle system is restored, see: T45563. */
@@ -5131,7 +5137,7 @@ static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), in
if (obi==NULL)
/* can't instance, just create the object */
- init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
+ init_render_object(eval_ctx, re, obd, ob, dob, dob_extra->obmat, timeoffset);
if (dob->type != OB_DUPLIGROUP) {
obd->flag |= OB_DONE;
@@ -5139,13 +5145,13 @@ static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), in
}
}
else
- init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
+ init_render_object(eval_ctx, re, obd, ob, dob, dob_extra->obmat, timeoffset);
if (re->test_break(re->tbh)) break;
}
/* restore particle system */
- dupli_render_particle_set(re, ob, timeoffset, 0, false);
+ dupli_render_particle_set(eval_ctx, re, ob, timeoffset, 0, false);
if (duplilist_apply_data) {
duplilist_restore(duplilist, duplilist_apply_data);
@@ -5154,10 +5160,10 @@ static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), in
free_object_duplilist(duplilist);
if (allow_render_object(re, ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ init_render_object(eval_ctx, re, ob, NULL, NULL, NULL, timeoffset);
}
else if (allow_render_object(re, ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ init_render_object(eval_ctx, re, ob, NULL, NULL, NULL, timeoffset);
}
if (re->test_break(re->tbh)) break;
@@ -5166,7 +5172,7 @@ static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), in
/* objects in groups with OB_RENDER_DUPLI set still need to be created,
* since they may not be part of the scene */
for (group= re->main->group.first; group; group=group->id.next)
- add_group_render_dupli_obs(re, group, nolamps, onlyselected, actob, timeoffset, 0);
+ add_group_render_dupli_obs(eval_ctx, re, group, nolamps, onlyselected, actob, timeoffset, 0);
if (!re->test_break(re->tbh))
RE_makeRenderInstances(re);
@@ -5210,7 +5216,6 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
/* applies changes fully */
if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, re->main, re->scene, NULL);
render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
}
@@ -5247,7 +5252,12 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
set_node_shader_lamp_loop(shade_material_loop);
/* MAKE RENDER DATA */
- database_init_objects(re, lay, 0, 0, NULL, 0);
+ EvaluationContext *eval_ctx = NULL;
+ BLI_assert(eval_ctx);
+ /* This will break things, and it should because honestly this function is deprecated and no one uses it.
+ * maybe freestyle? But even so, this need to change. Even freestyle need to get data from depsgraph
+ * so we can't create the database only once. */
+ database_init_objects(eval_ctx, re, lay, 0, 0, NULL, 0);
if (!re->test_break(re->tbh)) {
set_material_lightgroups(re);
@@ -5262,7 +5272,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
}
}
-void RE_Database_Preprocess(Render *re)
+void RE_Database_Preprocess(EvaluationContext *eval_ctx, Render *re)
{
if (!re->test_break(re->tbh)) {
int tothalo;
@@ -5292,7 +5302,7 @@ void RE_Database_Preprocess(Render *re)
/* point density texture */
if (!re->test_break(re->tbh))
- make_pointdensities(re);
+ make_pointdensities(eval_ctx, re);
/* voxel data texture */
if (!re->test_break(re->tbh))
make_voxeldata(re);
@@ -5363,7 +5373,11 @@ void RE_DataBase_GetView(Render *re, float mat[4][4])
/* Speed Vectors */
/* ------------------------------------------------------------------------- */
-static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int lay, int timeoffset)
+static void database_fromscene_vectors(EvaluationContext *eval_ctx,
+ Render *re,
+ Scene *scene,
+ unsigned int lay,
+ int timeoffset)
{
Object *camera= RE_GetCamera(re);
float mat[4][4];
@@ -5380,7 +5394,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
/* applies changes fully */
scene->r.cfra += timeoffset;
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, re->main, re->scene, NULL);
+ BKE_scene_graph_update_for_newframe(eval_ctx, eval_ctx->depsgraph, re->main, re->scene, NULL);
/* if no camera, viewmat should have been set! */
if (camera) {
@@ -5391,7 +5405,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
}
/* MAKE RENDER DATA */
- database_init_objects(re, lay, 0, 0, NULL, timeoffset);
+ database_init_objects(eval_ctx, re, lay, 0, 0, NULL, timeoffset);
if (!re->test_break(re->tbh))
project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
@@ -5748,7 +5762,7 @@ static void free_dbase_object_vectors(ListBase *lb)
BLI_freelistN(lb);
}
-void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned int lay)
+void RE_Database_FromScene_Vectors(EvaluationContext *eval_ctx, Render *re, Main *bmain, Scene *sce, unsigned int lay)
{
ObjectInstanceRen *obi, *oldobi;
StrandSurface *mesh;
@@ -5763,7 +5777,7 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
speedvector_project(re, NULL, NULL, NULL); /* initializes projection code */
/* creates entire dbase */
- database_fromscene_vectors(re, sce, lay, -1);
+ database_fromscene_vectors(eval_ctx, re, sce, lay, -1);
/* copy away vertex info */
copy_dbase_object_vectors(re, &oldtable);
@@ -5779,7 +5793,7 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
/* creates entire dbase */
re->i.infostr = IFACE_("Calculating next frame vectors");
- database_fromscene_vectors(re, sce, lay, +1);
+ database_fromscene_vectors(eval_ctx, re, sce, lay, +1);
}
/* copy away vertex info */
copy_dbase_object_vectors(re, &newtable);
@@ -5793,7 +5807,7 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
if (!re->test_break(re->tbh)) {
RE_Database_FromScene(re, bmain, sce, lay, 1);
- RE_Database_Preprocess(re);
+ RE_Database_Preprocess(eval_ctx, re);
}
if (!re->test_break(re->tbh)) {
@@ -5887,7 +5901,8 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
* RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects
* RE_BAKE_SHADOW: for baking, only shadows, but all objects
*/
-void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, const int type, Object *actob)
+void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, ViewLayer *view_layer,
+ unsigned int lay, const int type, Object *actob)
{
Object *camera;
float mat[4][4];
@@ -5904,6 +5919,16 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
render_copy_viewrender(&re->view_render, &scene->view_render);
RE_init_threadcount(re);
+
+ EvaluationContext *eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new();
+ DEG_evaluation_context_init_from_view_layer_for_render(eval_ctx, depsgraph, scene, view_layer);
+ DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
+ BKE_scene_graph_update_tagged(eval_ctx,
+ depsgraph,
+ bmain,
+ scene,
+ view_layer);
re->flag |= R_BAKING;
re->excludeob= actob;
@@ -5975,7 +6000,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
set_node_shader_lamp_loop(shade_material_loop);
/* MAKE RENDER DATA */
- database_init_objects(re, lay, nolamps, onlyselected, actob, 0);
+ database_init_objects(eval_ctx, re, lay, nolamps, onlyselected, actob, 0);
set_material_lightgroups(re);
@@ -5991,7 +6016,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
/* point density texture */
if (!re->test_break(re->tbh))
- make_pointdensities(re);
+ make_pointdensities(eval_ctx, re);
/* voxel data texture */
if (!re->test_break(re->tbh))
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index f666bbd2b95..19635dd26f2 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -250,12 +250,12 @@ static void env_set_imats(Render *re)
{
float mat[4][4];
- FOREACH_SCENE_OBJECT(re->scene, ob)
+ FOREACH_SCENE_OBJECT_BEGIN(re->scene, ob)
{
mul_m4_m4m4(mat, re->viewmat, ob->obmat);
invert_m4_m4(ob->imat, mat);
}
- FOREACH_SCENE_OBJECT_END
+ FOREACH_SCENE_OBJECT_END;
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index ddf128c0fbc..285cf8d660b 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -1,11 +1,10 @@
/*
-
* ***** 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.
+ * 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
@@ -42,6 +41,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "DNA_object_types.h"
+
#include "BKE_camera.h"
#include "BKE_global.h"
#include "BKE_colortools.h"
@@ -50,6 +51,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
@@ -526,9 +528,8 @@ RenderData *RE_engine_get_render_data(Render *re)
}
/* Bake */
-void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Depsgraph *graph, Scene *scene)
+void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
- re->depsgraph = graph;
re->scene = scene;
re->main = bmain;
render_copy_renderdata(&re->r, &scene->r);
@@ -579,20 +580,35 @@ bool RE_bake_engine(
/* update is only called so we create the engine.session */
if (type->update)
- type->update(engine, re->main, re->depsgraph, re->scene);
+ type->update(engine, re->main, re->scene);
if (type->bake) {
- type->bake(
- engine,
- re->scene,
- object,
- pass_type,
- pass_filter,
- object_id,
- pixel_array,
- num_pixels,
- depth,
- result);
+ EvaluationContext *eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new();
+ ViewLayer *view_layer = BLI_findlink(&re->scene->view_layers, re->scene->active_view_layer);
+
+ DEG_evaluation_context_init_from_view_layer_for_render(
+ eval_ctx,
+ depsgraph,
+ re->scene,
+ view_layer);
+
+ BKE_scene_graph_update_tagged(eval_ctx, depsgraph, re->main, re->scene, view_layer);
+
+ type->bake(engine,
+ depsgraph,
+ re->scene,
+ object,
+ pass_type,
+ pass_filter,
+ object_id,
+ pixel_array,
+ num_pixels,
+ depth,
+ result);
+
+ DEG_graph_free(depsgraph);
+ DEG_evaluation_context_free(eval_ctx);
}
engine->tile_x = 0;
@@ -629,8 +645,6 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
BPy_BEGIN_ALLOW_THREADS;
#endif
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, re->main, scene, NULL);
-
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
#endif
@@ -664,7 +678,6 @@ int RE_engine_render(Render *re, int do_all)
/* update animation here so any render layer animation is applied before
* creating the render result */
if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_BUTS_PREVIEW)) == 0) {
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, re->main, re->scene, NULL);
render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
}
@@ -731,7 +744,7 @@ int RE_engine_render(Render *re, int do_all)
render_result_exr_file_begin(re);
if (type->update) {
- type->update(engine, re->main, re->depsgraph, re->scene);
+ type->update(engine, re->main, re->scene);
}
/* Clear UI drawing locks. */
@@ -740,7 +753,25 @@ int RE_engine_render(Render *re, int do_all)
}
if (type->render_to_image) {
- type->render_to_image(engine, re->depsgraph);
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re, view_layer_iter)
+ {
+ EvaluationContext *eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new();
+ ViewLayer *view_layer = BLI_findstring(&re->scene->view_layers, view_layer_iter->name, offsetof(ViewLayer, name));
+
+ DEG_evaluation_context_init_from_view_layer_for_render(
+ eval_ctx,
+ depsgraph,
+ re->scene,
+ view_layer);
+
+ BKE_scene_graph_update_tagged(eval_ctx, depsgraph, re->main, re->scene, view_layer);
+ type->render_to_image(engine, depsgraph);
+
+ DEG_graph_free(depsgraph);
+ DEG_evaluation_context_free(eval_ctx);
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
}
engine->tile_x = 0;
@@ -803,8 +834,3 @@ void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, s
}
}
}
-
-ViewLayer *RE_engine_get_view_layer(Render *re)
-{
- return re->eval_ctx->view_layer;
-}
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 9182d545089..13c95dac05d 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -501,11 +501,6 @@ void RE_SetCamera(Render *re, Object *cam_ob)
re_camera_params_get(re, &params, cam_ob);
}
-void RE_SetDepsgraph(Render *re, Depsgraph *graph)
-{
- re->depsgraph = graph;
-}
-
void RE_SetPixelSize(Render *re, float pixsize)
{
re->viewdx = pixsize;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index e5426384c6f..170cd0ad419 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -81,6 +81,8 @@
#include "BKE_object.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
#include "IMB_colormanagement.h"
@@ -259,6 +261,11 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
}
}
+bool RE_HasSingleLayer(Render *re)
+{
+ return (re->r.scemode & R_SINGLE_LAYER);
+}
+
RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
{
return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty);
@@ -266,15 +273,22 @@ RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool
RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
{
- RenderLayer *rl = BLI_findlink(&rr->layers, re->active_view_layer);
-
- if (rl)
- return rl;
- else
- return rr->layers.first;
+ ViewLayer *view_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
+
+ if (view_layer) {
+ RenderLayer *rl = BLI_findstring(&rr->layers,
+ view_layer->name,
+ offsetof(RenderLayer, name));
+
+ if (rl) {
+ return rl;
+ }
+ }
+
+ return rr->layers.first;
}
-static int render_scene_needs_vector(Render *re)
+static int UNUSED_FUNCTION(render_scene_needs_vector)(Render *re)
{
ViewLayer *view_layer;
for (view_layer = re->view_layers.first; view_layer; view_layer = view_layer->next)
@@ -355,15 +369,6 @@ Scene *RE_GetScene(Render *re)
return NULL;
}
-EvaluationContext *RE_GetEvalCtx(Render *re)
-{
- if (re) {
- return re->eval_ctx;
- }
-
- return NULL;
-}
-
/**
* Same as #RE_AcquireResultImage but creating the necessary views to store the result
* fill provided result struct with a copy of thew views of what is done so far the
@@ -515,7 +520,6 @@ Render *RE_NewRender(const char *name)
BLI_strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
BLI_rw_mutex_init(&re->partsmutex);
- re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
}
RE_InitRenderCB(re);
@@ -592,7 +596,6 @@ void RE_FreeRender(Render *re)
/* main dbase can already be invalid now, some database-free code checks it */
re->main = NULL;
re->scene = NULL;
- re->depsgraph = NULL;
RE_Database_Free(re); /* view render can still have full database */
free_sample_tables(re);
@@ -601,7 +604,6 @@ void RE_FreeRender(Render *re)
render_result_free(re->pushedresult);
BLI_remlink(&RenderGlobal.renderlist, re);
- MEM_freeN(re->eval_ctx);
MEM_freeN(re);
}
@@ -862,12 +864,11 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->result->recty = re->recty;
render_result_view_new(re->result, "");
}
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- re->eval_ctx->mode = DAG_EVAL_PREVIEW;
- else
- re->eval_ctx->mode = DAG_EVAL_RENDER;
-
+
+ eEvaluationMode mode = (re->r.scemode & R_VIEWPORT_PREVIEW) ? DAG_EVAL_PREVIEW : DAG_EVAL_RENDER;
+ /* If we had a consistent EvaluationContext now would be the time to update it. */
+ (void)mode;
+
/* ensure renderdatabase can use part settings correct */
RE_parts_clamp(re);
@@ -1353,7 +1354,7 @@ static void *do_render_thread(void *thread_v)
return NULL;
}
-static void main_render_result_end(Render *re)
+static void UNUSED_FUNCTION(main_render_result_end)(Render *re)
{
if (re->result->do_exr_tile) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
@@ -1559,81 +1560,10 @@ void RE_TileProcessor(Render *re)
static void do_render_3d(Render *re)
{
- RenderView *rv;
-
re->current_scene_update(re->suh, re->scene);
- /* try external */
- if (RE_engine_render(re, 0))
- return;
-
- /* internal */
- RE_parts_clamp(re);
-
- /* add motion blur and fields offset to frames */
- const int cfra_backup = re->scene->r.cfra;
- const float subframe_backup = re->scene->r.subframe;
-
- BKE_scene_frame_set(
- re->scene, (double)re->scene->r.cfra + (double)re->scene->r.subframe +
- (double)re->mblur_offs + (double)re->field_offs);
-
- /* init main render result */
- main_render_result_new(re);
- if (re->result == NULL) {
- BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
- G.is_break = true;
- return;
- }
-
-#ifdef WITH_FREESTYLE
- if (re->r.mode & R_EDGE_FRS) {
- init_freestyle(re);
- }
-#endif
-
- /* we need a new database for each view */
- for (rv = re->result->views.first; rv; rv = rv->next) {
- RE_SetActiveRenderView(re, rv->name);
-
- /* lock drawing in UI during data phase */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 1);
-
- /* make render verts/faces/halos/lamps */
- if (render_scene_needs_vector(re))
- RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
- else {
- RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
- }
-
- /* clear UI drawing locks */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 0);
-
- threaded_tile_processor(re);
-
-#ifdef WITH_FREESTYLE
- /* Freestyle */
- if (re->r.mode & R_EDGE_FRS)
- if (!re->test_break(re->tbh))
- add_freestyle(re, 1);
-#endif
-
- /* do left-over 3d post effects (flares) */
- if (re->flag & R_HALO)
- if (!re->test_break(re->tbh))
- add_halo_flare(re);
-
- /* free all render verts etc */
- RE_Database_Free(re);
- }
-
- main_render_result_end(re);
-
- re->scene->r.cfra = cfra_backup;
- re->scene->r.subframe = subframe_backup;
+ /* All the rendering pipeline goes through "external" render engines. */
+ RE_engine_render(re, 0);
}
/* called by blur loop, accumulate RGBA key alpha */
@@ -1748,11 +1678,6 @@ static void do_render_blur_3d(Render *re)
re->mblur_offs = 0.0f;
re->i.curblur = 0; /* stats */
- /* make sure motion blur changes get reset to current frame */
- if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, re->main, re->scene, NULL);
- }
-
/* weak... the display callback wants an active renderlayer pointer... */
re->result->renlay = render_get_active_layer(re, re->result);
re->display_update(re->duh, re->result, NULL);
@@ -1986,7 +1911,6 @@ static void render_scene(Render *re, Scene *sce, int cfra)
/* still unsure entity this... */
resc->main = re->main;
- resc->depsgraph = re->depsgraph;
resc->scene = sce;
resc->lay = sce->lay;
resc->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
@@ -2069,7 +1993,7 @@ bool RE_allow_render_generic_object(Object *ob)
#ifdef DEPSGRAPH_WORKAROUND_HACK
static void tag_dependend_objects_for_render(Scene *scene, int UNUSED(renderlay))
{
- FOREACH_OBJECT_RENDERABLE(scene, object)
+ FOREACH_OBJECT_RENDERABLE_BEGIN(scene, object)
{
if (object->type == OB_MESH) {
if (RE_allow_render_generic_object(object)) {
@@ -2131,7 +2055,7 @@ static void tag_dependend_objects_for_render(Scene *scene, int UNUSED(renderlay)
}
}
}
- FOREACH_OBJECT_RENDERABLE_END
+ FOREACH_OBJECT_RENDERABLE_END;
}
#endif
@@ -2696,8 +2620,9 @@ static void do_render_composite_fields_blur_3d(Render *re)
R.i.starttime = re->i.starttime;
R.i.cfra = re->i.cfra;
- if (update_newframe)
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, re->main, re->scene, NULL);
+ if (update_newframe) {
+ /* If we have consistent depsgraph now would be a time to update them. */
+ }
if (re->r.scemode & R_FULL_SAMPLE)
do_merge_fullsample(re, ntree);
@@ -2807,9 +2732,10 @@ static void do_render_seq(Render *re)
tot_views = BKE_scene_multiview_num_views_get(&re->r);
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs");
+ EvaluationContext *eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
BKE_sequencer_new_render_data(
- re->eval_ctx, re->main, re->scene,
+ eval_ctx, re->main, re->scene,
re_x, re_y, 100,
&context);
@@ -2831,6 +2757,8 @@ static void do_render_seq(Render *re)
}
}
+ DEG_evaluation_context_free(eval_ctx);
+
rr = re->result;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
@@ -3399,7 +3327,7 @@ void RE_RenderFreestyleExternal(Render *re)
for (rv = re->result->views.first; rv; rv = rv->next) {
RE_SetActiveRenderView(re, rv->name);
RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
+ RE_Database_Preprocess(NULL, re);
add_freestyle(re, 1);
RE_Database_Free(re);
}
@@ -3772,8 +3700,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
NULL, camera_override, lay_override, 1, 0);
if (nfra != scene->r.cfra) {
- /* Skip this frame, but update for physics and particles system. */
- BKE_scene_graph_update_for_newframe(re->eval_ctx, re->depsgraph, bmain, scene, NULL);
+ /* Skip this frame, but could update for physics and particles system. */
continue;
}
else
@@ -3922,7 +3849,6 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
void RE_PreviewRender(Render *re, Main *bmain, Scene *sce, ViewRender *view_render)
{
Object *camera;
- ViewLayer *view_layer = BKE_view_layer_from_scene_get(sce);
int winx, winy;
winx = (sce->r.size * sce->r.xsch) / 100;
@@ -3936,8 +3862,6 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce, ViewRender *view_rend
re->scene = sce;
re->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
re->lay = sce->lay;
- re->depsgraph = BKE_scene_get_depsgraph(sce, view_layer, false);
- re->eval_ctx->view_layer = view_layer;
camera = RE_GetCamera(re);
RE_SetCamera(re, camera);
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 4f300b7286c..49738aa5f96 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -59,6 +59,7 @@
#include "BKE_colortools.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "render_types.h"
#include "texture.h"
@@ -169,7 +170,7 @@ static void alloc_point_data(PointDensity *pd)
}
}
-static void pointdensity_cache_psys(EvaluationContext *eval_ctx, Scene *scene,
+static void pointdensity_cache_psys(const EvaluationContext *eval_ctx, Scene *scene,
PointDensity *pd,
Object *ob,
ParticleSystem *psys,
@@ -403,7 +404,7 @@ static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob
}
}
-static void pointdensity_cache_object(EvaluationContext *eval_ctx, Scene *scene,
+static void pointdensity_cache_object(const EvaluationContext *eval_ctx, Scene *scene,
PointDensity *pd,
Object *ob,
const bool use_render_params)
@@ -478,7 +479,8 @@ static void pointdensity_cache_object(EvaluationContext *eval_ctx, Scene *scene,
}
-static void cache_pointdensity_ex(EvaluationContext *eval_ctx, Scene *scene,
+static void cache_pointdensity_ex(const EvaluationContext *eval_ctx,
+ Scene *scene,
PointDensity *pd,
float viewmat[4][4],
float winmat[4][4],
@@ -523,9 +525,9 @@ static void cache_pointdensity_ex(EvaluationContext *eval_ctx, Scene *scene,
}
}
-void cache_pointdensity(Render *re, PointDensity *pd)
+void cache_pointdensity(const EvaluationContext *eval_ctx, Render *re, PointDensity *pd)
{
- cache_pointdensity_ex(re->eval_ctx,
+ cache_pointdensity_ex(eval_ctx,
re->scene,
pd,
re->viewmat, re->winmat,
@@ -551,7 +553,7 @@ void free_pointdensity(PointDensity *pd)
pd->totpoints = 0;
}
-void make_pointdensities(Render *re)
+void make_pointdensities(const EvaluationContext *eval_ctx, Render *re)
{
Tex *tex;
@@ -564,7 +566,7 @@ void make_pointdensities(Render *re)
for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
if (tex->id.us && tex->type == TEX_POINTDENSITY) {
- cache_pointdensity(re, tex->pd);
+ cache_pointdensity(eval_ctx, re, tex->pd);
}
}
@@ -881,7 +883,7 @@ static void sample_dummy_point_density(int resolution, float *values)
memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
}
-static void particle_system_minmax(EvaluationContext *eval_ctx,
+static void particle_system_minmax(const EvaluationContext *eval_ctx,
Scene *scene,
Object *object,
ParticleSystem *psys,
@@ -944,33 +946,30 @@ static void particle_system_minmax(EvaluationContext *eval_ctx,
}
void RE_point_density_cache(
- Scene *scene,
- ViewLayer *view_layer,
- PointDensity *pd,
- const bool use_render_params)
+ const struct EvaluationContext *eval_ctx,
+ PointDensity *pd)
{
- EvaluationContext eval_ctx = {0};
float mat[4][4];
+ const bool use_render_params = (eval_ctx->mode == DAG_EVAL_RENDER);
- DEG_evaluation_context_init(&eval_ctx, use_render_params ? DAG_EVAL_RENDER
- : DAG_EVAL_VIEWPORT);
-
- eval_ctx.view_layer = view_layer;
+ Depsgraph *depsgraph = eval_ctx->depsgraph;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
/* Same matricies/resolution as dupli_render_particle_set(). */
unit_m4(mat);
BLI_mutex_lock(&sample_mutex);
- cache_pointdensity_ex(&eval_ctx, scene, pd, mat, mat, 1, 1, use_render_params);
+ cache_pointdensity_ex(eval_ctx, scene, pd, mat, mat, 1, 1, use_render_params);
BLI_mutex_unlock(&sample_mutex);
}
void RE_point_density_minmax(
- struct Scene *scene,
- ViewLayer *view_layer,
+ const struct EvaluationContext *eval_ctx,
struct PointDensity *pd,
- const bool use_render_params,
float r_min[3], float r_max[3])
{
+ const bool use_render_params = (eval_ctx->mode == DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = eval_ctx->depsgraph;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
Object *object = pd->object;
if (object == NULL) {
zero_v3(r_min);
@@ -979,7 +978,6 @@ void RE_point_density_minmax(
}
if (pd->source == TEX_PD_PSYS) {
ParticleSystem *psys;
- EvaluationContext eval_ctx = {0};
if (pd->psys == 0) {
zero_v3(r_min);
@@ -993,13 +991,7 @@ void RE_point_density_minmax(
return;
}
- DEG_evaluation_context_init(&eval_ctx, use_render_params ? DAG_EVAL_RENDER :
- DAG_EVAL_VIEWPORT);
-
- eval_ctx.ctime = (float)scene->r.cfra + scene->r.subframe;
- eval_ctx.view_layer = view_layer;
-
- particle_system_minmax(&eval_ctx,
+ particle_system_minmax(eval_ctx,
scene,
object,
psys,
@@ -1072,11 +1064,9 @@ static void point_density_sample_func(
* NOTE 2: Frees point density structure after sampling.
*/
void RE_point_density_sample(
- Scene *scene,
- ViewLayer *view_layer,
+ const EvaluationContext *eval_ctx,
PointDensity *pd,
const int resolution,
- const bool use_render_params,
float *values)
{
Object *object = pd->object;
@@ -1092,10 +1082,8 @@ void RE_point_density_sample(
}
BLI_mutex_lock(&sample_mutex);
- RE_point_density_minmax(scene,
- view_layer,
+ RE_point_density_minmax(eval_ctx,
pd,
- use_render_params,
min,
max);
BLI_mutex_unlock(&sample_mutex);
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index f97c8fb0b06..c5d1dfc50f4 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -266,9 +266,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
RenderResult *rr;
RenderLayer *rl;
RenderView *rv;
- ViewLayer *view_layer;
int rectx, recty;
- int nr;
rectx = BLI_rcti_size_x(partrct);
recty = BLI_rcti_size_y(partrct);
@@ -296,23 +294,14 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
render_result_views_new(rr, &re->r);
/* check renderdata for amount of layers */
- for (nr = 0, view_layer = re->view_layers.first; view_layer; view_layer = view_layer->next, nr++) {
-
- if (layername && layername[0])
- if (!STREQ(view_layer->name, layername))
- continue;
-
- if (re->r.scemode & R_SINGLE_LAYER) {
- if (nr != re->active_view_layer) {
- continue;
- }
- }
- else {
- if ((view_layer->flag & VIEW_LAYER_RENDER) == 0) {
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re, view_layer)
+ {
+ if (layername && layername[0]) {
+ if (!STREQ(view_layer->name, layername)) {
continue;
}
}
-
+
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
@@ -417,6 +406,8 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
#undef RENDER_LAYER_ADD_PASS_SAFE
}
}
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+
/* sss, previewrender and envmap don't do layers, so we make a default one */
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index e66dd86a75a..cefa739a796 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -3745,7 +3745,7 @@ static void textured_face_generate_uv(
}
/* Generate an updated copy of material to use for color sampling. */
-Material *RE_sample_material_init(Material *orig_mat, Scene *scene)
+Material *RE_sample_material_init(const EvaluationContext *eval_ctx, Material *orig_mat, Scene *scene)
{
Tex *tex = NULL;
Material *mat;
@@ -3821,7 +3821,7 @@ Material *RE_sample_material_init(Material *orig_mat, Scene *scene)
unit_m4(dummy_re.viewmat);
unit_m4(dummy_re.winmat);
dummy_re.winx = dummy_re.winy = 128;
- cache_pointdensity(&dummy_re, tex->pd);
+ cache_pointdensity(eval_ctx, &dummy_re, tex->pd);
}
/* update image sequences and movies */
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 0da45202730..234491a2186 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -35,6 +35,7 @@ set(INC
../compositor
../depsgraph
../editors/include
+ ../draw
../gpu
../imbuf
../makesdna
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index aaf1a11a416..b7ac144c70d 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -121,6 +121,11 @@ struct bScreen *WM_window_get_active_screen(const struct wmWindow *win) ATTR_NON
void WM_window_set_active_screen(struct wmWindow *win, struct WorkSpace *workspace, struct bScreen *screen) ATTR_NONNULL(1);
bool WM_window_is_temp_screen(const struct wmWindow *win) ATTR_WARN_UNUSED_RESULT;
+void *WM_opengl_context_create(void);
+void WM_opengl_context_dispose(void *context);
+void WM_opengl_context_activate(void *context);
+void WM_opengl_context_release(void *context);
+
/* defines for 'type' WM_window_open_temp */
enum {
WM_WINDOW_RENDER = 1,
@@ -418,6 +423,7 @@ struct MenuType *WM_menutype_find(const char *idname, bool quiet);
bool WM_menutype_add(struct MenuType *mt);
void WM_menutype_freelink(struct MenuType *mt);
void WM_menutype_free(void);
+bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
/* wm_gesture_ops.c */
int WM_gesture_border_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
@@ -500,6 +506,7 @@ enum {
WM_JOB_TYPE_POINTCACHE,
WM_JOB_TYPE_DPAINT_BAKE,
WM_JOB_TYPE_ALEMBIC,
+ WM_JOB_TYPE_SHADER_COMPILATION,
/* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 8a94472aaf5..b4d4d55479d 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -76,7 +76,8 @@ wmKeyMap *WM_keymap_find_all(const struct bContext *C, const char *idname, int s
wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap);
wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap);
-
+bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap);
+
wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id);
int WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2);
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 47fcbb1f523..65b1c5951f9 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -342,6 +342,22 @@ void WM_menutype_free(void)
menutypes_hash = NULL;
}
+bool WM_menutype_poll(bContext *C, MenuType *mt)
+{
+ /* If we're tagged, only use compatible. */
+ if (mt->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, mt->owner_id) == false) {
+ return false;
+ }
+ }
+
+ if (mt->poll != NULL) {
+ return mt->poll(C, mt);
+ }
+ return true;
+}
+
/* ****************************************** */
void WM_keymap_init(bContext *C)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 040ecc63bec..037d6752396 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2198,7 +2198,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
PRINT("%s: checking '%s' ...", __func__, keymap->idname);
- if (!keymap->poll || keymap->poll(C)) {
+ if (WM_keymap_poll(C, keymap)) {
PRINT("pass\n");
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 98606379a61..8c0f78a9824 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -182,6 +182,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
{
win->ghostwin = oldwin->ghostwin;
+ win->gwnctx = oldwin->gwnctx;
win->active = oldwin->active;
if (win->active)
wm->winactive = win;
@@ -190,6 +191,7 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
oldwin->ghostwin = NULL;
+ oldwin->gwnctx = NULL;
win->eventstate = oldwin->eventstate;
oldwin->eventstate = NULL;
@@ -495,6 +497,8 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
BPY_python_reset(C);
addons_loaded = true;
}
+#else
+ UNUSED_VARS(use_userdef);
#endif /* WITH_PYTHON */
WM_operatortype_last_properties_clear_all();
@@ -2194,11 +2198,13 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
- if (BLI_exists(path)) {
+ if (RNA_boolean_get(op->ptr, "check_existing") && BLI_exists(path)) {
ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
}
else {
ret = wm_save_as_mainfile_exec(C, op);
+ /* Without this there is no feedback the file was saved. */
+ BKE_reportf(op->reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(path));
}
}
else {
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index adb03de4612..98ac3eebb57 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -116,6 +116,7 @@
#include "BLF_api.h"
#include "BLT_lang.h"
+#include "GPU_material.h"
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_init_exit.h"
@@ -125,6 +126,8 @@
#include "DEG_depsgraph.h"
+#include "DRW_engine.h"
+
#ifdef WITH_OPENSUBDIV
# include "BKE_subsurf.h"
#endif
@@ -207,6 +210,7 @@ void WM_init(bContext *C, int argc, const char **argv)
/* sets 3D mouse deadzone */
WM_ndof_deadzone_set(U.ndof_deadzone);
#endif
+ DRW_opengl_context_create();
GPU_init();
@@ -520,6 +524,17 @@ void WM_exit_ext(bContext *C, const bool do_python)
#ifdef WITH_COMPOSITOR
COM_deinitialize();
#endif
+
+ if (!G.background) {
+#ifdef WITH_OPENSUBDIV
+ BKE_subsurf_osd_cleanup();
+#endif
+
+ GPU_global_buffer_pool_free();
+ GPU_free_unused_buffers();
+
+ GPU_exit();
+ }
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// free_matcopybuf();
@@ -538,6 +553,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLF_exit();
+ if (!G.background) {
+ GPU_pass_cache_free();
+ DRW_opengl_context_destroy();
+ }
+
#ifdef WITH_INTERNATIONAL
BLF_free_unifont();
BLF_free_unifont_mono();
@@ -565,17 +585,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
- if (!G.background) {
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_cleanup();
-#endif
-
- GPU_global_buffer_pool_free();
- GPU_free_unused_buffers();
-
- GPU_exit();
- }
-
BKE_undo_reset();
ED_file_exit(); /* for fsmenu */
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 910b7eadf4c..e86e80dddf6 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -37,6 +37,7 @@
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
@@ -49,6 +50,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLT_translation.h"
@@ -341,6 +343,12 @@ static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid)
km->spaceid = spaceid;
km->regionid = regionid;
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(km->owner_id, owner_id, sizeof(km->owner_id));
+ }
+ }
return km;
}
@@ -398,6 +406,23 @@ bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
}
}
+
+bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
+{
+ /* If we're tagged, only use compatible. */
+ if (keymap->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, keymap->owner_id) == false) {
+ return false;
+ }
+ }
+
+ if (keymap->poll != NULL) {
+ return keymap->poll(C);
+ }
+ return true;
+}
+
static void keymap_event_set(wmKeyMapItem *kmi, short type, short val, int modifier, short keymodifier)
{
kmi->type = type;
@@ -1087,7 +1112,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
for (handler = handlers->first; handler; handler = handler->next) {
keymap = WM_keymap_active(wm, handler->keymap);
- if (keymap && (!keymap->poll || keymap->poll((bContext *)C))) {
+ if (keymap && WM_keymap_poll((bContext *)C, keymap)) {
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
/* skip disabled keymap items [T38447] */
if (kmi->flag & KMI_INACTIVE)
@@ -1719,7 +1744,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "Mesh", 0, 0);
/* some mesh operators are active in object mode too, like add-prim */
- if (km && km->poll && km->poll((bContext *)C) == 0) {
+ if (km && !WM_keymap_poll((bContext *)C, km)) {
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
}
@@ -1729,7 +1754,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "Curve", 0, 0);
/* some curve operators are active in object mode too, like add-prim */
- if (km && km->poll && km->poll((bContext *)C) == 0) {
+ if (km && !WM_keymap_poll((bContext *)C, km)) {
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
}
@@ -1757,7 +1782,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "Metaball", 0, 0);
/* some mball operators are active in object mode too, like add-prim */
- if (km && km->poll && km->poll((bContext *)C) == 0) {
+ if (km && !WM_keymap_poll((bContext *)C, km)) {
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
}
@@ -1809,7 +1834,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
* Mesh keymap is probably not ideal, but best place I could find to put those. */
if (sl->spacetype == SPACE_VIEW3D) {
km = WM_keymap_find_all(C, "Mesh", 0, 0);
- if (km && km->poll && !km->poll((bContext *)C)) {
+ if (km && !WM_keymap_poll((bContext *)C, km)) {
km = NULL;
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 579892734db..7ce3495ae47 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1817,7 +1817,7 @@ static int wm_operator_tool_set_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
- bToolDef tool_def = {0};
+ bToolDef tool_def = {{0}};
tool_def.index = RNA_int_get(op->ptr, "index");
tool_def.spacetype = sa->spacetype;
@@ -3221,26 +3221,38 @@ static void WM_OT_radial_control(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* all paths relative to the context */
- RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control");
+ PropertyRNA *prop;
+ prop = RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control");
+ prop = RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths");
+ prop = RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display");
+ prop = RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control");
+ prop = RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control");
+ prop = RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "fill_color_override_path", NULL, 0, "Fill Color Override Path", "");
- RNA_def_string(ot->srna, "fill_color_override_test_path", NULL, 0, "Fill Color Override Test", "");
+ prop = RNA_def_string(ot->srna, "fill_color_override_path", NULL, 0, "Fill Color Override Path", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_string(ot->srna, "fill_color_override_test_path", NULL, 0, "Fill Color Override Test", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control");
+ prop = RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control");
+ prop = RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_boolean(ot->srna, "secondary_tex", false, "Secondary Texture", "Tweak brush secondary/mask texture");
+ prop = RNA_def_boolean(ot->srna, "secondary_tex", false, "Secondary Texture", "Tweak brush secondary/mask texture");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ************************** timer for testing ***************** */
@@ -4057,6 +4069,7 @@ static const EnumPropertyItem *rna_id_itemf(
for (; id; id = id->next) {
if ((filter_ids != NULL) && filter_ids(user_data, id) == false) {
+ i++;
continue;
}
if (local == false || !ID_IS_LINKED(id)) {
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 5ca34880743..f34b5bf9c95 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -69,8 +69,6 @@ void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct
scissor_pad = false;
}
- int x = drawrct->xmin;
- int y = drawrct->ymin;
int width = BLI_rcti_size_x(winrct) + 1;
int height = BLI_rcti_size_y(winrct) + 1;
@@ -85,8 +83,8 @@ void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct
scissor_height += 1;
}
- glViewport(x, y, width, height);
- glScissor(x, y, scissor_width, scissor_height);
+ glViewport(winrct->xmin, winrct->ymin, width, height);
+ glScissor(drawrct->xmin, drawrct->ymin, scissor_width, scissor_height);
wmOrtho2_pixelspace(width, height);
gpuLoadIdentity();
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 60e67bb2129..ad8365b03ed 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -79,6 +79,7 @@
#include "PIL_time.h"
+#include "GPU_batch.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
@@ -87,6 +88,8 @@
#include "UI_resources.h"
+#include "../../../intern/gawain/gawain/gwn_context.h"
+
/* for assert */
#ifndef NDEBUG
# include "BLI_threads.h"
@@ -169,11 +172,23 @@ static void wm_window_check_position(rcti *rect)
}
-static void wm_ghostwindow_destroy(wmWindow *win)
+static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
{
if (win->ghostwin) {
+ /* We need this window's opengl context active to discard it. */
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GWN_context_active_set(win->gwnctx);
+
+ /* Delete local gawain objects. */
+ GWN_context_discard(win->gwnctx);
+
GHOST_DisposeWindow(g_system, win->ghostwin);
win->ghostwin = NULL;
+ win->gwnctx = NULL;
+
+ /* prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
+ wm->windrawable = NULL;
+ wm->winactive = NULL;
}
}
@@ -204,11 +219,6 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
BLI_freelinkN(&win->global_areas, sa);
}
- /* always set drawable and active to NULL,
- * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
- wm->windrawable = NULL;
- wm->winactive = NULL;
-
/* end running jobs, a job end also removes its timer */
for (wt = wm->timers.first; wt; wt = wtnext) {
wtnext = wt->next;
@@ -229,7 +239,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
wm_draw_data_free(win);
- wm_ghostwindow_destroy(win);
+ wm_ghostwindow_destroy(wm, win);
BKE_workspace_instance_hook_free(G.main, win->workspace_hook);
MEM_freeN(win->stereo3d_format);
@@ -383,9 +393,21 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
if (screen) {
ED_screen_exit(C, win, screen);
}
-
+
+ if (tmpwin) {
+ gpu_batch_presets_reset();
+ immDeactivate();
+ }
+
wm_window_free(C, wm, win);
-
+
+ /* keep imediatemode active before the next `wm_window_make_drawable` call */
+ if (tmpwin) {
+ GHOST_ActivateWindowDrawingContext(tmpwin->ghostwin);
+ GWN_context_active_set(tmpwin->gwnctx);
+ immActivate();
+ }
+
/* if temp screen, delete it after window free (it stops jobs that can access it) */
if (screen && screen->temp) {
Main *bmain = CTX_data_main(C);
@@ -486,17 +508,14 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
ghostwin = GHOST_CreateWindow(g_system, title,
win->posx, posy, win->sizex, win->sizey,
-#ifdef __APPLE__
- /* we agreed to not set any fullscreen or iconized state on startup */
- GHOST_kWindowStateNormal,
-#else
(GHOST_TWindowState)win->windowstate,
-#endif
GHOST_kDrawingContextTypeOpenGL,
glSettings);
-
+
if (ghostwin) {
GHOST_RectangleHandle bounds;
+
+ win->gwnctx = GWN_context_create();
/* the new window has already been made drawable upon creation */
wm->windrawable = win;
@@ -545,7 +564,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
}
/**
- * Initialize #wmWindows without ghostwin, open these and clear.
+ * Initialize #wmWindow without ghostwin, open these and clear.
*
* window size is read from window, if 0 it uses prefsize
* called in #WM_check, also inits stuff after file read.
@@ -755,7 +774,11 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
WM_window_set_active_layout(win, workspace, layout);
}
- if (WM_window_get_active_scene(win) != scene) {
+ if (win->scene == NULL) {
+ win->scene = scene;
+ }
+ /* In case we reuse an already existing temp window (see win lookup above). */
+ else if (WM_window_get_active_scene(win) != scene) {
WM_window_change_active_scene(bmain, C, win, scene);
}
@@ -1015,14 +1038,16 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
{
if (win != wm->windrawable && win->ghostwin) {
// win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
-
+
wm->windrawable = win;
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set drawable %d\n", __func__, win->winid);
}
+ gpu_batch_presets_reset();
immDeactivate();
GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GWN_context_active_set(win->gwnctx);
immActivate();
/* this can change per window */
@@ -1030,6 +1055,26 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
}
}
+/* Reset active the current window opengl drawing context. */
+void wm_window_reset_drawable(void)
+{
+ BLI_assert(BLI_thread_is_main());
+ wmWindowManager *wm = G.main->wm.first;
+
+ if (wm == NULL)
+ return;
+
+ wmWindow *win = wm->windrawable;
+
+ if (win && win->ghostwin) {
+ gpu_batch_presets_reset();
+ immDeactivate();
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GWN_context_active_set(win->gwnctx);
+ immActivate();
+ }
+}
+
/* called by ghost, here we handle events for windows themselves or send to event system */
/* mouse coordinate converversion happens here */
static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
@@ -1799,7 +1844,6 @@ void wm_window_raise(wmWindow *win)
void wm_window_swap_buffers(wmWindow *win)
{
-
#ifdef WIN32
glDisable(GL_SCISSOR_TEST);
GHOST_SwapWindowBuffers(win->ghostwin);
@@ -1990,10 +2034,9 @@ Scene *WM_window_get_active_scene(const wmWindow *win)
void WM_window_change_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene_new)
{
const bScreen *screen = WM_window_get_active_screen(win);
+ Scene *scene_old = win->scene;
- ED_scene_exit(C);
- win->scene = scene_new;
- ED_scene_changed_update(bmain, C, scene_new, screen);
+ ED_scene_change_update(bmain, C, win, screen, scene_old, scene_new);
}
WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
@@ -2053,3 +2096,30 @@ void wm_window_IME_end(wmWindow *win)
win->ime_data = NULL;
}
#endif /* WITH_INPUT_IME */
+
+/* ****** direct opengl context management ****** */
+
+void *WM_opengl_context_create(void)
+{
+ /* On Windows there is a problem creating contexts that share lists
+ * from one context that is current in another thread.
+ * So we should call this function only on the main thread.
+ */
+ BLI_assert(BLI_thread_is_main());
+ return GHOST_CreateOpenGLContext(g_system);
+}
+
+void WM_opengl_context_dispose(void *context)
+{
+ GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context);
+}
+
+void WM_opengl_context_activate(void *context)
+{
+ GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context);
+}
+
+void WM_opengl_context_release(void *context)
+{
+ GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context);
+}
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
index 53bee9c6775..97fcb4513be 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
@@ -331,4 +331,6 @@ void WM_manipulator_group_type_unlink_delayed(const char *idname);
/* Utilities */
bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step);
+bool WM_manipulator_group_type_poll(const struct bContext *C, const struct wmManipulatorGroupType *wgt);
+
#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 6d83f411db1..8a5580582d7 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
@@ -341,6 +341,7 @@ typedef struct wmManipulatorGroupTypeRef {
typedef struct wmManipulatorGroupType {
const char *idname; /* MAX_NAME */
const char *name; /* manipulator-group name - displayed in UI (keymap editor) */
+ char owner_id[64]; /* MAX_NAME */
/* poll if manipulator-map should be visible */
wmManipulatorGroupFnPoll poll;
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
index 0e63f3d6ffe..31861df1db2 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
@@ -44,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -201,10 +202,17 @@ void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bC
}
}
-bool wm_manipulatorgroup_is_visible(const wmManipulatorGroup *mgroup, const bContext *C)
+bool WM_manipulator_group_type_poll(const bContext *C, const struct wmManipulatorGroupType *wgt)
{
+ /* If we're tagged, only use compatible. */
+ if (wgt->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, wgt->owner_id) == false) {
+ return false;
+ }
+ }
/* Check for poll function, if manipulator-group belongs to an operator, also check if the operator is running. */
- return (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type));
+ return (!wgt->poll || wgt->poll(C, (wmManipulatorGroupType *)wgt));
}
bool wm_manipulatorgroup_is_visible_in_drawstep(
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
index b7982cf00df..a131c6c5069 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
@@ -75,7 +75,6 @@ struct wmManipulator *wm_manipulatorgroup_find_intersected_manipulator(
void wm_manipulatorgroup_intersectable_manipulators_to_list(
const struct wmManipulatorGroup *mgroup, struct ListBase *listbase);
void wm_manipulatorgroup_ensure_initialized(struct wmManipulatorGroup *mgroup, const struct bContext *C);
-bool wm_manipulatorgroup_is_visible(const struct wmManipulatorGroup *mgroup, const struct bContext *C);
bool wm_manipulatorgroup_is_visible_in_drawstep(
const struct wmManipulatorGroup *mgroup, const eWM_ManipulatorMapDrawStep drawstep);
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
index 153052d7e1c..d774c4e4a2e 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
@@ -272,7 +272,7 @@ static GHash *WM_manipulatormap_manipulator_hash_new(
/* collect manipulators */
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
- if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) {
+ if (WM_manipulator_group_type_poll(C, mgroup->type)) {
for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
if ((include_hidden || (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
(!poll || poll(mpr, data)))
@@ -350,7 +350,7 @@ static void manipulatormap_prepare_drawing(
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
/* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) ||
- !wm_manipulatorgroup_is_visible(mgroup, C))
+ !WM_manipulator_group_type_poll(C, mgroup->type))
{
continue;
}
@@ -597,7 +597,7 @@ wmManipulator *wm_manipulatormap_highlight_find(
continue;
}
- if (wm_manipulatorgroup_is_visible(mgroup, C)) {
+ if (WM_manipulator_group_type_poll(C, mgroup->type)) {
eWM_ManipulatorMapDrawStep step;
if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) {
step = WM_MANIPULATORMAP_DRAWSTEP_3D;
@@ -984,7 +984,7 @@ void WM_manipulatormap_message_subscribe(
bContext *C, wmManipulatorMap *mmap, ARegion *ar, struct wmMsgBus *mbus)
{
for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
- if (!wm_manipulatorgroup_is_visible(mgroup, C)) {
+ if (!WM_manipulator_group_type_poll(C, mgroup->type)) {
continue;
}
for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
index dba38dc8c8c..06a9c2de69b 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -40,7 +40,7 @@
/** \name Public API
* \{ */
-static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {NULL};
+static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {{{NULL}}};
typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *);
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
index f9d8d968b84..c9b43cc2a91 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -148,7 +148,6 @@ static void wm_msg_rna_update_by_id(
}
}
- printf("AAA ~ %d\n", remove);
if (remove) {
/* Failed to persist, remove the key. */
BLI_remlink(&mbus->messages, key);
@@ -301,14 +300,14 @@ void WM_msg_subscribe_ID(
struct wmMsgBus *mbus, ID *id, const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
- wmMsgParams_RNA msg_key_params = {NULL};
+ wmMsgParams_RNA msg_key_params = {{{NULL}}};
RNA_id_pointer_create(id, &msg_key_params.ptr);
WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr);
}
void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id)
{
- wmMsgParams_RNA msg_key_params = {NULL};
+ wmMsgParams_RNA msg_key_params = {{{NULL}}};
RNA_id_pointer_create(id, &msg_key_params.ptr);
WM_msg_publish_rna_params(mbus, &msg_key_params);
}
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 0264955a4c5..652cefb1a54 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -58,6 +58,7 @@ void wm_window_process_events (const bContext *C);
void wm_window_process_events_nosleep(void);
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
+void wm_window_reset_drawable(void);
void wm_window_raise (wmWindow *win);
void wm_window_lower (wmWindow *win);
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index dc7acb5ccd7..60abf0806d3 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -58,8 +58,8 @@ elseif(APPLE)
set(PLAYER_SOURCEINFO ${PLAYER_SOURCEDIR}/Contents/Info.plist)
set_target_properties(blenderplayer PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${PLAYER_SOURCEINFO}
- MACOSX_BUNDLE_SHORT_VERSION_STRING ${BLENDER_VERSION}
- MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION} ${BLENDER_DATE}")
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR}"
+ MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR} ${BLENDER_DATE}")
else()
add_executable(blenderplayer bad_level_call_stubs/stubs.c)
diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
index d2c2129532a..0a50c0876fb 100644
--- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
+++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../../blender/blenlib
../../blender/blenkernel
../../blender/blenloader
+ ../../blender/depsgraph
../../blender/makesdna
../../blender/makesrna
../../../intern/glew-mx
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index a0489d7609a..e4287dd78ae 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -152,7 +152,6 @@ struct wmManipulatorMap;
#include "../../intern/elbeem/extern/elbeem.h"
#include "../blender/blenkernel/BKE_modifier.h"
#include "../blender/blenkernel/BKE_paint.h"
-#include "../blender/collada/collada.h"
#include "../blender/compositor/COM_compositor.h"
#include "../blender/editors/include/ED_armature.h"
#include "../blender/editors/include/ED_anim_api.h"
@@ -239,10 +238,12 @@ bool BPY_string_is_keyword(const char *str) { return false; }
/* -------------------------------------------------------------------- */
/* Stubs */
+void DRW_deferred_shader_remove(struct GPUMaterial *mat) RET_NONE
+
/*new render funcs */
void EDBM_selectmode_set(struct BMEditMesh *em) RET_NONE
void EDBM_mesh_load(struct Object *ob) RET_NONE
-void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool use_key_index) RET_NONE
+void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool use_key_index) RET_NONE
void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
void *g_system;
bool EDBM_uv_check(struct BMEditMesh *em) RET_ZERO
@@ -281,7 +282,7 @@ int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], i
int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex, struct ImagePool *pool) RET_ZERO
-struct Material *RE_sample_material_init(struct Material *orig_mat, struct Scene *scene) RET_NULL
+struct Material *RE_sample_material_init(const struct EvaluationContext *eval_ctx, struct Material *orig_mat, struct Scene *scene) RET_NULL
void RE_sample_material_free(struct Material *mat) RET_NONE
void RE_sample_material_color(
struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
@@ -631,13 +632,9 @@ bool ED_transform_snap_object_project_ray_ex(
struct Object **r_ob, float r_obmat[4][4]) RET_ZERO
void BIF_selectTransformOrientationValue(struct View3D *v3d, int orientation) RET_NONE
-void ED_lattice_editlatt_make(struct Object *obedit) RET_NONE
-void ED_lattice_editlatt_load(struct Object *obedit) RET_NONE
-
void ED_curve_editnurb_load(struct Object *obedit) RET_NONE
void ED_curve_editnurb_make(struct Object *obedit) RET_NONE
-
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon) RET_NONE
void uiItemFullO(uiLayout *layout, const char *idname, const char *name, int icon, struct IDProperty *properties, int context, int flag, struct PointerRNA *r_opptr) RET_NONE
@@ -774,16 +771,14 @@ void RE_engine_update_memory_stats(struct RenderEngine *engine, float mem_used,
struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE
void RE_FreePersistentData(void) RET_NONE
-void RE_point_density_cache(struct Scene *scene, struct ViewLayer *view_layer, struct PointDensity *pd, const bool use_render_params) RET_NONE
-void RE_point_density_minmax(struct Scene *scene, struct ViewLayer *view_layer, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE
-void RE_point_density_sample(struct Scene *scene, struct ViewLayer *view_layer, struct PointDensity *pd, const int resolution, const bool use_render_params, float *values) RET_NONE
+void RE_point_density_cache(const struct EvaluationContext *eval_ctx, struct PointDensity *pd) RET_NONE
+void RE_point_density_minmax(const struct EvaluationContext *eval_ctx, struct PointDensity *pd, float r_min[3], float r_max[3]) RET_NONE
+void RE_point_density_sample(const struct EvaluationContext *eval_ctx, struct PointDensity *pd, const int resolution, float *values) RET_NONE
void RE_point_density_free(struct PointDensity *pd) RET_NONE
void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE
void RE_FreeAllPersistentData(void) RET_NONE
float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO
void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int channels, const char *chanid, int type) RET_NONE
-struct ViewLayer *RE_engine_get_view_layer(struct Render *re) RET_NULL
-void RE_SetDepsgraph(struct Render *re, struct Depsgraph *graph) RET_NONE
/* Draw */
void OBJECT_collection_settings_create(struct IDProperty *properties) RET_NONE
@@ -832,33 +827,6 @@ struct uiLayout *uiLayoutRadial(struct uiLayout *layout) RET_NULL
int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title, const char *opname,
const char *propname, const struct wmEvent *event) RET_ZERO
-/* RNA COLLADA dependency */
-int collada_export(const struct EvaluationContext *eval_ctx,
- struct Scene *sce,
- struct ViewLayer *view_layer,
- const char *filepath,
- int apply_modifiers,
- BC_export_mesh_type export_mesh_type,
-
- int selected,
- int include_children,
- int include_armatures,
- int include_shapekeys,
- int deform_bones_only,
-
- int active_uv_only,
- int include_material_textures,
- int use_texture_copies,
-
- int triangulate,
- int use_object_instantiation,
- int use_blender_profile,
- int sort_by_name,
- BC_export_transformation_type export_transformation_type,
- int open_sim,
- int limit_precision,
- int keep_bind_info) RET_ZERO
-
void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly) RET_NONE
/* bpy/python internal api */
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index b6229539cd9..177e9744510 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -870,8 +870,8 @@ elseif(APPLE)
set_target_properties(blender PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${OSX_APP_SOURCEDIR}/Contents/Info.plist
- MACOSX_BUNDLE_SHORT_VERSION_STRING ${BLENDER_VERSION}
- MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION} ${BLENDER_DATE}")
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR}"
+ MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR} ${BLENDER_DATE}")
# Gather the date in finder-style
execute_process(COMMAND date "+%m/%d/%Y/%H:%M"
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index fba3189d5ed..df4946a8175 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -428,26 +428,6 @@ static void arg_py_context_restore(
/** \} */
-static void render_set_depgraph(bContext *C, Render *re)
-{
- /* TODO(sergey): For until we make depsgraph to be created and
- * handled by render pipeline.
- */
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- /* NOTE: This is STUPID to use first layer, but is ok for now
- * (at least for until depsgraph becomes per-layer).
- * Apparently, CTX_data_layer is crashing here (context's layer
- * is NULL for old files, and there is no workspace).
- */
- ViewLayer *view_layer = scene->view_layers.first;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- DEG_graph_on_visible_update(bmain, depsgraph);
-
- RE_SetDepsgraph(re, depsgraph);
-}
-
/* -------------------------------------------------------------------- */
/** \name Handle Argument Callbacks
@@ -524,7 +504,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf("\n");
printf("Window Options:\n");
BLI_argsPrintArgDoc(ba, "--window-border");
- BLI_argsPrintArgDoc(ba, "--window-borderless");
+ BLI_argsPrintArgDoc(ba, "--window-fullscreen");
BLI_argsPrintArgDoc(ba, "--window-geometry");
BLI_argsPrintArgDoc(ba, "--start-console");
BLI_argsPrintArgDoc(ba, "--no-native-pixels");
@@ -570,6 +550,9 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--debug-jobs");
BLI_argsPrintArgDoc(ba, "--debug-python");
BLI_argsPrintArgDoc(ba, "--debug-depsgraph");
+ BLI_argsPrintArgDoc(ba, "--debug-depsgraph-eval");
+ BLI_argsPrintArgDoc(ba, "--debug-depsgraph-build");
+ BLI_argsPrintArgDoc(ba, "--debug-depsgraph-tag");
BLI_argsPrintArgDoc(ba, "--debug-depsgraph-no-threads");
BLI_argsPrintArgDoc(ba, "--debug-gpumem");
@@ -765,9 +748,19 @@ static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
"\n\tEnable gpu debug context and information for OpenGL 4.3+.";
static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
-"\n\tEnable debug messages from dependency graph.";
+"\n\tEnable all debug messages from dependency graph.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_build[] =
+"\n\tEnable debug messages from dependency graph related on graph construction.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_tag[] =
+"\n\tEnable debug messages from dependency graph related on tagging.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_time[] =
+"\n\tEnable debug messages from dependency graph related on timing.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_eval[] =
+"\n\tEnable debug messages from dependency graph related on evaluation.";
static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
"\n\tSwitch dependency graph to a single threaded evaluation.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_pretty[] =
+"\n\tEnable colors for dependency graph debug messages.";
static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
"\n\tEnable GPU memory stats in status bar.";
@@ -981,7 +974,7 @@ static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv),
}
static const char arg_handle_without_borders_doc[] =
-"\n\tForce opening without borders."
+"\n\tForce opening in fullscreen mode."
;
static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -1376,7 +1369,6 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
BLI_threaded_malloc_begin();
BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
- render_set_depgraph(C, re);
for (int i = 0; i < frames_range_len; i++) {
/* We could pass in frame ranges,
* but prefer having exact behavior as passing in multiple frames */
@@ -1419,7 +1411,6 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg
BLI_threaded_malloc_begin();
BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
- render_set_depgraph(C, re);
RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
RE_SetReports(re, NULL);
BKE_reports_clear(&reports);
@@ -1855,8 +1846,18 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, gpu), (void *)G_DEBUG_GPU);
BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph",
CB_EX(arg_handle_debug_mode_generic_set, depsgraph), (void *)G_DEBUG_DEPSGRAPH);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-build",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph_build), (void *)G_DEBUG_DEPSGRAPH_BUILD);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-eval",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph_eval), (void *)G_DEBUG_DEPSGRAPH_EVAL);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-tag",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph_tag), (void *)G_DEBUG_DEPSGRAPH_TAG);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-time",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph_time), (void *)G_DEBUG_DEPSGRAPH_TIME);
BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads",
CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads), (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-pretty",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph_pretty), (void *)G_DEBUG_DEPSGRAPH_PRETTY);
BLI_argsAdd(ba, 1, NULL, "--debug-gpumem",
CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
BLI_argsAdd(ba, 1, NULL, "--debug-gpu-shaders",
@@ -1876,7 +1877,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
/* second pass: custom window stuff */
BLI_argsAdd(ba, 2, "-p", "--window-geometry", CB(arg_handle_window_geometry), NULL);
BLI_argsAdd(ba, 2, "-w", "--window-border", CB(arg_handle_with_borders), NULL);
- BLI_argsAdd(ba, 2, "-W", "--window-borderless", CB(arg_handle_without_borders), NULL);
+ BLI_argsAdd(ba, 2, "-W", "--window-fullscreen", CB(arg_handle_without_borders), NULL);
BLI_argsAdd(ba, 2, "-con", "--start-console", CB(arg_handle_start_with_console), NULL);
BLI_argsAdd(ba, 2, "-R", NULL, CB(arg_handle_register_extension), NULL);
BLI_argsAdd(ba, 2, "-r", NULL, CB_EX(arg_handle_register_extension, silent), ba);
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index dda1864f07c..c390bff09a4 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -2059,7 +2059,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
for (git=tempglist.begin(); git!=tempglist.end(); git++)
{
Group* group = *git;
- FOREACH_GROUP_OBJECT(group, blenderobject)
+ FOREACH_GROUP_OBJECT_BEGIN(group, blenderobject)
{
if (converter->FindGameObject(blenderobject) == NULL)
{
@@ -2095,7 +2095,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
}
}
}
- FOREACH_GROUP_OBJECT_END
+ FOREACH_GROUP_OBJECT_END;
}
}
}
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 48b50d24975..0e6b04c6df5 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -738,7 +738,7 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
m_groupGameObjects.clear();
group = blgroupobj->dup_group;
- FOREACH_GROUP_BASE(group, base)
+ FOREACH_GROUP_BASE_BEGIN(group, base)
{
Object *blenderobj = base->object;
if (blgroupobj == blenderobj)
@@ -761,7 +761,7 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
}
m_groupGameObjects.insert(gameobj);
}
- FOREACH_GROUP_BASE_END
+ FOREACH_GROUP_BASE_END;
set<CValue*>::iterator oit;
for (oit=m_groupGameObjects.begin(); oit != m_groupGameObjects.end(); oit++)
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
index 10196804656..11ec97ca5f8 100644
--- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -228,7 +228,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
codecCtx->frame_rate_base=1000;
m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
#else
- m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx->streams[videoStream]));
+ m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx, formatCtx->streams[videoStream]));
#endif
if (m_baseFrameRate <= 0.0)
m_baseFrameRate = defFrameRate;
diff --git a/source/tools b/source/tools
-Subproject b11375e89061303401376f7aeae42ac2fd64692
+Subproject 7695e14cfc5820ac66546e0e515914d85ab81af
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index f973488d657..3abfe29c000 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -27,6 +27,7 @@
set(USE_EXPERIMENTAL_TESTS FALSE)
set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
+set(TEST_DATA_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests_data)
set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
# ugh, any better way to do this on testing only?
@@ -546,20 +547,22 @@ if(WITH_CYCLES)
add_cycles_render_test(opengl)
endif()
add_cycles_render_test(bake)
+ add_cycles_render_test(bsdf)
add_cycles_render_test(denoise)
add_cycles_render_test(displacement)
+ add_cycles_render_test(hair)
add_cycles_render_test(image_data_types)
add_cycles_render_test(image_mapping)
add_cycles_render_test(image_texture_limit)
+ add_cycles_render_test(integrator)
add_cycles_render_test(light)
- add_cycles_render_test(mblur)
+ add_cycles_render_test(mesh)
+ add_cycles_render_test(motion_blur)
+ add_cycles_render_test(render_layer)
add_cycles_render_test(reports)
- add_cycles_render_test(render)
add_cycles_render_test(shader)
- add_cycles_render_test(shader_tangent)
add_cycles_render_test(shadow_catcher)
add_cycles_render_test(sss)
- add_cycles_render_test(texture_space)
add_cycles_render_test(volume)
else()
MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist")
@@ -617,4 +620,14 @@ if(WITH_ALEMBIC)
)
endif()
+if(WITH_CODEC_FFMPEG)
+ add_python_test(
+ ffmpeg_tests
+ ${CMAKE_CURRENT_LIST_DIR}/ffmpeg_tests.py
+ --blender "$<TARGET_FILE:blender>"
+ --testdir "${TEST_DATA_SRC_DIR}/ffmpeg"
+ )
+endif()
+
+add_subdirectory(collada)
add_subdirectory(view_layer)
diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py
index 96a68de9801..b9dc78a821f 100755
--- a/tests/python/alembic_tests.py
+++ b/tests/python/alembic_tests.py
@@ -28,37 +28,17 @@ import sys
import tempfile
import unittest
+from modules.test_utils import (with_tempdir,
+ AbstractBlenderRunnerTest,
+ )
-def with_tempdir(wrapped):
- """Creates a temporary directory for the function, cleaning up after it returns normally.
-
- When the wrapped function raises an exception, the contents of the temporary directory
- remain available for manual inspection.
-
- The wrapped function is called with an extra positional argument containing
- the pathlib.Path() of the temporary directory.
- """
-
- @functools.wraps(wrapped)
- def decorator(*args, **kwargs):
- dirname = tempfile.mkdtemp(prefix='blender-alembic-test')
- try:
- retval = wrapped(*args, pathlib.Path(dirname), **kwargs)
- except:
- print('Exception in %s, not cleaning up temporary directory %s' % (wrapped, dirname))
- raise
- else:
- shutil.rmtree(dirname)
- return retval
-
- return decorator
class AbcPropError(Exception):
"""Raised when AbstractAlembicTest.abcprop() finds an error."""
-class AbstractAlembicTest(unittest.TestCase):
+class AbstractAlembicTest(AbstractBlenderRunnerTest):
@classmethod
def setUpClass(cls):
import re
@@ -74,37 +54,6 @@ class AbstractAlembicTest(unittest.TestCase):
# 'abcls' array notation, like "name[16]"
cls.abcls_array = re.compile(r'^(?P<name>[^\[]+)(\[(?P<arraysize>\d+)\])?$')
- def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str:
- """Runs Blender by opening a blendfile and executing a script.
-
- Returns Blender's stdout + stderr combined into one string.
-
- :param filepath: taken relative to self.testdir.
- :param timeout: in seconds
- """
-
- blendfile = self.testdir / filepath
-
- command = (
- self.blender,
- '--background',
- '-noaudio',
- '--factory-startup',
- '--enable-autoexec',
- str(blendfile),
- '-E', 'CYCLES',
- '--python-exit-code', '47',
- '--python-expr', python_script,
- )
-
- proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
- timeout=timeout)
- output = proc.stdout.decode('utf8')
- if proc.returncode:
- self.fail('Error %d running Blender:\n%s' % (proc.returncode, output))
-
- return output
-
def abcprop(self, filepath: pathlib.Path, proppath: str) -> dict:
"""Uses abcls to obtain compound property values from an Alembic object.
diff --git a/tests/python/collada/CMakeLists.txt b/tests/python/collada/CMakeLists.txt
new file mode 100644
index 00000000000..421e4ba7667
--- /dev/null
+++ b/tests/python/collada/CMakeLists.txt
@@ -0,0 +1,66 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# --env-system-scripts allows to run without the install target.
+
+# Use '--write-blend=/tmp/test.blend' to view output
+
+# Some tests are interesting but take too long to run
+# and don't give deterministic results
+set(USE_EXPERIMENTAL_TESTS FALSE)
+
+set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
+set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
+
+# ugh, any better way to do this on testing only?
+execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR})
+
+#~ if(NOT IS_DIRECTORY ${TEST_SRC_DIR})
+#~ message(FATAL_ERROR "CMake test directory not found!")
+#~ endif()
+
+# all calls to blender use this
+if(APPLE)
+ if(${CMAKE_GENERATOR} MATCHES "Xcode")
+ set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup)
+ else()
+ set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
+ endif()
+else()
+ set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
+endif()
+
+# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
+# set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE})
+# set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} ${TEST_BLENDER_EXE_PARAMS} )
+
+# ------------------------------------------------------------------------------
+# GENERAL PYTHON CORRECTNESS TESTS
+macro (COLLADA_TEST module test_name blend_file)
+ add_test(
+ NAME collada_${module}_${test_name}
+ COMMAND "$<TARGET_FILE:blender>" ${TEST_BLENDER_EXE_PARAMS} ${TEST_SRC_DIR}/collada/${module}/${blend_file}
+ --python ${CMAKE_CURRENT_LIST_DIR}/${module}/test_${module}_${test_name}.py --
+ --testdir ${TEST_SRC_DIR}/collada/${module}
+ )
+endmacro()
+
+COLLADA_TEST(mesh simple mesh_simple.blend)
+COLLADA_TEST(animation simple suzannes_parent_inverse.blend)
diff --git a/tests/python/collada/animation/test_animation_simple.py b/tests/python/collada/animation/test_animation_simple.py
new file mode 100644
index 00000000000..6686d429261
--- /dev/null
+++ b/tests/python/collada/animation/test_animation_simple.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env python3
+# ##### 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 #####
+#
+# Call as follows:
+# python collada_mesh_simple.py --blender PATH_TO_BLENDER_EXE --testdir PATH_TO_SVN/lib/tests/collada/mesh
+#
+import sys
+import bpy
+import argparse
+import functools
+import shutil
+import tempfile
+import unittest
+import difflib
+import pathlib
+from pathlib import Path
+
+def with_tempdir(wrapped):
+ """Creates a temporary directory for the function, cleaning up after it returns normally.
+
+ When the wrapped function raises an exception, the contents of the temporary directory
+ remain available for manual inspection.
+
+ The wrapped function is called with an extra positional argument containing
+ the pathlib.Path() of the temporary directory.
+ """
+
+ @functools.wraps(wrapped)
+ def decorator(*args, **kwargs):
+ dirname = tempfile.mkdtemp(prefix='blender-collada-test')
+ #print("Using tempdir %s" % dirname)
+ try:
+ retval = wrapped(*args, pathlib.Path(dirname), **kwargs)
+ except:
+ print('Exception in %s, not cleaning up temporary directory %s' % (wrapped, dirname))
+ raise
+ else:
+ shutil.rmtree(dirname)
+ return retval
+
+ return decorator
+
+LINE = "+----------------------------------------------------------------"
+
+class AbstractColladaTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.testdir = pathlib.Path(args.testdir)
+
+ def checkdae(self, reference, export):
+ """
+ collada verifier checks if exported dae file is the same as reference dae
+ """
+
+ ref = open(reference)
+ exp = open(export)
+ diff=difflib.unified_diff(ref.readlines(), exp.readlines(), lineterm='', n=0)
+ ref.close()
+ exp.close()
+
+ diff_count = 0;
+ for line in diff:
+ error = True
+ for prefix in ('---', '+++', '@@'):
+ # Ignore diff metadata
+ if line.startswith(prefix):
+ error=False
+ break
+ else:
+ # Ignore time stamps
+ for ignore in ('<created>', '<modified>', '<authoring_tool>'):
+ if line[1:].strip().startswith(ignore):
+ error=False
+ break
+ if error:
+ diff_count +=1
+ pline = line.strip()
+ if diff_count == 1:
+ print("\n%s" % LINE)
+ print("|Test has errors:")
+ print(LINE)
+ pre = "reference" if pline[0] == "-" else "generated"
+ print ("| %s:%s"% (pre, pline[1:]))
+
+ if diff_count > 0:
+ print(LINE)
+ print("ref :%s" % reference)
+ print("test:%s" % export)
+ print("%s\n" % LINE)
+
+ return diff_count == 0
+
+class MeshExportTest4(AbstractColladaTest):
+ @with_tempdir
+ def test_export_animation_suzannes_sample_matrix(self, tempdir: pathlib.Path):
+ test = "suzannes_parent_inverse_sample_10_matrix"
+ reference_dae = self.testdir / Path("%s.dae" % test)
+ outfile = tempdir / Path("%s_out.dae" % test)
+
+ bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=True,
+ sampling_rate=10,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='matrix',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
+ keep_bind_info=False)
+
+ # Now check the resulting Collada file.
+ if not self.checkdae(reference_dae, outfile):
+ self.fail()
+
+class MeshExportTest3(AbstractColladaTest):
+ @with_tempdir
+ def test_export_animation_suzannes_sample_locrotscale(self, tempdir: pathlib.Path):
+ test = "suzannes_parent_inverse_sample_10_channels"
+ reference_dae = self.testdir / Path("%s.dae" % test)
+ outfile = tempdir / Path("%s_out.dae" % test)
+
+ bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=True,
+ sampling_rate=10,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='transrotloc',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
+ keep_bind_info=False)
+
+ # Now check the resulting Collada file.
+ if not self.checkdae(reference_dae, outfile):
+ self.fail()
+
+class MeshExportTest2(AbstractColladaTest):
+ @with_tempdir
+ def test_export_animation_suzannes_keyframe_matrix(self, tempdir: pathlib.Path):
+ test = "suzannes_parent_inverse_keyframes_matrix"
+ reference_dae = self.testdir / Path("%s.dae" % test)
+ outfile = tempdir / Path("%s_out.dae" % test)
+
+ bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=False,
+ sampling_rate=1,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='matrix',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
+ keep_bind_info=False)
+
+ # Now check the resulting Collada file.
+ if not self.checkdae(reference_dae, outfile):
+ self.fail()
+
+class MeshExportTest1(AbstractColladaTest):
+ @with_tempdir
+ def test_export_animation_suzannes_keyframe_locrotscale(self, tempdir: pathlib.Path):
+ test = "suzannes_parent_inverse_keyframes_channels"
+ reference_dae = self.testdir / Path("%s.dae" % test)
+ outfile = tempdir / Path("%s_out.dae" % test)
+
+ bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=False,
+ sampling_rate=1,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='transrotloc',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
+ keep_bind_info=False)
+
+ # Now check the resulting Collada file.
+ if not self.checkdae(reference_dae, outfile):
+ self.fail()
+
+
+if __name__ == '__main__':
+ sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--testdir', required=True)
+ args, remaining = parser.parse_known_args()
+ unittest.main(argv=sys.argv[0:1]+remaining) \ No newline at end of file
diff --git a/tests/python/collada/mesh/test_mesh_simple.py b/tests/python/collada/mesh/test_mesh_simple.py
new file mode 100644
index 00000000000..f592160f6aa
--- /dev/null
+++ b/tests/python/collada/mesh/test_mesh_simple.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+# ##### 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 #####
+#
+# Call as follows:
+# python collada_mesh_simple.py --blender PATH_TO_BLENDER_EXE --testdir PATH_TO_SVN/lib/tests/collada/mesh
+#
+import sys
+import bpy
+import argparse
+import functools
+import shutil
+import tempfile
+import unittest
+import difflib
+import pathlib
+from pathlib import Path
+
+def with_tempdir(wrapped):
+ """Creates a temporary directory for the function, cleaning up after it returns normally.
+
+ When the wrapped function raises an exception, the contents of the temporary directory
+ remain available for manual inspection.
+
+ The wrapped function is called with an extra positional argument containing
+ the pathlib.Path() of the temporary directory.
+ """
+
+ @functools.wraps(wrapped)
+ def decorator(*args, **kwargs):
+ dirname = tempfile.mkdtemp(prefix='blender-collada-test')
+ #print("Using tempdir %s" % dirname)
+ try:
+ retval = wrapped(*args, pathlib.Path(dirname), **kwargs)
+ except:
+ print('Exception in %s, not cleaning up temporary directory %s' % (wrapped, dirname))
+ raise
+ else:
+ shutil.rmtree(dirname)
+ return retval
+
+ return decorator
+
+LINE = "+----------------------------------------------------------------"
+
+class AbstractColladaTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.testdir = pathlib.Path(args.testdir)
+
+ def checkdae(self, reference, export):
+ """
+ collada verifier checks if exported dae file is the same as reference dae
+ """
+
+ ref = open(reference)
+ exp = open(export)
+ diff=difflib.unified_diff(ref.readlines(), exp.readlines(), lineterm='', n=0)
+ ref.close()
+ exp.close()
+
+ diff_count = 0;
+ for line in diff:
+ error = True
+ for prefix in ('---', '+++', '@@'):
+ # Ignore diff metadata
+ if line.startswith(prefix):
+ error=False
+ break
+ else:
+ # Ignore time stamps
+ for ignore in ('<created>', '<modified>', '<authoring_tool>'):
+ if line[1:].strip().startswith(ignore):
+ error=False
+ break
+ if error:
+ diff_count +=1
+ pline = line.strip()
+ if diff_count == 1:
+ print("\n%s" % LINE)
+ print("|Test has errors:")
+ print(LINE)
+ pre = "reference" if pline[0] == "-" else "generated"
+ print ("| %s:%s"% (pre, pline[1:]))
+
+ if diff_count > 0:
+ print(LINE)
+ print("ref :%s" % reference)
+ print("test:%s" % export)
+ print("%s\n" % LINE)
+
+ return diff_count == 0
+
+class MeshExportTest(AbstractColladaTest):
+ @with_tempdir
+ def test_export_single_mesh(self, tempdir: pathlib.Path):
+ test = "mesh_simple_001"
+ reference_dae = self.testdir / Path("%s.dae" % test)
+ outfile = tempdir / Path("%s_out.dae" % test)
+
+ bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
+ check_existing=True,
+ filemode=8,
+ display_type="DEFAULT",
+ sort_method="FILE_SORT_ALPHA",
+ apply_modifiers=False,
+ export_mesh_type=0,
+ export_mesh_type_selection="view",
+ selected=False,
+ include_children=False,
+ include_armatures=False,
+ include_shapekeys=True,
+ deform_bones_only=False,
+ sampling_rate=0,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection="matrix",
+ export_texture_type=0,
+ export_texture_type_selection="mat",
+ open_sim=False,
+ limit_precision=False,
+ keep_bind_info=False)
+
+ # Now check the resulting Collada file.
+ if not self.checkdae(reference_dae, outfile):
+ self.fail()
+
+if __name__ == '__main__':
+ sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--testdir', required=True)
+ args, remaining = parser.parse_known_args()
+ unittest.main(argv=sys.argv[0:1]+remaining) \ No newline at end of file
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
new file mode 100755
index 00000000000..9493d6f7a17
--- /dev/null
+++ b/tests/python/ffmpeg_tests.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import argparse
+import functools
+import shutil
+import pathlib
+import subprocess
+import sys
+import tempfile
+import unittest
+
+from modules.test_utils import AbstractBlenderRunnerTest
+
+
+class AbstractFFmpegTest(AbstractBlenderRunnerTest):
+ @classmethod
+ def setUpClass(cls):
+ cls.blender = args.blender
+ cls.testdir = pathlib.Path(args.testdir)
+
+
+class AbstractFFmpegSequencerTest(AbstractFFmpegTest):
+ def get_script_for_file(self, filename: pathlib.Path) -> str:
+ movie = self.testdir / filename
+ return \
+ "import bpy; " \
+ "bpy.context.scene.sequence_editor_create(); " \
+ "strip = bpy.context.scene.sequence_editor.sequences.new_movie(" \
+ "'test_movie', %r, channel=1, frame_start=1); " \
+ "print(f'fps:{strip.fps}')" % movie.as_posix()
+
+ def get_movie_file_fps(self, filename: pathlib.Path) -> float:
+ script = self.get_script_for_file(filename)
+ output = self.run_blender('', script)
+ for line in output.splitlines():
+ if line.startswith('fps:'):
+ return float(line.split(':')[1])
+ return 0.0
+
+
+class FPSDetectionTest(AbstractFFmpegSequencerTest):
+ def test_T51153(self):
+ self.assertAlmostEqual(
+ self.get_movie_file_fps('T51153_bad_clip_2.mts'),
+ 29.97,
+ places=2)
+
+ def test_T53857(self):
+ self.assertAlmostEqual(
+ self.get_movie_file_fps('T53857_2018-01-22_15-30-49.mkv'),
+ 30.0,
+ places=2)
+
+ def test_T54148(self):
+ self.assertAlmostEqual(
+ self.get_movie_file_fps('T54148_magn_0.mkv'),
+ 1.0,
+ places=2)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--blender', required=True)
+ parser.add_argument('--testdir', required=True)
+ args, remaining = parser.parse_known_args()
+
+ unittest.main(argv=sys.argv[0:1] + remaining)
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
new file mode 100755
index 00000000000..55ef882c49c
--- /dev/null
+++ b/tests/python/modules/test_utils.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import argparse
+import functools
+import shutil
+import pathlib
+import re
+import subprocess
+import sys
+import tempfile
+import unittest
+
+
+def with_tempdir(wrapped):
+ """Creates a temporary directory for the function, cleaning up after it returns normally.
+
+ When the wrapped function raises an exception, the contents of the temporary directory
+ remain available for manual inspection.
+
+ The wrapped function is called with an extra positional argument containing
+ the pathlib.Path() of the temporary directory.
+ """
+
+ @functools.wraps(wrapped)
+ def decorator(*args, **kwargs):
+ dirname = tempfile.mkdtemp(prefix='blender-alembic-test')
+ try:
+ retval = wrapped(*args, pathlib.Path(dirname), **kwargs)
+ except:
+ print('Exception in %s, not cleaning up temporary directory %s' % (wrapped, dirname))
+ raise
+ else:
+ shutil.rmtree(dirname)
+ return retval
+
+ return decorator
+
+
+class AbstractBlenderRunnerTest(unittest.TestCase):
+ """Base class for all test suites which needs to run Blender"""
+
+ # Set in a subclass
+ blender: pathlib.Path = None
+ testdir: pathlib.Path = None
+
+
+ def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str:
+ """Runs Blender by opening a blendfile and executing a script.
+
+ Returns Blender's stdout + stderr combined into one string.
+
+ :param filepath: taken relative to self.testdir.
+ :param timeout: in seconds
+ """
+
+ assert self.blender, "Path to Blender binary is to be set in setUpClass()"
+ assert self.testdir, "Path to tests binary is to be set in setUpClass()"
+
+ blendfile = self.testdir / filepath if filepath else ""
+
+ command = [
+ self.blender,
+ '--background',
+ '-noaudio',
+ '--factory-startup',
+ '--enable-autoexec',
+ ]
+
+ if blendfile:
+ command.append(str(blendfile))
+
+ command.extend([
+ '-E', 'CYCLES',
+ '--python-exit-code', '47',
+ '--python-expr', python_script,
+ ]
+ )
+
+ proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ timeout=timeout)
+ output = proc.stdout.decode('utf8')
+ if proc.returncode:
+ self.fail('Error %d running Blender:\n%s' % (proc.returncode, output))
+
+ return output
+
diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt
index cc5a3ba54b1..9cb33420ac5 100644
--- a/tests/python/view_layer/CMakeLists.txt
+++ b/tests/python/view_layer/CMakeLists.txt
@@ -94,6 +94,7 @@ VIEW_LAYER_TEST(group_a)
VIEW_LAYER_TEST(group_b)
VIEW_LAYER_TEST(group_c)
VIEW_LAYER_TEST(group_d)
+VIEW_LAYER_TEST(group_e)
VIEW_LAYER_TEST(object_add_cylinder)
VIEW_LAYER_TEST(object_add_empty)
VIEW_LAYER_TEST(object_add_torus)
@@ -107,6 +108,7 @@ VIEW_LAYER_TEST(object_link_a)
VIEW_LAYER_TEST(object_link_b)
VIEW_LAYER_TEST(object_link_c)
VIEW_LAYER_TEST(operator_context)
+VIEW_LAYER_TEST(make_single_user)
VIEW_LAYER_TEST(move_above_below_scene_collection_a)
VIEW_LAYER_TEST(move_above_below_scene_collection_b)
VIEW_LAYER_TEST(move_above_below_scene_collection_c)
diff --git a/tests/python/view_layer/test_group_e.py b/tests/python/view_layer/test_group_e.py
new file mode 100644
index 00000000000..566c043572e
--- /dev/null
+++ b/tests/python/view_layer/test_group_e.py
@@ -0,0 +1,72 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_group_delete_object(self):
+ """
+ See if we can safely remove instanced objects
+ """
+ import bpy
+ scene = bpy.context.scene
+ view_layer = bpy.context.view_layer
+ ob = bpy.context.object
+
+ # clean up the scene a bit
+ for o in (o for o in view_layer.objects if o != ob):
+ view_layer.collections[0].collection.objects.unlink(o)
+
+ for v in (v for v in scene.view_layers if v != view_layer):
+ scene.view_layers.remove(v)
+
+ # update depsgraph
+ scene.update()
+
+ # create group
+ group = bpy.data.groups.new("Switch")
+ group.objects.link(ob)
+
+ # update depsgraph
+ scene.update()
+
+ # instance the group
+ empty = bpy.data.objects.new("Empty", None)
+ bpy.context.scene_collection.objects.link(empty)
+ layer_collection = bpy.context.layer_collection
+ empty.dupli_type = 'GROUP'
+ empty.dupli_group = group
+
+ # prepare to delete the original object
+ # we could just pass an overridden context
+ # but let's do it the old fashion way
+ view_layer.objects.active = ob
+ ob.select_set('SELECT')
+ self.assertTrue(ob.select_get())
+ empty.select_set('DESELECT')
+ self.assertFalse(empty.select_get())
+
+ # update depsgraph
+ scene.update()
+
+ # delete the original object
+ bpy.ops.object.delete()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_make_single_user.py b/tests/python/view_layer/test_make_single_user.py
new file mode 100644
index 00000000000..2a8a479bab2
--- /dev/null
+++ b/tests/python/view_layer/test_make_single_user.py
@@ -0,0 +1,54 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_make_single_user(self):
+ """
+ Really basic test, just to check for crashes on basic files.
+ """
+ import bpy
+ scene = bpy.context.scene
+ master_collection = scene.master_collection
+ view_layer = bpy.context.view_layer
+ ob = bpy.context.object
+
+ # clean up the scene a bit
+ for o in (o for o in view_layer.objects if o != ob):
+ view_layer.collections[0].collection.objects.unlink(o)
+
+ for v in (v for v in scene.view_layers if v != view_layer):
+ scene.view_layers.remove(v)
+
+ while master_collection.collections:
+ master_collection.collections.remove(
+ master_collection.collections[0])
+
+ view_layer.collections.link(master_collection)
+ ob.select_set('SELECT')
+
+ # update depsgraph
+ scene.update()
+
+ # test itself
+ bpy.ops.object.make_single_user(object=True)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()