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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2020-03-12 17:58:03 +0300
committerJulian Eisel <julian@blender.org>2020-03-12 17:58:03 +0300
commitb86be9b2145458037fd0b17433b7af0efa7b6472 (patch)
treef333625555402992ebb35d258f93eda1130389e6
parent00f83ec125207e90bf180b3eb7752d8cb6482a86 (diff)
parentcb6cec904fa14ce0ab10a2a53af5c936d56376cf (diff)
Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside
-rw-r--r--extern/bullet2/CMakeLists.txt7
-rw-r--r--extern/glog/CMakeLists.txt5
-rw-r--r--intern/cycles/CMakeLists.txt13
-rw-r--r--intern/cycles/app/cycles_xml.cpp2
-rw-r--r--intern/cycles/blender/CMakeLists.txt1
-rw-r--r--intern/cycles/blender/addon/properties.py1
-rw-r--r--intern/cycles/blender/addon/ui.py2
-rw-r--r--intern/cycles/blender/blender_device.cpp2
-rw-r--r--intern/cycles/blender/blender_geometry.cpp2
-rw-r--r--intern/cycles/blender/blender_image.cpp380
-rw-r--r--intern/cycles/blender/blender_image.h61
-rw-r--r--intern/cycles/blender/blender_session.cpp8
-rw-r--r--intern/cycles/blender/blender_session.h16
-rw-r--r--intern/cycles/blender/blender_shader.cpp84
-rw-r--r--intern/cycles/blender/blender_sync.cpp1
-rw-r--r--intern/cycles/blender/blender_sync.h2
-rw-r--r--intern/cycles/blender/blender_volume.cpp180
-rw-r--r--intern/cycles/bvh/bvh.cpp10
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp1
-rw-r--r--intern/cycles/device/cuda/device_cuda_impl.cpp11
-rw-r--r--intern/cycles/device/device_cpu.cpp11
-rw-r--r--intern/cycles/device/device_memory.cpp1
-rw-r--r--intern/cycles/device/device_memory.h1
-rw-r--r--intern/cycles/device/device_optix.cpp11
-rw-r--r--intern/cycles/device/opencl/device_opencl_impl.cpp2
-rw-r--r--intern/cycles/kernel/kernel_random.h2
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h4
-rw-r--r--intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h4
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h2
-rw-r--r--intern/cycles/kernel/osl/CMakeLists.txt3
-rw-r--r--intern/cycles/kernel/svm/svm_image.h4
-rw-r--r--intern/cycles/render/CMakeLists.txt4
-rw-r--r--intern/cycles/render/attribute.cpp88
-rw-r--r--intern/cycles/render/attribute.h36
-rw-r--r--intern/cycles/render/colorspace.cpp12
-rw-r--r--intern/cycles/render/geometry.cpp17
-rw-r--r--intern/cycles/render/geometry.h2
-rw-r--r--intern/cycles/render/image.cpp768
-rw-r--r--intern/cycles/render/image.h217
-rw-r--r--intern/cycles/render/image_oiio.cpp236
-rw-r--r--intern/cycles/render/image_oiio.h48
-rw-r--r--intern/cycles/render/light.cpp4
-rw-r--r--intern/cycles/render/mesh_volume.cpp6
-rw-r--r--intern/cycles/render/nodes.cpp390
-rw-r--r--intern/cycles/render/nodes.h53
-rw-r--r--intern/cycles/render/osl.cpp25
-rw-r--r--intern/cycles/render/osl.h7
-rw-r--r--intern/cycles/render/scene.cpp6
-rw-r--r--intern/cycles/render/scene.h1
-rw-r--r--intern/cycles/render/session.cpp13
-rw-r--r--intern/cycles/render/shader.cpp45
-rw-r--r--intern/cycles/render/shader.h4
-rw-r--r--intern/cycles/render/svm.cpp3
-rw-r--r--intern/cycles/util/util_profiling.cpp1
-rw-r--r--intern/cycles/util/util_profiling.h1
-rw-r--r--intern/cycles/util/util_texture.h3
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp2
-rw-r--r--intern/ghost/test/CMakeLists.txt141
-rw-r--r--intern/ghost/test/multitest/MultiTest.c102
-rw-r--r--intern/ghost/test/multitest/stubs.c29
-rw-r--r--intern/mantaflow/extern/manta_fluid_API.h16
-rw-r--r--intern/mantaflow/intern/manta_fluid_API.cpp43
-rw-r--r--release/scripts/modules/bl_ui_utils/bug_report_url.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py32
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py29
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py8
-rw-r--r--source/blender/blendthumb/CMakeLists.txt2
-rw-r--r--source/blender/blendthumb/src/Dll.cpp6
-rw-r--r--source/blender/blenfont/intern/blf.c8
-rw-r--r--source/blender/blenfont/intern/blf_font.c2
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c6
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h26
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_ocean.h8
-rw-r--r--source/blender/blenkernel/BKE_scene.h1
-rw-r--r--source/blender/blenkernel/BKE_screen.h2
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/armature.c4
-rw-r--r--source/blender/blenkernel/intern/brush.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c6
-rw-r--r--source/blender/blenkernel/intern/fluid.c6
-rw-r--r--source/blender/blenkernel/intern/image.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c8
-rw-r--r--source/blender/blenkernel/intern/lib_query.c38
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c43
-rw-r--r--source/blender/blenkernel/intern/main_idmap.c2
-rw-r--r--source/blender/blenkernel/intern/node.c17
-rw-r--r--source/blender/blenkernel/intern/ocean.c159
-rw-r--r--source/blender/blenkernel/intern/ocean_intern.h137
-rw-r--r--source/blender/blenkernel/intern/ocean_spectrum.c224
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/scene.c16
-rw-r--r--source/blender/blenkernel/intern/tracking.c2
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c26
-rw-r--r--source/blender/blenloader/intern/versioning_280.c16
-rw-r--r--source/blender/blenloader/intern/writefile.c6
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc12
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc11
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc16
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h3
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h5
-rw-r--r--source/blender/draw/CMakeLists.txt48
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c158
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c61
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c16
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h33
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c50
-rw-r--r--source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl130
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl22
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl18
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c3
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl81
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl97
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl154
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl44
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl47
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl34
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl30
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl103
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl31
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl24
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl44
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl11
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl36
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl20
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl118
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl83
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl30
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl18
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl97
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl94
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl114
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl16
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl89
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl26
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl40
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl88
-rw-r--r--source/blender/draw/engines/workbench/solid_mode.c119
-rw-r--r--source/blender/draw/engines/workbench/transparent_mode.c97
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c407
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c1415
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_aa.c101
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_antialiasing.c421
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_cavity.c182
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c217
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_fxaa.c59
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_outline.c55
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_taa.c305
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c547
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.h2
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c817
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c529
-rw-r--r--source/blender/draw/engines/workbench/workbench_opaque.c165
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h670
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c95
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.c533
-rw-r--r--source/blender/draw/engines/workbench/workbench_shadow.c367
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c257
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c180
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c123
-rw-r--r--source/blender/draw/intern/DRW_render.h109
-rw-r--r--source/blender/draw/intern/draw_common.h5
-rw-r--r--source/blender/draw/intern/draw_hair.c51
-rw-r--r--source/blender/draw/intern/draw_manager.c38
-rw-r--r--source/blender/draw/intern/draw_manager_data.c20
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c187
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c141
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c16
-rw-r--r--source/blender/editors/animation/anim_filter.c118
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c3
-rw-r--r--source/blender/editors/armature/armature_select.c7
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c18
-rw-r--r--source/blender/editors/include/UI_interface.h3
-rw-r--r--source/blender/editors/interface/interface_handlers.c7
-rw-r--r--source/blender/editors/interface/interface_intern.h8
-rw-r--r--source/blender/editors/interface/interface_query.c34
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c2
-rw-r--r--source/blender/editors/mesh/meshtools.c2
-rw-r--r--source/blender/editors/render/render_shading.c14
-rw-r--r--source/blender/editors/scene/scene_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c28
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c8
-rw-r--r--source/blender/editors/space_console/console_draw.c37
-rw-r--r--source/blender/editors/space_info/info_draw.c65
-rw-r--r--source/blender/editors/space_info/info_intern.h14
-rw-r--r--source/blender/editors/space_info/info_report.c2
-rw-r--r--source/blender/editors/space_info/textview.h36
-rw-r--r--source/blender/editors/space_node/space_node.c1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c20
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c5
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c8
-rw-r--r--source/blender/gpu/GPU_draw.h12
-rw-r--r--source/blender/gpu/GPU_extensions.h1
-rw-r--r--source/blender/gpu/GPU_material.h28
-rw-r--r--source/blender/gpu/GPU_state.h12
-rw-r--r--source/blender/gpu/GPU_texture.h11
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c24
-rw-r--r--source/blender/gpu/intern/gpu_draw.c185
-rw-r--r--source/blender/gpu/intern/gpu_draw_smoke.c112
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c12
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c8
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c4
-rw-r--r--source/blender/gpu/intern/gpu_material.c34
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c69
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h8
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c7
-rw-r--r--source/blender/gpu/intern/gpu_shader.c6
-rw-r--r--source/blender/gpu/intern/gpu_state.c185
-rw-r--r--source/blender/gpu/intern/gpu_texture.c228
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl77
-rw-r--r--source/blender/io/usd/intern/abstract_hierarchy_iterator.cc4
-rw-r--r--source/blender/io/usd/intern/abstract_hierarchy_iterator.h6
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc2
-rw-r--r--source/blender/makesdna/DNA_ID.h18
-rw-r--r--source/blender/makesdna/DNA_action_types.h4
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h3
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h12
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h20
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h4
-rw-r--r--source/blender/makesdna/DNA_view3d_enums.h4
-rw-r--r--source/blender/makesrna/intern/makesrna.c4
-rw-r--r--source/blender/makesrna/intern/rna_access.c2
-rw-r--r--source/blender/makesrna/intern/rna_action.c9
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c47
-rw-r--r--source/blender/makesrna/intern/rna_particle.c10
-rw-r--r--source/blender/makesrna/intern/rna_scene.c10
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c12
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c6
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c2
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c2
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c4
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_info.c25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.c47
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c310
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c2
-rwxr-xr-xtests/python/eevee_render_tests.py10
277 files changed, 8505 insertions, 8220 deletions
diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet2/CMakeLists.txt
index f1bb6a37cbf..b386aa4035b 100644
--- a/extern/bullet2/CMakeLists.txt
+++ b/extern/bullet2/CMakeLists.txt
@@ -415,4 +415,11 @@ if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
endif()
+if(MSVC)
+ # bullet is responsible for quite a few silly warnings
+ # suppress all of them. Not great, but they really needed
+ # to sort that out themselves.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W0")
+endif()
+
blender_add_lib(extern_bullet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/extern/glog/CMakeLists.txt b/extern/glog/CMakeLists.txt
index c60e30d0b48..bfe715d3463 100644
--- a/extern/glog/CMakeLists.txt
+++ b/extern/glog/CMakeLists.txt
@@ -77,6 +77,11 @@ if(WIN32)
list(APPEND INC
src/windows
)
+ if(MSVC)
+ # Suppress warning about google::LogMessageFatal::~LogMessageFatal
+ # not returning.
+ add_definitions("/wd4722")
+ endif()
else()
list(APPEND INC
include
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 1014831c403..6d4d2e38e82 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -177,14 +177,11 @@ if(CXX_HAS_AVX2)
add_definitions(-DWITH_KERNEL_AVX2)
endif()
-if(WITH_CYCLES_OSL)
- # LLVM and OSL need to build without RTTI
- if(WIN32 AND MSVC)
- set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
- elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
- set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
- endif()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}")
+# LLVM and OSL need to build without RTTI
+if(WIN32 AND MSVC)
+ set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
+elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
+ set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
endif()
# Definitions and Includes
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 2540786a014..11db5b1a07d 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -292,7 +292,7 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node
filepath = path_join(state.base, filepath);
}
- snode = ((OSLShaderManager *)manager)->osl_node(filepath);
+ snode = OSLShaderManager::osl_node(manager, filepath);
if (!snode) {
fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index d9a2ebf8571..ae191b6c0f7 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SRC
CCL_api.h
blender_device.h
blender_id_map.h
+ blender_image.h
blender_object_cull.h
blender_sync.h
blender_session.h
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 1a93a603e23..cd72da128aa 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -361,6 +361,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Noise level step to stop sampling at, lower values reduce noise the cost of render time. Zero for automatic setting based on number of AA samples",
min=0.0, max=1.0,
default=0.0,
+ precision=4,
)
adaptive_min_samples: IntProperty(
name="Adaptive Min Samples",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index d24d965bb06..3e0d40bc5fd 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -770,6 +770,8 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_solid", text="Surfaces")
col = flow.column()
col.prop(view_layer, "use_strand", text="Hair")
+ col = flow.column()
+ col.prop(view_layer, "use_volumes", text="Volumes")
if with_freestyle:
col = flow.column()
col.prop(view_layer, "use_freestyle", text="Freestyle")
diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp
index d0f8465a98f..5140f190f36 100644
--- a/intern/cycles/blender/blender_device.cpp
+++ b/intern/cycles/blender/blender_device.cpp
@@ -17,6 +17,8 @@
#include "blender/blender_device.h"
#include "blender/blender_util.h"
+#include "util/util_foreach.h"
+
CCL_NAMESPACE_BEGIN
enum DenoiserType {
diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp
index 304b3d18e27..e2a4a125ca1 100644
--- a/intern/cycles/blender/blender_geometry.cpp
+++ b/intern/cycles/blender/blender_geometry.cpp
@@ -23,6 +23,8 @@
#include "blender/blender_sync.h"
#include "blender/blender_util.h"
+#include "util/util_foreach.h"
+
CCL_NAMESPACE_BEGIN
Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp
index 55ce6a295d1..459dc1779fb 100644
--- a/intern/cycles/blender/blender_image.cpp
+++ b/intern/cycles/blender/blender_image.cpp
@@ -14,206 +14,71 @@
* limitations under the License.
*/
-#include "render/image.h"
+#include "MEM_guardedalloc.h"
-#include "blender/blender_sync.h"
+#include "blender/blender_image.h"
#include "blender/blender_session.h"
#include "blender/blender_util.h"
CCL_NAMESPACE_BEGIN
-/* builtin image file name is actually an image datablock name with
- * absolute sequence frame number concatenated via '@' character
- *
- * this function splits frame from builtin name
- */
-int BlenderSession::builtin_image_frame(const string &builtin_name)
+/* Packed Images */
+
+BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame)
+ : b_image(b_image), frame(frame), free_cache(!b_image.has_data())
{
- int last = builtin_name.find_last_of('@');
- return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
}
-void BlenderSession::builtin_image_info(const string &builtin_name,
- void *builtin_data,
- ImageMetaData &metadata)
+bool BlenderImageLoader::load_metadata(ImageMetaData &metadata)
{
- /* empty image */
- metadata.width = 1;
- metadata.height = 1;
-
- if (!builtin_data)
- return;
-
- /* recover ID pointer */
- PointerRNA ptr;
- RNA_id_pointer_create((ID *)builtin_data, &ptr);
- BL::ID b_id(ptr);
-
- if (b_id.is_a(&RNA_Image)) {
- /* image data */
- BL::Image b_image(b_id);
+ metadata.width = b_image.size()[0];
+ metadata.height = b_image.size()[1];
+ metadata.depth = 1;
+ metadata.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();
-
- if (metadata.is_float) {
- /* Float images are already converted on the Blender side,
- * no need to do anything in Cycles. */
- metadata.colorspace = u_colorspace_raw;
+ if (b_image.is_float()) {
+ if (metadata.channels == 1) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
- }
- else if (b_id.is_a(&RNA_Object)) {
- /* smoke volume data */
- BL::Object b_ob(b_id);
- BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
-
- 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) ||
- builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE))
- metadata.channels = 1;
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
- metadata.channels = 4;
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY))
- metadata.channels = 3;
- else
- return;
-
- int3 resolution = get_int3(b_domain.domain_resolution());
- int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
-
- /* Velocity and heat data is always low-resolution. */
- if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
- builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
- amplify = 1;
+ else if (metadata.channels == 4) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
}
-
- 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. */
- PointerRNA ptr;
- RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
- BL::Node b_node(ptr);
- if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
- BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
- metadata.channels = 4;
- metadata.width = b_point_density_node.resolution();
- metadata.height = metadata.width;
- metadata.depth = metadata.width;
- metadata.is_float = true;
+ else {
+ return false;
}
- }
-}
-bool BlenderSession::builtin_image_pixels(const string &builtin_name,
- void *builtin_data,
- int tile,
- unsigned char *pixels,
- const size_t pixels_size,
- const bool associate_alpha,
- const bool free_cache)
-{
- if (!builtin_data) {
- return false;
- }
-
- const int frame = builtin_image_frame(builtin_name);
-
- PointerRNA ptr;
- RNA_id_pointer_create((ID *)builtin_data, &ptr);
- BL::Image b_image(ptr);
-
- const int width = b_image.size()[0];
- const int height = b_image.size()[1];
- const int channels = b_image.channels();
-
- unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
- const size_t num_pixels = ((size_t)width) * height;
-
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
+ /* Float images are already converted on the Blender side,
+ * no need to do anything in Cycles. */
+ metadata.colorspace = u_colorspace_raw;
}
else {
- if (channels == 1) {
- memset(pixels, 0, pixels_size * sizeof(unsigned char));
+ if (metadata.channels == 1) {
+ metadata.type = IMAGE_DATA_TYPE_BYTE;
+ }
+ else if (metadata.channels == 4) {
+ metadata.type = IMAGE_DATA_TYPE_BYTE4;
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- unsigned char *cp = pixels;
- for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
- cp[0] = 255;
- cp[1] = 0;
- cp[2] = 255;
- if (channels == 4) {
- cp[3] = 255;
- }
- }
+ return false;
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
- }
-
- /* Free image buffers to save memory during render. */
- if (free_cache) {
- b_image.buffers_free();
- }
-
- if (associate_alpha) {
- /* Premultiply, byte images are always straight for Blender. */
- unsigned char *cp = pixels;
- for (size_t i = 0; i < num_pixels; i++, cp += channels) {
- cp[0] = (cp[0] * cp[3]) >> 8;
- cp[1] = (cp[1] * cp[3]) >> 8;
- cp[2] = (cp[2] * cp[3]) >> 8;
- }
- }
return true;
}
-bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
- void *builtin_data,
- int tile,
- float *pixels,
- const size_t pixels_size,
- const bool,
- const bool free_cache)
+bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha)
{
- if (!builtin_data) {
- return false;
- }
+ const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
+ const int channels = metadata.channels;
+ const int tile = 0; /* TODO(lukas): Support tiles here? */
- PointerRNA ptr;
- RNA_id_pointer_create((ID *)builtin_data, &ptr);
- BL::ID b_id(ptr);
-
- if (b_id.is_a(&RNA_Image)) {
+ if (b_image.is_float()) {
/* image data */
- BL::Image b_image(b_id);
- int frame = builtin_image_frame(builtin_name);
-
- const int width = b_image.size()[0];
- const int height = b_image.size()[1];
- const int channels = b_image.channels();
-
float *image_pixels;
image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
- const size_t num_pixels = ((size_t)width) * height;
if (image_pixels && num_pixels * channels == pixels_size) {
memcpy(pixels, image_pixels, pixels_size * sizeof(float));
@@ -224,7 +89,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
}
else {
const size_t num_pixels_safe = pixels_size / channels;
- float *fp = pixels;
+ float *fp = (float *)pixels;
for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
fp[0] = 1.0f;
fp[1] = 0.0f;
@@ -239,107 +104,91 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
if (image_pixels) {
MEM_freeN(image_pixels);
}
-
- /* Free image buffers to save memory during render. */
- if (free_cache) {
- b_image.buffers_free();
- }
-
- return true;
}
- else if (b_id.is_a(&RNA_Object)) {
- /* smoke volume data */
- BL::Object b_ob(b_id);
- BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
-
- if (!b_domain) {
- return false;
- }
-#ifdef WITH_FLUID
- int3 resolution = get_int3(b_domain.domain_resolution());
- int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
-
- /* Velocity and heat data is always low-resolution. */
- if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
- builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
- amplify = 1;
- }
-
- const int width = resolution.x * amplify;
- const int height = resolution.y * amplify;
- const int depth = resolution.z * amplify;
- const size_t num_pixels = ((size_t)width) * height * depth;
+ else {
+ unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
- if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
- FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels);
- return true;
- }
- }
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
- /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
- * as 1500..3000 K with the first part faded to zero density */
- FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
- return true;
- }
+ if (image_pixels && num_pixels * channels == pixels_size) {
+ memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
}
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
- /* the RGB is "premultiplied" by density for better interpolation results */
- FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels * 4) {
- FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels);
- return true;
+ else {
+ if (channels == 1) {
+ memset(pixels, 0, pixels_size * sizeof(unsigned char));
}
- }
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
- FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels * 3) {
- FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
- return true;
+ else {
+ const size_t num_pixels_safe = pixels_size / channels;
+ unsigned char *cp = (unsigned char *)pixels;
+ for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
+ cp[0] = 255;
+ cp[1] = 0;
+ cp[2] = 255;
+ if (channels == 4) {
+ cp[3] = 255;
+ }
+ }
}
}
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
- FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
- return true;
- }
+
+ if (image_pixels) {
+ MEM_freeN(image_pixels);
}
- else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
- FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
- if (length == num_pixels) {
- FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
- return true;
+
+ if (associate_alpha) {
+ /* Premultiply, byte images are always straight for Blender. */
+ unsigned char *cp = (unsigned char *)pixels;
+ for (size_t i = 0; i < num_pixels; i++, cp += channels) {
+ cp[0] = (cp[0] * cp[3]) >> 8;
+ cp[1] = (cp[1] * cp[3]) >> 8;
+ cp[2] = (cp[2] * cp[3]) >> 8;
}
}
- else {
- fprintf(
- stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str());
- pixels[0] = 0.0f;
- return false;
- }
-#endif
- fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
}
- else {
- /* We originally were passing view_layer here but in reality we need a
- * a depsgraph 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);
- BL::Node b_node(ptr);
- if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
- BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
- int length;
- b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels);
- }
+
+ /* Free image buffers to save memory during render. */
+ if (free_cache) {
+ b_image.buffers_free();
}
- return false;
+ return true;
+}
+
+string BlenderImageLoader::name() const
+{
+ return BL::Image(b_image).name();
+}
+
+bool BlenderImageLoader::equals(const ImageLoader &other) const
+{
+ const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other;
+ return b_image == other_loader.b_image && frame == other_loader.frame;
+}
+
+/* Point Density */
+
+BlenderPointDensityLoader::BlenderPointDensityLoader(BL::Depsgraph b_depsgraph,
+ BL::ShaderNodeTexPointDensity b_node)
+ : b_depsgraph(b_depsgraph), b_node(b_node)
+{
+}
+
+bool BlenderPointDensityLoader::load_metadata(ImageMetaData &metadata)
+{
+ metadata.channels = 4;
+ metadata.width = b_node.resolution();
+ metadata.height = metadata.width;
+ metadata.depth = metadata.width;
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ return true;
+}
+
+bool BlenderPointDensityLoader::load_pixels(const ImageMetaData &,
+ void *pixels,
+ const size_t,
+ const bool)
+{
+ int length;
+ b_node.calc_point_density(b_depsgraph, &length, (float **)&pixels);
+ return true;
}
void BlenderSession::builtin_images_load()
@@ -357,4 +206,15 @@ void BlenderSession::builtin_images_load()
manager->device_load_builtin(device, session->scene, session->progress);
}
+string BlenderPointDensityLoader::name() const
+{
+ return BL::ShaderNodeTexPointDensity(b_node).name();
+}
+
+bool BlenderPointDensityLoader::equals(const ImageLoader &other) const
+{
+ const BlenderPointDensityLoader &other_loader = (const BlenderPointDensityLoader &)other;
+ return b_node == other_loader.b_node && b_depsgraph == other_loader.b_depsgraph;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_image.h b/intern/cycles/blender/blender_image.h
new file mode 100644
index 00000000000..b58a159a6ba
--- /dev/null
+++ b/intern/cycles/blender/blender_image.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2020 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 __BLENDER_IMAGE_H__
+#define __BLENDER_IMAGE_H__
+
+#include "RNA_blender_cpp.h"
+
+#include "render/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BlenderImageLoader : public ImageLoader {
+ public:
+ BlenderImageLoader(BL::Image b_image, int frame);
+
+ bool load_metadata(ImageMetaData &metadata) override;
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+ string name() const override;
+ bool equals(const ImageLoader &other) const override;
+
+ BL::Image b_image;
+ int frame;
+ bool free_cache;
+};
+
+class BlenderPointDensityLoader : public ImageLoader {
+ public:
+ BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node);
+
+ bool load_metadata(ImageMetaData &metadata) override;
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+ string name() const override;
+ bool equals(const ImageLoader &other) const override;
+
+ BL::Depsgraph b_depsgraph;
+ BL::ShaderNodeTexPointDensity b_node;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_IMAGE_H__ */
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index ac307743e48..8e01ad9a96d 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -138,14 +138,6 @@ void BlenderSession::create_session()
scene = new Scene(scene_params, session->device);
scene->name = b_scene.name();
- /* setup callbacks for builtin image support */
- 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, _6, _7);
- scene->image_manager->builtin_image_float_pixels_cb = function_bind(
- &BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5, _6, _7);
-
session->scene = scene;
/* There is no single depsgraph to use for the entire render.
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index a107d526dd6..3e6498bb655 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -157,22 +157,6 @@ class BlenderSession {
bool do_update_only);
void do_write_update_render_tile(RenderTile &rtile, bool do_update_only, bool highlight);
- int builtin_image_frame(const string &builtin_name);
- void builtin_image_info(const string &builtin_name, void *builtin_data, ImageMetaData &metadata);
- bool builtin_image_pixels(const string &builtin_name,
- void *builtin_data,
- int tile,
- unsigned char *pixels,
- const size_t pixels_size,
- const bool associate_alpha,
- const bool free_cache);
- bool builtin_image_float_pixels(const string &builtin_name,
- void *builtin_data,
- int tile,
- float *pixels,
- const size_t pixels_size,
- const bool associate_alpha,
- const bool free_cache);
void builtin_images_load();
/* Update tile manager to reflect resumable render settings. */
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 732c4b0da96..dc226805664 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -23,6 +23,7 @@
#include "render/scene.h"
#include "render/shader.h"
+#include "blender/blender_image.h"
#include "blender/blender_texture.h"
#include "blender/blender_sync.h"
#include "blender/blender_util.h"
@@ -619,16 +620,16 @@ static ShaderNode *add_node(Scene *scene,
/* create script node */
BL::ShaderNodeScript b_script_node(b_node);
- OSLShaderManager *manager = (OSLShaderManager *)scene->shader_manager;
+ ShaderManager *manager = scene->shader_manager;
string bytecode_hash = b_script_node.bytecode_hash();
if (!bytecode_hash.empty()) {
- node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
+ node = OSLShaderManager::osl_node(manager, "", bytecode_hash, b_script_node.bytecode());
}
else {
string absolute_filepath = blender_absolute_path(
b_data, b_ntree, b_script_node.filepath());
- node = manager->osl_node(absolute_filepath, "");
+ node = OSLShaderManager::osl_node(manager, absolute_filepath, "");
}
}
#else
@@ -650,6 +651,18 @@ static ShaderNode *add_node(Scene *scene,
get_tex_mapping(&image->tex_mapping, b_texture_mapping);
if (b_image) {
+ PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
+ image->colorspace = get_enum_identifier(colorspace_ptr, "name");
+
+ image->animated = b_image_node.image_user().use_auto_refresh();
+ image->alpha_type = get_image_alpha_type(b_image);
+
+ image->tiles.clear();
+ BL::Image::tiles_iterator b_iter;
+ for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
+ image->tiles.push_back(b_iter->number());
+ }
+
/* builtin images will use callback-based reading because
* they could only be loaded correct from blender side
*/
@@ -666,34 +679,13 @@ static ShaderNode *add_node(Scene *scene,
*/
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, scene_frame);
- image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
- image->builtin_data = b_image.ptr.data;
+ image->handle = scene->image_manager->add_image(
+ new BlenderImageLoader(b_image, image_frame), image->image_params());
}
else {
image->filename = image_user_file_path(
b_image_user, b_image, b_scene.frame_current(), true);
- image->builtin_data = NULL;
- }
-
- PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
- image->colorspace = get_enum_identifier(colorspace_ptr, "name");
-
- image->animated = b_image_node.image_user().use_auto_refresh();
- image->alpha_type = get_image_alpha_type(b_image);
-
- image->tiles.clear();
- BL::Image::tiles_iterator b_iter;
- for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
- image->tiles.push_back(b_iter->number());
- }
-
- /* TODO: restore */
- /* TODO(sergey): Does not work properly when we change builtin type. */
-#if 0
- if (b_image.is_updated()) {
- scene->image_manager->tag_reload_image(image->image_key());
}
-#endif
}
node = image;
}
@@ -709,6 +701,12 @@ static ShaderNode *add_node(Scene *scene,
get_tex_mapping(&env->tex_mapping, b_texture_mapping);
if (b_image) {
+ PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
+ env->colorspace = get_enum_identifier(colorspace_ptr, "name");
+
+ env->animated = b_env_node.image_user().use_auto_refresh();
+ env->alpha_type = get_image_alpha_type(b_image);
+
bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
b_image.source() == BL::Image::source_MOVIE ||
(b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE);
@@ -716,28 +714,13 @@ static ShaderNode *add_node(Scene *scene,
if (is_builtin) {
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, scene_frame);
- env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
- env->builtin_data = b_image.ptr.data;
+ env->handle = scene->image_manager->add_image(new BlenderImageLoader(b_image, image_frame),
+ env->image_params());
}
else {
env->filename = image_user_file_path(
b_image_user, b_image, b_scene.frame_current(), false);
- env->builtin_data = NULL;
}
-
- PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
- env->colorspace = get_enum_identifier(colorspace_ptr, "name");
-
- env->animated = b_env_node.image_user().use_auto_refresh();
- env->alpha_type = get_image_alpha_type(b_image);
-
- /* TODO: restore */
- /* TODO(sergey): Does not work properly when we change builtin type. */
-#if 0
- if (b_image.is_updated()) {
- scene->image_manager->tag_reload_image(env->image_key());
- }
-#endif
}
node = env;
}
@@ -881,18 +864,13 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
PointDensityTextureNode *point_density = new PointDensityTextureNode();
- point_density->filename = b_point_density_node.name();
point_density->space = (NodeTexVoxelSpace)b_point_density_node.space();
point_density->interpolation = get_image_interpolation(b_point_density_node);
- point_density->builtin_data = b_point_density_node.ptr.data;
- point_density->image_manager = scene->image_manager;
-
- /* TODO(sergey): Use more proper update flag. */
- if (true) {
- point_density->add_image();
- b_point_density_node.cache_point_density(b_depsgraph);
- scene->image_manager->tag_reload_image(point_density->image_key());
- }
+ point_density->handle = scene->image_manager->add_image(
+ new BlenderPointDensityLoader(b_depsgraph, b_point_density_node),
+ point_density->image_params());
+
+ b_point_density_node.cache_point_density(b_depsgraph);
node = point_density;
/* Transformation form world space to texture space.
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 8f00f9ccda0..4529c6a2798 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -405,6 +405,7 @@ void BlenderSync::sync_view_layer(BL::SpaceView3D & /*b_v3d*/, BL::ViewLayer &b_
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.use_volumes = b_view_layer.use_volumes();
/* Material override. */
view_layer.material_override = b_view_layer.material_override();
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 0a7174e407b..d212caa69f7 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -236,6 +236,7 @@ class BlenderSync {
use_background_ao(true),
use_surfaces(true),
use_hair(true),
+ use_volumes(true),
samples(0),
bound_samples(false)
{
@@ -247,6 +248,7 @@ class BlenderSync {
bool use_background_ao;
bool use_surfaces;
bool use_hair;
+ bool use_volumes;
int samples;
bool bound_samples;
} view_layer;
diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp
index 47259d4945c..237c5d061e8 100644
--- a/intern/cycles/blender/blender_volume.cpp
+++ b/intern/cycles/blender/blender_volume.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2011-2013 Blender Foundation
*
@@ -24,6 +23,152 @@
CCL_NAMESPACE_BEGIN
+/* TODO: verify this is not loading unnecessary attributes. */
+class BlenderSmokeLoader : public ImageLoader {
+ public:
+ BlenderSmokeLoader(const BL::Object &b_ob, AttributeStandard attribute)
+ : b_ob(b_ob), attribute(attribute)
+ {
+ }
+
+ bool load_metadata(ImageMetaData &metadata) override
+ {
+ BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
+
+ if (!b_domain) {
+ return false;
+ }
+
+ if (attribute == ATTR_STD_VOLUME_DENSITY || attribute == ATTR_STD_VOLUME_FLAME ||
+ attribute == ATTR_STD_VOLUME_HEAT || attribute == ATTR_STD_VOLUME_TEMPERATURE) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT;
+ metadata.channels = 1;
+ }
+ else if (attribute == ATTR_STD_VOLUME_COLOR) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ metadata.channels = 4;
+ }
+ else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ metadata.channels = 3;
+ }
+ else {
+ return false;
+ }
+
+ int3 resolution = get_int3(b_domain.domain_resolution());
+ int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
+
+ /* Velocity and heat data is always low-resolution. */
+ if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) {
+ amplify = 1;
+ }
+
+ metadata.width = resolution.x * amplify;
+ metadata.height = resolution.y * amplify;
+ metadata.depth = resolution.z * amplify;
+
+ return true;
+ }
+
+ bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override
+ {
+ /* smoke volume data */
+ BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
+
+ if (!b_domain) {
+ return false;
+ }
+#ifdef WITH_FLUID
+ int3 resolution = get_int3(b_domain.domain_resolution());
+ int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
+
+ /* Velocity and heat data is always low-resolution. */
+ if (attribute == ATTR_STD_VOLUME_VELOCITY || attribute == ATTR_STD_VOLUME_HEAT) {
+ amplify = 1;
+ }
+
+ const int width = resolution.x * amplify;
+ const int height = resolution.y * amplify;
+ const int depth = resolution.z * amplify;
+ const size_t num_pixels = ((size_t)width) * height * depth;
+
+ float *fpixels = (float *)pixels;
+
+ if (attribute == ATTR_STD_VOLUME_DENSITY) {
+ FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_density_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_FLAME) {
+ /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
+ * as 1500..3000 K with the first part faded to zero density */
+ FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_flame_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_COLOR) {
+ /* the RGB is "premultiplied" by density for better interpolation results */
+ FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels * 4) {
+ FluidDomainSettings_color_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
+ FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels * 3) {
+ FluidDomainSettings_velocity_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_HEAT) {
+ FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_heat_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else if (attribute == ATTR_STD_VOLUME_TEMPERATURE) {
+ FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
+ if (length == num_pixels) {
+ FluidDomainSettings_temperature_grid_get(&b_domain.ptr, fpixels);
+ return true;
+ }
+ }
+ else {
+ fprintf(stderr,
+ "Cycles error: unknown volume attribute %s, skipping\n",
+ Attribute::standard_name(attribute));
+ fpixels[0] = 0.0f;
+ return false;
+ }
+#else
+ (void)pixels;
+#endif
+ fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
+ return false;
+ }
+
+ string name() const override
+ {
+ return Attribute::standard_name(attribute);
+ }
+
+ bool equals(const ImageLoader &other) const override
+ {
+ const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other;
+ return b_ob == other_loader.b_ob && attribute == other_loader.attribute;
+ }
+
+ BL::Object b_ob;
+ AttributeStandard attribute;
+};
+
static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame)
{
BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
@@ -31,7 +176,6 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float
return;
}
- ImageManager *image_manager = scene->image_manager;
AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY,
ATTR_STD_VOLUME_COLOR,
ATTR_STD_VOLUME_FLAME,
@@ -49,15 +193,12 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float
mesh->volume_isovalue = b_domain.clipping();
Attribute *attr = mesh->attributes.add(std);
- VoxelAttribute *volume_data = attr->data_voxel();
- ImageMetaData metadata;
- ImageKey key;
- key.filename = Attribute::standard_name(std);
- key.builtin_data = b_ob.ptr.data;
+ ImageLoader *loader = new BlenderSmokeLoader(b_ob, std);
+ ImageParams params;
+ params.frame = frame;
- volume_data->manager = image_manager;
- volume_data->slot = image_manager->add_image(key, frame, metadata);
+ attr->data_voxel() = scene->image_manager->add_image(loader, params);
}
/* Create a matrix to transform from object space to mesh texture space.
@@ -75,18 +216,33 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float
}
}
+/* If the voxel attributes change, we need to rebuild the bounding mesh. */
+static vector<int> get_voxel_image_slots(Mesh *mesh)
+{
+ vector<int> slots;
+ for (const Attribute &attr : mesh->attributes.attributes) {
+ if (attr.element == ATTR_ELEMENT_VOXEL) {
+ slots.push_back(attr.data_voxel().svm_slot());
+ }
+ }
+
+ return slots;
+}
+
void BlenderSync::sync_volume(BL::Object &b_ob, Mesh *mesh, const vector<Shader *> &used_shaders)
{
- bool old_has_voxel_attributes = mesh->has_voxel_attributes();
+ vector<int> old_voxel_slots = get_voxel_image_slots(mesh);
mesh->clear();
mesh->used_shaders = used_shaders;
/* Smoke domain. */
- sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current());
+ if (view_layer.use_volumes) {
+ sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current());
+ }
/* Tag update. */
- bool rebuild = (old_has_voxel_attributes != mesh->has_voxel_attributes());
+ bool rebuild = (old_voxel_slots != get_voxel_image_slots(mesh));
mesh->tag_update(scene, rebuild);
}
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 3a8b0fe7fa2..e6502a40313 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -535,8 +535,9 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* Modify offsets into arrays */
int4 data = bvh_nodes[i + nsize_bbox];
- int4 data1 = bvh_nodes[i + nsize_bbox - 1];
+
if (use_obvh) {
+ int4 data1 = bvh_nodes[i + nsize_bbox - 1];
data.z += (data.z < 0) ? -noffset_leaf : noffset;
data.w += (data.w < 0) ? -noffset_leaf : noffset;
data.x += (data.x < 0) ? -noffset_leaf : noffset;
@@ -545,6 +546,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
data1.w += (data1.w < 0) ? -noffset_leaf : noffset;
data1.x += (data1.x < 0) ? -noffset_leaf : noffset;
data1.y += (data1.y < 0) ? -noffset_leaf : noffset;
+ pack_nodes[pack_nodes_offset + nsize_bbox] = data;
+ pack_nodes[pack_nodes_offset + nsize_bbox - 1] = data1;
}
else {
data.z += (data.z < 0) ? -noffset_leaf : noffset;
@@ -553,10 +556,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
data.x += (data.x < 0) ? -noffset_leaf : noffset;
data.y += (data.y < 0) ? -noffset_leaf : noffset;
}
- }
- pack_nodes[pack_nodes_offset + nsize_bbox] = data;
- if (use_obvh) {
- pack_nodes[pack_nodes_offset + nsize_bbox - 1] = data1;
+ pack_nodes[pack_nodes_offset + nsize_bbox] = data;
}
/* Usually this copies nothing, but we better
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
index a3b6261dcad..da548e9c0db 100644
--- a/intern/cycles/bvh/bvh_optix.cpp
+++ b/intern/cycles/bvh/bvh_optix.cpp
@@ -22,6 +22,7 @@
# include "render/geometry.h"
# include "render/mesh.h"
# include "render/object.h"
+# include "util/util_foreach.h"
# include "util/util_logging.h"
# include "util/util_progress.h"
diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp
index 4e8d8b7ca7c..4df1ca2097a 100644
--- a/intern/cycles/device/cuda/device_cuda_impl.cpp
+++ b/intern/cycles/device/cuda/device_cuda_impl.cpp
@@ -1169,10 +1169,10 @@ void CUDADevice::tex_alloc(device_memory &mem)
}
/* Kepler+, bindless textures. */
- int flat_slot = 0;
+ int slot = 0;
if (string_startswith(mem.name, "__tex_image")) {
int pos = string(mem.name).rfind("_");
- flat_slot = atoi(mem.name + pos + 1);
+ slot = atoi(mem.name + pos + 1);
}
else {
assert(0);
@@ -1214,15 +1214,16 @@ void CUDADevice::tex_alloc(device_memory &mem)
cuda_assert(cuTexObjectCreate(&cmem->texobject, &resDesc, &texDesc, NULL));
/* Resize once */
- if (flat_slot >= texture_info.size()) {
+ if (slot >= texture_info.size()) {
/* Allocate some slots in advance, to reduce amount
* of re-allocations. */
- texture_info.resize(flat_slot + 128);
+ texture_info.resize(slot + 128);
}
/* Set Mapping and tag that we need to (re-)upload to device */
- TextureInfo &info = texture_info[flat_slot];
+ TextureInfo &info = texture_info[slot];
info.data = (uint64_t)cmem->texobject;
+ info.data_type = mem.image_data_type;
info.cl_buffer = 0;
info.interpolation = mem.interpolation;
info.extension = mem.extension;
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index d11918ccbbf..56569a5ee3d 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -465,23 +465,24 @@ class CPUDevice : public Device {
}
else {
/* Image Texture. */
- int flat_slot = 0;
+ int slot = 0;
if (string_startswith(mem.name, "__tex_image")) {
int pos = string(mem.name).rfind("_");
- flat_slot = atoi(mem.name + pos + 1);
+ slot = atoi(mem.name + pos + 1);
}
else {
assert(0);
}
- if (flat_slot >= texture_info.size()) {
+ if (slot >= texture_info.size()) {
/* Allocate some slots in advance, to reduce amount
* of re-allocations. */
- texture_info.resize(flat_slot + 128);
+ texture_info.resize(slot + 128);
}
- TextureInfo &info = texture_info[flat_slot];
+ TextureInfo &info = texture_info[slot];
info.data = (uint64_t)mem.host_pointer;
+ info.data_type = mem.image_data_type;
info.cl_buffer = 0;
info.interpolation = mem.interpolation;
info.extension = mem.extension;
diff --git a/intern/cycles/device/device_memory.cpp b/intern/cycles/device/device_memory.cpp
index 3a99a49dffc..f22b91f3fa1 100644
--- a/intern/cycles/device/device_memory.cpp
+++ b/intern/cycles/device/device_memory.cpp
@@ -31,6 +31,7 @@ device_memory::device_memory(Device *device, const char *name, MemoryType type)
data_depth(0),
type(type),
name(name),
+ image_data_type(IMAGE_DATA_NUM_TYPES),
interpolation(INTERPOLATION_NONE),
extension(EXTENSION_REPEAT),
device(device),
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 2949773ef0c..617cc0c4342 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -208,6 +208,7 @@ class device_memory {
size_t data_depth;
MemoryType type;
const char *name;
+ ImageDataType image_data_type;
InterpolationType interpolation;
ExtensionType extension;
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index 30d624fdf7c..329876ce6f6 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -477,9 +477,9 @@ class OptiXDevice : public CUDADevice {
// Calculate maximum trace continuation stack size
unsigned int trace_css = stack_size[PG_HITD].cssCH;
// This is based on the maximum of closest-hit and any-hit/intersection programs
- trace_css = max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH);
- trace_css = max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH);
- trace_css = max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH);
+ trace_css = std::max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH);
+ trace_css = std::max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH);
+ trace_css = std::max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH);
OptixPipelineLinkOptions link_options;
link_options.maxTraceDepth = 1;
@@ -548,8 +548,9 @@ class OptiXDevice : public CUDADevice {
&pipelines[PIP_SHADER_EVAL]));
// Calculate continuation stack size based on the maximum of all ray generation stack sizes
- const unsigned int css = max(stack_size[PG_BAKE].cssRG,
- max(stack_size[PG_DISP].cssRG, stack_size[PG_BACK].cssRG)) +
+ const unsigned int css = std::max(stack_size[PG_BAKE].cssRG,
+ std::max(stack_size[PG_DISP].cssRG,
+ stack_size[PG_BACK].cssRG)) +
link_options.maxTraceDepth * trace_css;
check_result_optix_ret(optixPipelineSetStackSize(
diff --git a/intern/cycles/device/opencl/device_opencl_impl.cpp b/intern/cycles/device/opencl/device_opencl_impl.cpp
index 3dbe54b38aa..09d3b78dd28 100644
--- a/intern/cycles/device/opencl/device_opencl_impl.cpp
+++ b/intern/cycles/device/opencl/device_opencl_impl.cpp
@@ -1298,6 +1298,8 @@ void OpenCLDevice::flush_texture_buffers()
if (string_startswith(slot.name, "__tex_image")) {
device_memory *mem = textures[slot.name];
+ info.data_type = mem->image_data_type;
+
info.width = mem->data_width;
info.height = mem->data_height;
info.depth = mem->data_depth;
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index ec41ef2f0e9..f4c3b36e778 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -302,7 +302,7 @@ ccl_device_inline bool sample_is_even(int pattern, int sample)
#elif defined(__KERNEL_OPENCL__)
return popcount(sample & 0xaaaaaaaa) & 1;
#else
-/* TODO(Stefan): popcnt intrinsic for Windows with fallback for older CPUs. */
+ /* TODO(Stefan): popcnt intrinsic for Windows with fallback for older CPUs. */
int i = sample & 0xaaaaaaaa;
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
index 8f311baf010..7eb66b0b4ca 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
@@ -474,7 +474,7 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
- switch (kernel_tex_type(id)) {
+ switch (info.data_type) {
case IMAGE_DATA_TYPE_HALF:
return TextureInterpolator<half>::interp(info, x, y);
case IMAGE_DATA_TYPE_BYTE:
@@ -503,7 +503,7 @@ ccl_device float4 kernel_tex_image_interp_3d(
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
- switch (kernel_tex_type(id)) {
+ switch (info.data_type) {
case IMAGE_DATA_TYPE_HALF:
return TextureInterpolator<half>::interp_3d(info, x, y, z, interp);
case IMAGE_DATA_TYPE_BYTE:
diff --git a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h
index 7c68f08ea10..24bc3c7b59e 100644
--- a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h
+++ b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h
@@ -124,7 +124,7 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
CUtexObject tex = (CUtexObject)info.data;
/* float4, byte4, ushort4 and half4 */
- const int texture_type = kernel_tex_type(id);
+ const int texture_type = info.data_type;
if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 ||
texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4) {
if (info.interpolation == INTERPOLATION_CUBIC) {
@@ -156,7 +156,7 @@ ccl_device float4 kernel_tex_image_interp_3d(
CUtexObject tex = (CUtexObject)info.data;
uint interpolation = (interp == INTERPOLATION_NONE) ? info.interpolation : interp;
- const int texture_type = kernel_tex_type(id);
+ const int texture_type = info.data_type;
if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 ||
texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4) {
if (interpolation == INTERPOLATION_CUBIC) {
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
index b6390679331..f7dea383b82 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
+++ b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
@@ -47,7 +47,7 @@ ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg,
int id,
int offset)
{
- const int texture_type = kernel_tex_type(id);
+ const int texture_type = info->data_type;
/* Float4 */
if (texture_type == IMAGE_DATA_TYPE_FLOAT4) {
diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt
index 5be5bd181ec..fc0c845fd4f 100644
--- a/intern/cycles/kernel/osl/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/CMakeLists.txt
@@ -33,6 +33,9 @@ set(LIB
${LLVM_LIBRARY}
)
+# OSL and LLVM are built without RTTI
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}")
+
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index 90f1a7845c7..63939a049a5 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -30,10 +30,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) {
r /= alpha;
- const int texture_type = kernel_tex_type(id);
- if (texture_type == IMAGE_DATA_TYPE_BYTE4 || texture_type == IMAGE_DATA_TYPE_BYTE) {
- r = min(r, make_float4(1.0f, 1.0f, 1.0f, 1.0f));
- }
r.w = alpha;
}
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 2a077f486fa..9922547a8d2 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -23,6 +23,7 @@ set(SRC
graph.cpp
hair.cpp
image.cpp
+ image_oiio.cpp
integrator.cpp
jitter.cpp
light.cpp
@@ -61,6 +62,7 @@ set(SRC_HEADERS
graph.h
hair.h
image.h
+ image_oiio.h
integrator.h
light.h
jitter.h
@@ -92,6 +94,8 @@ if(WITH_CYCLES_OSL)
list(APPEND LIB
cycles_kernel_osl
)
+
+ SET_PROPERTY(SOURCE osl.cpp PROPERTY COMPILE_FLAGS ${RTTI_DISABLE_FLAGS})
endif()
include_directories(${INC})
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index 1e293f1aa16..d0d9888ac88 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -26,46 +26,51 @@ CCL_NAMESPACE_BEGIN
/* Attribute */
-Attribute::~Attribute()
-{
- /* for voxel data, we need to remove the image from the image manager */
- if (element == ATTR_ELEMENT_VOXEL) {
- VoxelAttribute *voxel_data = data_voxel();
-
- if (voxel_data && voxel_data->slot != -1) {
- voxel_data->manager->remove_image(voxel_data->slot);
- }
- }
-}
-
-void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
+Attribute::Attribute(
+ ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
+ : name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0)
{
- name = name_;
- type = type_;
- element = element_;
- std = ATTR_STD_NONE;
- flags = 0;
-
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2 ||
type == TypeRGBA);
+
+ if (element == ATTR_ELEMENT_VOXEL) {
+ buffer.resize(sizeof(ImageHandle));
+ new (buffer.data()) ImageHandle();
+ }
+ else {
+ resize(geom, prim, false);
+ }
}
-void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
+Attribute::~Attribute()
{
- if (reserve_only) {
- buffer.reserve(buffer_size(geom, prim));
+ /* For voxel data, we need to free the image handle. */
+ if (element == ATTR_ELEMENT_VOXEL) {
+ ImageHandle &handle = data_voxel();
+ handle.~ImageHandle();
}
- else {
- buffer.resize(buffer_size(geom, prim), 0);
+}
+
+void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
+{
+ if (element != ATTR_ELEMENT_VOXEL) {
+ if (reserve_only) {
+ buffer.reserve(buffer_size(geom, prim));
+ }
+ else {
+ buffer.resize(buffer_size(geom, prim), 0);
+ }
}
}
void Attribute::resize(size_t num_elements)
{
- buffer.resize(num_elements * data_sizeof(), 0);
+ if (element != ATTR_ELEMENT_VOXEL) {
+ buffer.resize(num_elements * data_sizeof(), 0);
+ }
}
void Attribute::add(const float &f)
@@ -123,17 +128,6 @@ void Attribute::add(const Transform &f)
buffer.push_back(data[i]);
}
-void Attribute::add(const VoxelAttribute &f)
-{
- assert(data_sizeof() == sizeof(VoxelAttribute));
-
- char *data = (char *)&f;
- size_t size = sizeof(f);
-
- for (size_t i = 0; i < size; i++)
- buffer.push_back(data[i]);
-}
-
void Attribute::add(const char *data)
{
size_t size = data_sizeof();
@@ -145,7 +139,7 @@ void Attribute::add(const char *data)
size_t Attribute::data_sizeof() const
{
if (element == ATTR_ELEMENT_VOXEL)
- return sizeof(VoxelAttribute);
+ return sizeof(ImageHandle);
else if (element == ATTR_ELEMENT_CORNER_BYTE)
return sizeof(uchar4);
else if (type == TypeDesc::TypeFloat)
@@ -414,23 +408,9 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme
remove(name);
}
-#if __cplusplus >= 201103L
- attributes.emplace_back();
- attr = &attributes.back();
- attr->set(name, type, element);
-#else
- {
- Attribute attr_temp;
- attr_temp.set(name, type, element);
- attributes.push_back(attr_temp);
- attr = &attributes.back();
- }
-#endif
-
- /* this is weak .. */
- attr->resize(geometry, prim, false);
-
- return attr;
+ Attribute new_attr(name, type, element, geometry, prim);
+ attributes.emplace_back(std::move(new_attr));
+ return &attributes.back();
}
Attribute *AttributeSet::find(ustring name) const
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index f1fd30fd85a..351357a7f7a 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -17,6 +17,8 @@
#ifndef __ATTRIBUTE_H__
#define __ATTRIBUTE_H__
+#include "render/image.h"
+
#include "kernel/kernel_types.h"
#include "util/util_list.h"
@@ -31,19 +33,12 @@ class Attribute;
class AttributeRequest;
class AttributeRequestSet;
class AttributeSet;
-class ImageManager;
+class ImageHandle;
class Geometry;
class Hair;
class Mesh;
struct Transform;
-/* Attributes for voxels are images */
-
-struct VoxelAttribute {
- ImageManager *manager;
- int slot;
-};
-
/* Attribute
*
* Arbitrary data layers on meshes.
@@ -59,9 +54,11 @@ class Attribute {
AttributeElement element;
uint flags; /* enum AttributeFlag */
- Attribute()
- {
- }
+ Attribute(ustring name,
+ TypeDesc type,
+ AttributeElement element,
+ Geometry *geom,
+ AttributePrimitive prim);
~Attribute();
void set(ustring name, TypeDesc type, AttributeElement element);
void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only);
@@ -105,10 +102,12 @@ class Attribute {
assert(data_sizeof() == sizeof(Transform));
return (Transform *)data();
}
- VoxelAttribute *data_voxel()
+
+ /* Attributes for voxels are images */
+ ImageHandle &data_voxel()
{
- assert(data_sizeof() == sizeof(VoxelAttribute));
- return (VoxelAttribute *)data();
+ assert(data_sizeof() == sizeof(ImageHandle));
+ return *(ImageHandle *)data();
}
const char *data() const
@@ -140,10 +139,10 @@ class Attribute {
assert(data_sizeof() == sizeof(Transform));
return (const Transform *)data();
}
- const VoxelAttribute *data_voxel() const
+ const ImageHandle &data_voxel() const
{
- assert(data_sizeof() == sizeof(VoxelAttribute));
- return (const VoxelAttribute *)data();
+ assert(data_sizeof() == sizeof(ImageHandle));
+ return *(const ImageHandle *)data();
}
void zero_data(void *dst);
@@ -153,8 +152,7 @@ class Attribute {
void add(const float2 &f);
void add(const float3 &f);
void add(const uchar4 &f);
- void add(const Transform &f);
- void add(const VoxelAttribute &f);
+ void add(const Transform &tfm);
void add(const char *data);
static bool same_storage(TypeDesc a, TypeDesc b);
diff --git a/intern/cycles/render/colorspace.cpp b/intern/cycles/render/colorspace.cpp
index 2e5b53057c0..97a9ba3f012 100644
--- a/intern/cycles/render/colorspace.cpp
+++ b/intern/cycles/render/colorspace.cpp
@@ -283,7 +283,7 @@ inline void processor_apply_pixels(const OCIO::Processor *processor,
for (size_t x = 0; x < width; x++, i++) {
float4 value = cast_to_float4(pixels + 4 * (y * width + x));
- if (!(value.w == 0.0f || value.w == 1.0f)) {
+ if (!(value.w <= 0.0f || value.w == 1.0f)) {
float inv_alpha = 1.0f / value.w;
value.x *= inv_alpha;
value.y *= inv_alpha;
@@ -302,14 +302,16 @@ inline void processor_apply_pixels(const OCIO::Processor *processor,
for (size_t x = 0; x < width; x++, i++) {
float4 value = float_pixels[i];
- value.x *= value.w;
- value.y *= value.w;
- value.z *= value.w;
-
if (compress_as_srgb) {
value = color_linear_to_srgb_v4(value);
}
+ if (!(value.w <= 0.0f || value.w == 1.0f)) {
+ value.x *= value.w;
+ value.y *= value.w;
+ value.z *= value.w;
+ }
+
cast_from_float4(pixels + 4 * (y * width + x), value);
}
}
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 880fb7b4c7d..748a8f7cf67 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -534,8 +534,8 @@ static void update_attribute_element_offset(Geometry *geom,
if (mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
- VoxelAttribute *voxel_data = mattr->data_voxel();
- offset = voxel_data->slot;
+ ImageHandle &handle = mattr->data_voxel();
+ offset = handle.svm_slot();
}
else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
uchar4 *data = mattr->data_uchar4();
@@ -1143,7 +1143,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
}
Mesh *mesh = static_cast<Mesh *>(geom);
- create_volume_mesh(scene, mesh, progress);
+ create_volume_mesh(mesh, progress);
}
}
}
@@ -1171,7 +1171,8 @@ void GeometryManager::device_update_displacement_images(Device *device,
}
ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node);
- foreach (int slot, image_node->slots) {
+ for (int i = 0; i < image_node->handle.num_tiles(); i++) {
+ const int slot = image_node->handle.svm_slot(i);
if (slot != -1) {
bump_images.insert(slot);
}
@@ -1204,10 +1205,10 @@ void GeometryManager::device_update_volume_images(Device *device, Scene *scene,
continue;
}
- VoxelAttribute *voxel = attr.data_voxel();
-
- if (voxel->slot != -1) {
- volume_images.insert(voxel->slot);
+ ImageHandle &handle = attr.data_voxel();
+ const int slot = handle.svm_slot();
+ if (slot != -1) {
+ volume_images.insert(slot);
}
}
}
diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h
index 66ae8472102..82f539d391d 100644
--- a/intern/cycles/render/geometry.h
+++ b/intern/cycles/render/geometry.h
@@ -166,7 +166,7 @@ class GeometryManager {
protected:
bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress);
- void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress);
+ void create_volume_mesh(Mesh *mesh, Progress &progress);
/* Attributes */
void update_osl_attributes(Device *device,
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index e5fb2fcaf3d..b4539b5ce3c 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -15,12 +15,14 @@
*/
#include "render/image.h"
+#include "render/image_oiio.h"
#include "device/device.h"
#include "render/colorspace.h"
#include "render/scene.h"
#include "render/stats.h"
#include "util/util_foreach.h"
+#include "util/util_image.h"
#include "util/util_image_impl.h"
#include "util/util_logging.h"
#include "util/util_path.h"
@@ -50,21 +52,6 @@ bool isfinite(uint16_t /*value*/)
return true;
}
-/* The lower three bits of a device texture slot number indicate its type.
- * These functions convert the slot ids from ImageManager "images" ones
- * to device ones and vice verse.
- */
-int type_index_to_flattened_slot(int slot, ImageDataType type)
-{
- return (slot << IMAGE_DATA_TYPE_SHIFT) | (type);
-}
-
-int flattened_slot_to_type_index(int flat_slot, ImageDataType *type)
-{
- *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK);
- return flat_slot >> IMAGE_DATA_TYPE_SHIFT;
-}
-
const char *name_from_type(ImageDataType type)
{
switch (type) {
@@ -94,302 +81,342 @@ const char *name_from_type(ImageDataType type)
} // namespace
-ImageManager::ImageManager(const DeviceInfo &info)
+/* Image Handle */
+
+ImageHandle::ImageHandle() : manager(NULL)
{
- need_update = true;
- osl_texture_system = NULL;
- animation_frame = 0;
+}
- /* Set image limits */
- max_num_images = TEX_NUM_MAX;
- has_half_images = info.has_half_images;
+ImageHandle::ImageHandle(const ImageHandle &other)
+ : tile_slots(other.tile_slots), manager(other.manager)
+{
+ /* Increase image user count. */
+ foreach (const int slot, tile_slots) {
+ manager->add_image_user(slot);
+ }
+}
- for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- tex_num_images[type] = 0;
+ImageHandle &ImageHandle::operator=(const ImageHandle &other)
+{
+ clear();
+ manager = other.manager;
+ tile_slots = other.tile_slots;
+
+ foreach (const int slot, tile_slots) {
+ manager->add_image_user(slot);
}
+
+ return *this;
}
-ImageManager::~ImageManager()
+ImageHandle::~ImageHandle()
{
- for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++)
- assert(!images[type][slot]);
+ clear();
+}
+
+void ImageHandle::clear()
+{
+ foreach (const int slot, tile_slots) {
+ manager->remove_image_user(slot);
}
}
-void ImageManager::set_osl_texture_system(void *texture_system)
+bool ImageHandle::empty()
{
- osl_texture_system = texture_system;
+ return tile_slots.empty();
}
-bool ImageManager::set_animation_frame_update(int frame)
+int ImageHandle::num_tiles()
{
- if (frame != animation_frame) {
- animation_frame = frame;
+ return tile_slots.size();
+}
- for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] && images[type][slot]->key.animated)
- return true;
- }
- }
+ImageMetaData ImageHandle::metadata()
+{
+ if (tile_slots.empty()) {
+ return ImageMetaData();
}
- return false;
+ ImageManager::Image *img = manager->images[tile_slots.front()];
+ manager->load_image_metadata(img);
+ return img->metadata;
}
-device_memory *ImageManager::image_memory(int flat_slot)
+int ImageHandle::svm_slot(const int tile_index) const
{
- ImageDataType type;
- int slot = flattened_slot_to_type_index(flat_slot, &type);
+ if (tile_index >= tile_slots.size()) {
+ return -1;
+ }
- Image *img = images[type][slot];
+ if (manager->osl_texture_system) {
+ ImageManager::Image *img = manager->images[tile_slots[tile_index]];
+ if (img->loader->osl_filepath()) {
+ return -1;
+ }
+ }
- return img->mem;
+ return tile_slots[tile_index];
}
-bool ImageManager::get_image_metadata(int flat_slot, ImageMetaData &metadata)
+device_memory *ImageHandle::image_memory(const int tile_index) const
{
- if (flat_slot == -1) {
- return false;
+ if (tile_index >= tile_slots.size()) {
+ return NULL;
}
- ImageDataType type;
- int slot = flattened_slot_to_type_index(flat_slot, &type);
+ ImageManager::Image *img = manager->images[tile_slots[tile_index]];
+ return img ? img->mem : NULL;
+}
- Image *img = images[type][slot];
- if (img) {
- metadata = img->metadata;
- return true;
- }
+bool ImageHandle::operator==(const ImageHandle &other) const
+{
+ return manager == other.manager && tile_slots == other.tile_slots;
+}
- return false;
+/* Image MetaData */
+
+ImageMetaData::ImageMetaData()
+ : channels(0),
+ width(0),
+ height(0),
+ depth(0),
+ type(IMAGE_DATA_NUM_TYPES),
+ colorspace(u_colorspace_raw),
+ colorspace_file_format(""),
+ compress_as_srgb(false)
+{
+}
+
+bool ImageMetaData::operator==(const ImageMetaData &other) const
+{
+ return channels == other.channels && width == other.width && height == other.height &&
+ depth == other.depth && type == other.type && colorspace == other.colorspace &&
+ compress_as_srgb == other.compress_as_srgb;
+}
+
+bool ImageMetaData::is_float() const
+{
+ return (type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4 ||
+ type == IMAGE_DATA_TYPE_HALF || type == IMAGE_DATA_TYPE_HALF4);
}
-void ImageManager::metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format)
+void ImageMetaData::detect_colorspace()
{
/* Convert used specified color spaces to one we know how to handle. */
- metadata.colorspace = ColorSpaceManager::detect_known_colorspace(
- metadata.colorspace, file_format, metadata.is_float || metadata.is_half);
+ colorspace = ColorSpaceManager::detect_known_colorspace(
+ colorspace, colorspace_file_format, is_float());
- if (metadata.colorspace == u_colorspace_raw) {
+ if (colorspace == u_colorspace_raw) {
/* Nothing to do. */
}
- else if (metadata.colorspace == u_colorspace_srgb) {
+ else if (colorspace == u_colorspace_srgb) {
/* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time
* for the common case of 8bit sRGB images like PNG. */
- metadata.compress_as_srgb = true;
+ compress_as_srgb = true;
}
else {
/* Always compress non-raw 8bit images as scene linear + sRGB, as a
* heuristic to keep memory usage the same without too much data loss
* due to quantization in common cases. */
- metadata.compress_as_srgb = (metadata.type == IMAGE_DATA_TYPE_BYTE ||
- metadata.type == IMAGE_DATA_TYPE_BYTE4);
+ compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4);
/* If colorspace conversion needed, use half instead of short so we can
* represent HDR values that might result from conversion. */
- if (metadata.type == IMAGE_DATA_TYPE_USHORT) {
- metadata.type = IMAGE_DATA_TYPE_HALF;
+ if (type == IMAGE_DATA_TYPE_USHORT) {
+ type = IMAGE_DATA_TYPE_HALF;
}
- else if (metadata.type == IMAGE_DATA_TYPE_USHORT4) {
- metadata.type = IMAGE_DATA_TYPE_HALF4;
+ else if (type == IMAGE_DATA_TYPE_USHORT4) {
+ type = IMAGE_DATA_TYPE_HALF4;
}
}
}
-bool ImageManager::get_image_metadata(const ImageKey &key, ImageMetaData &metadata)
-{
- metadata = ImageMetaData();
- metadata.colorspace = key.colorspace;
+/* Image Loader */
- if (key.builtin_data) {
- if (builtin_image_info_cb) {
- builtin_image_info_cb(key.filename, key.builtin_data, metadata);
- }
- else {
- return false;
- }
-
- if (metadata.is_float) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
- }
- else {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
- }
+ImageLoader::ImageLoader()
+{
+}
- metadata_detect_colorspace(metadata, "");
+ustring ImageLoader::osl_filepath() const
+{
+ return ustring();
+}
+bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b)
+{
+ if (a == NULL && b == NULL) {
return true;
}
-
- /* Perform preliminary checks, with meaningful logging. */
- if (!path_exists(key.filename)) {
- VLOG(1) << "File '" << key.filename << "' does not exist.";
- return false;
+ else {
+ return (a && b && typeid(*a) == typeid(*b) && a->equals(*b));
}
- if (path_is_directory(key.filename)) {
- VLOG(1) << "File '" << key.filename << "' is a directory, can't use as image.";
- return false;
+}
+
+/* Image Manager */
+
+ImageManager::ImageManager(const DeviceInfo &info)
+{
+ need_update = true;
+ osl_texture_system = NULL;
+ animation_frame = 0;
+
+ /* Set image limits */
+ has_half_images = info.has_half_images;
+}
+
+ImageManager::~ImageManager()
+{
+ for (size_t slot = 0; slot < images.size(); slot++)
+ assert(!images[slot]);
+}
+
+void ImageManager::set_osl_texture_system(void *texture_system)
+{
+ osl_texture_system = texture_system;
+}
+
+bool ImageManager::set_animation_frame_update(int frame)
+{
+ if (frame != animation_frame) {
+ animation_frame = frame;
+
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ if (images[slot] && images[slot]->params.animated)
+ return true;
+ }
}
- unique_ptr<ImageInput> in(ImageInput::create(key.filename));
+ return false;
+}
- if (!in) {
- return false;
+void ImageManager::load_image_metadata(Image *img)
+{
+ if (!img->need_metadata) {
+ return;
}
- ImageSpec spec;
- if (!in->open(key.filename, spec)) {
- return false;
+ thread_scoped_lock image_lock(img->mutex);
+ if (!img->need_metadata) {
+ return;
}
- metadata.width = spec.width;
- metadata.height = spec.height;
- metadata.depth = spec.depth;
- metadata.compress_as_srgb = false;
+ ImageMetaData &metadata = img->metadata;
+ metadata = ImageMetaData();
+ metadata.colorspace = img->params.colorspace;
- /* Check the main format, and channel formats. */
- size_t channel_size = spec.format.basesize();
+ img->loader->load_metadata(metadata);
- if (spec.format.is_floating_point()) {
- metadata.is_float = true;
- }
+ metadata.detect_colorspace();
- for (size_t channel = 0; channel < spec.channelformats.size(); channel++) {
- channel_size = max(channel_size, spec.channelformats[channel].basesize());
- if (spec.channelformats[channel].is_floating_point()) {
- metadata.is_float = true;
+ /* No half textures on OpenCL, use full float instead. */
+ if (!has_half_images) {
+ if (metadata.type == IMAGE_DATA_TYPE_HALF4) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT4;
+ }
+ else if (metadata.type == IMAGE_DATA_TYPE_HALF) {
+ metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
}
- /* check if it's half float */
- if (spec.format == TypeDesc::HALF) {
- metadata.is_half = true;
- }
+ img->need_metadata = false;
+}
- /* set type and channels */
- metadata.channels = spec.nchannels;
+ImageHandle ImageManager::add_image(const string &filename, const ImageParams &params)
+{
+ const int slot = add_image_slot(new OIIOImageLoader(filename), params, false);
- if (metadata.is_half) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
- }
- else if (metadata.is_float) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
- }
- else if (spec.format == TypeDesc::USHORT) {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT;
- }
- else {
- metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ ImageHandle handle;
+ handle.tile_slots.push_back(slot);
+ handle.manager = this;
+ return handle;
+}
+
+ImageHandle ImageManager::add_image(const string &filename,
+ const ImageParams &params,
+ const vector<int> &tiles)
+{
+ ImageHandle handle;
+ handle.manager = this;
+
+ foreach (int tile, tiles) {
+ string tile_filename = filename;
+ if (tile != 0) {
+ string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
+ }
+ const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
+ handle.tile_slots.push_back(slot);
}
- metadata_detect_colorspace(metadata, in->format_name());
+ return handle;
+}
- in->close();
+ImageHandle ImageManager::add_image(ImageLoader *loader, const ImageParams &params)
+{
+ const int slot = add_image_slot(loader, params, true);
- return true;
+ ImageHandle handle;
+ handle.tile_slots.push_back(slot);
+ handle.manager = this;
+ return handle;
}
-int ImageManager::add_image(const ImageKey &key, float frame, ImageMetaData &metadata)
+int ImageManager::add_image_slot(ImageLoader *loader,
+ const ImageParams &params,
+ const bool builtin)
{
Image *img;
size_t slot;
- get_image_metadata(key, metadata);
- ImageDataType type = metadata.type;
-
thread_scoped_lock device_lock(device_mutex);
- /* No half textures on OpenCL, use full float instead. */
- if (!has_half_images) {
- if (type == IMAGE_DATA_TYPE_HALF4) {
- type = IMAGE_DATA_TYPE_FLOAT4;
- }
- else if (type == IMAGE_DATA_TYPE_HALF) {
- type = IMAGE_DATA_TYPE_FLOAT;
- }
- }
-
/* Fnd existing image. */
- for (slot = 0; slot < images[type].size(); slot++) {
- img = images[type][slot];
- if (img && img->key == key) {
- if (img->frame != frame) {
- img->frame = frame;
- img->need_load = true;
- }
- if (!(img->metadata == metadata)) {
- img->metadata = metadata;
- img->need_load = true;
- }
+ for (slot = 0; slot < images.size(); slot++) {
+ img = images[slot];
+ if (img && ImageLoader::equals(img->loader, loader) && img->params == params) {
img->users++;
- return type_index_to_flattened_slot(slot, type);
+ delete loader;
+ return slot;
}
}
/* Find free slot. */
- for (slot = 0; slot < images[type].size(); slot++) {
- if (!images[type][slot])
+ for (slot = 0; slot < images.size(); slot++) {
+ if (!images[slot])
break;
}
- /* Count if we're over the limit.
- * Very unlikely, since max_num_images is insanely big. But better safe
- * than sorry.
- */
- int tex_count = 0;
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- tex_count += tex_num_images[type];
- }
- if (tex_count > max_num_images) {
- printf(
- "ImageManager::add_image: Reached image limit (%d), "
- "skipping '%s'\n",
- max_num_images,
- key.filename.c_str());
- return -1;
- }
-
- if (slot == images[type].size()) {
- images[type].resize(images[type].size() + 1);
+ if (slot == images.size()) {
+ images.resize(images.size() + 1);
}
/* Add new image. */
img = new Image();
- img->key = key;
- img->frame = frame;
- img->metadata = metadata;
- img->need_load = true;
+ img->params = params;
+ img->loader = loader;
+ img->need_metadata = true;
+ img->need_load = !(osl_texture_system && img->loader->osl_filepath());
+ img->builtin = builtin;
img->users = 1;
img->mem = NULL;
- images[type][slot] = img;
-
- ++tex_num_images[type];
+ images[slot] = img;
need_update = true;
- return type_index_to_flattened_slot(slot, type);
+ return slot;
}
-void ImageManager::add_image_user(int flat_slot)
+void ImageManager::add_image_user(int slot)
{
- ImageDataType type;
- int slot = flattened_slot_to_type_index(flat_slot, &type);
-
- Image *image = images[type][slot];
+ Image *image = images[slot];
assert(image && image->users >= 1);
image->users++;
}
-void ImageManager::remove_image(int flat_slot)
+void ImageManager::remove_image_user(int slot)
{
- ImageDataType type;
- int slot = flattened_slot_to_type_index(flat_slot, &type);
-
- Image *image = images[type][slot];
+ Image *image = images[slot];
assert(image && image->users >= 1);
/* decrement user count */
@@ -402,98 +429,22 @@ void ImageManager::remove_image(int flat_slot)
need_update = true;
}
-void ImageManager::remove_image(const ImageKey &key)
-{
- size_t slot;
-
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] && images[type][slot]->key == key) {
- remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type));
- return;
- }
- }
- }
-}
-
-/* TODO(sergey): Deduplicate with the iteration above, but make it pretty,
- * without bunch of arguments passing around making code readability even
- * more cluttered.
- */
-void ImageManager::tag_reload_image(const ImageKey &key)
-{
- for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] && images[type][slot]->key == key) {
- images[type][slot]->need_load = true;
- break;
- }
- }
- }
-}
-
static bool image_associate_alpha(ImageManager::Image *img)
{
/* For typical RGBA images we let OIIO convert to associated alpha,
* but some types we want to leave the RGB channels untouched. */
- return !(ColorSpaceManager::colorspace_is_data(img->key.colorspace) ||
- img->key.alpha_type == IMAGE_ALPHA_IGNORE ||
- img->key.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED);
-}
-
-bool ImageManager::file_load_image_generic(Image *img, unique_ptr<ImageInput> *in)
-{
- if (img->key.filename == "")
- return false;
-
- if (!img->key.builtin_data) {
- /* NOTE: Error logging is done in meta data acquisition. */
- if (!path_exists(img->key.filename) || path_is_directory(img->key.filename)) {
- return false;
- }
-
- /* load image from file through OIIO */
- *in = unique_ptr<ImageInput>(ImageInput::create(img->key.filename));
-
- if (!*in)
- return false;
-
- ImageSpec spec = ImageSpec();
- ImageSpec config = ImageSpec();
-
- if (!image_associate_alpha(img)) {
- config.attribute("oiio:UnassociatedAlpha", 1);
- }
-
- if (!(*in)->open(img->key.filename, spec, config)) {
- return false;
- }
- }
- else {
- /* load image using builtin images callbacks */
- if (!builtin_image_info_cb || !builtin_image_pixels_cb)
- return false;
- }
-
- /* we only handle certain number of components */
- if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) {
- if (*in) {
- (*in)->close();
- }
- return false;
- }
-
- return true;
+ return !(ColorSpaceManager::colorspace_is_data(img->params.colorspace) ||
+ img->params.alpha_type == IMAGE_ALPHA_IGNORE ||
+ img->params.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED);
}
template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType>
bool ImageManager::file_load_image(Image *img,
- ImageDataType type,
int texture_limit,
device_vector<DeviceType> &tex_img)
{
- unique_ptr<ImageInput> in = NULL;
- if (!file_load_image_generic(img, &in)) {
+ /* we only handle certain number of components */
+ if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) {
return false;
}
@@ -527,90 +478,21 @@ bool ImageManager::file_load_image(Image *img,
return false;
}
- bool cmyk = false;
const size_t num_pixels = ((size_t)width) * height * depth;
- if (in) {
- /* Read pixels through OpenImageIO. */
- StorageType *readpixels = pixels;
- vector<StorageType> tmppixels;
- if (components > 4) {
- tmppixels.resize(((size_t)width) * height * components);
- readpixels = &tmppixels[0];
- }
-
- if (depth <= 1) {
- size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
- in->read_image(FileFormat,
- (uchar *)readpixels + (height - 1) * scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
- }
- else {
- in->read_image(FileFormat, (uchar *)readpixels);
- }
-
- if (components > 4) {
- size_t dimensions = ((size_t)width) * height;
- for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
- pixels[i * 4 + 3] = tmppixels[i * components + 3];
- pixels[i * 4 + 2] = tmppixels[i * components + 2];
- pixels[i * 4 + 1] = tmppixels[i * components + 1];
- pixels[i * 4 + 0] = tmppixels[i * components + 0];
- }
- tmppixels.clear();
- }
-
- cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
- in->close();
- }
- else {
- /* Read pixels through callback. */
- if (FileFormat == TypeDesc::FLOAT) {
- builtin_image_float_pixels_cb(img->key.filename,
- img->key.builtin_data,
- 0, /* TODO(lukas): Support tiles here? */
- (float *)&pixels[0],
- num_pixels * components,
- image_associate_alpha(img),
- img->metadata.builtin_free_cache);
- }
- else if (FileFormat == TypeDesc::UINT8) {
- builtin_image_pixels_cb(img->key.filename,
- img->key.builtin_data,
- 0, /* TODO(lukas): Support tiles here? */
- (uchar *)&pixels[0],
- num_pixels * components,
- image_associate_alpha(img),
- img->metadata.builtin_free_cache);
- }
- else {
- /* TODO(dingto): Support half for ImBuf. */
- }
- }
+ img->loader->load_pixels(
+ img->metadata, pixels, num_pixels * components, image_associate_alpha(img));
/* The kernel can handle 1 and 4 channel images. Anything that is not a single
* channel image is converted to RGBA format. */
- bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 ||
- type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4);
+ bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 ||
+ img->metadata.type == IMAGE_DATA_TYPE_HALF4 ||
+ img->metadata.type == IMAGE_DATA_TYPE_BYTE4 ||
+ img->metadata.type == IMAGE_DATA_TYPE_USHORT4);
if (is_rgba) {
const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
- if (cmyk) {
- /* CMYK to RGBA. */
- for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- float c = util_image_cast_to_float(pixels[i * 4 + 0]);
- float m = util_image_cast_to_float(pixels[i * 4 + 1]);
- float y = util_image_cast_to_float(pixels[i * 4 + 2]);
- float k = util_image_cast_to_float(pixels[i * 4 + 3]);
- pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k));
- pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k));
- pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k));
- pixels[i * 4 + 3] = one;
- }
- }
- else if (components == 2) {
+ if (components == 2) {
/* Grayscale + alpha to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = pixels[i * 2 + 1];
@@ -639,7 +521,7 @@ bool ImageManager::file_load_image(Image *img,
}
/* Disable alpha if requested by the user. */
- if (img->key.alpha_type == IMAGE_ALPHA_IGNORE) {
+ if (img->params.alpha_type == IMAGE_ALPHA_IGNORE) {
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
}
@@ -686,7 +568,8 @@ bool ImageManager::file_load_image(Image *img,
while (max_size * scale_factor > texture_limit) {
scale_factor *= 0.5f;
}
- VLOG(1) << "Scaling image " << img->key.filename << " by a factor of " << scale_factor << ".";
+ VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
+ << ".";
vector<StorageType> scaled_pixels;
size_t scaled_width, scaled_height, scaled_depth;
util_image_resize_pixels(pixels_storage,
@@ -716,29 +599,28 @@ bool ImageManager::file_load_image(Image *img,
static void image_set_device_memory(ImageManager::Image *img, device_memory *mem)
{
img->mem = mem;
- mem->interpolation = img->key.interpolation;
- mem->extension = img->key.extension;
+ mem->image_data_type = img->metadata.type;
+ mem->interpolation = img->params.interpolation;
+ mem->extension = img->params.extension;
}
-void ImageManager::device_load_image(
- Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress)
+void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress)
{
- if (progress->get_cancel())
+ if (progress->get_cancel()) {
return;
+ }
- Image *img = images[type][slot];
+ Image *img = images[slot];
- if (osl_texture_system && !img->key.builtin_data)
- return;
-
- string filename = path_filename(images[type][slot]->key.filename);
- progress->set_status("Updating Images", "Loading " + filename);
+ progress->set_status("Updating Images", "Loading " + img->loader->name());
const int texture_limit = scene->params.texture_limit;
+ load_image_metadata(img);
+ ImageDataType type = img->metadata.type;
+
/* Slot assignment */
- int flat_slot = type_index_to_flattened_slot(slot, type);
- img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), flat_slot);
+ img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), slot);
/* Free previous texture in slot. */
if (img->mem) {
@@ -752,7 +634,7 @@ void ImageManager::device_load_image(
device_vector<float4> *tex_img = new device_vector<float4>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
float *pixels = (float *)tex_img->alloc(1, 1);
@@ -772,7 +654,7 @@ void ImageManager::device_load_image(
device_vector<float> *tex_img = new device_vector<float>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
float *pixels = (float *)tex_img->alloc(1, 1);
@@ -789,7 +671,7 @@ void ImageManager::device_load_image(
device_vector<uchar4> *tex_img = new device_vector<uchar4>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
uchar *pixels = (uchar *)tex_img->alloc(1, 1);
@@ -809,7 +691,7 @@ void ImageManager::device_load_image(
device_vector<uchar> *tex_img = new device_vector<uchar>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
uchar *pixels = (uchar *)tex_img->alloc(1, 1);
@@ -826,7 +708,7 @@ void ImageManager::device_load_image(
device_vector<half4> *tex_img = new device_vector<half4>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
half *pixels = (half *)tex_img->alloc(1, 1);
@@ -846,7 +728,7 @@ void ImageManager::device_load_image(
device_vector<uint16_t> *tex_img = new device_vector<uint16_t>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1);
@@ -863,7 +745,7 @@ void ImageManager::device_load_image(
device_vector<ushort4> *tex_img = new device_vector<ushort4>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1);
@@ -883,7 +765,7 @@ void ImageManager::device_load_image(
device_vector<half> *tex_img = new device_vector<half>(
device, img->mem_name.c_str(), MEM_TEXTURE);
- if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) {
+ if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit, *tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
thread_scoped_lock device_lock(device_mutex);
half *pixels = (half *)tex_img->alloc(1, 1);
@@ -896,30 +778,36 @@ void ImageManager::device_load_image(
thread_scoped_lock device_lock(device_mutex);
tex_img->copy_to_device();
}
+
+ /* Cleanup memory in image loader. */
+ img->loader->cleanup();
img->need_load = false;
}
-void ImageManager::device_free_image(Device *, ImageDataType type, int slot)
+void ImageManager::device_free_image(Device *, int slot)
{
- Image *img = images[type][slot];
+ Image *img = images[slot];
+ if (img == NULL) {
+ return;
+ }
- if (img) {
- if (osl_texture_system && !img->key.builtin_data) {
+ if (osl_texture_system) {
#ifdef WITH_OSL
- ustring filename(images[type][slot]->key.filename);
- ((OSL::TextureSystem *)osl_texture_system)->invalidate(filename);
-#endif
- }
-
- if (img->mem) {
- thread_scoped_lock device_lock(device_mutex);
- delete img->mem;
+ ustring filepath = img->loader->osl_filepath();
+ if (filepath) {
+ ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
}
+#endif
+ }
- delete img;
- images[type][slot] = NULL;
- --tex_num_images[type];
+ if (img->mem) {
+ thread_scoped_lock device_lock(device_mutex);
+ delete img->mem;
}
+
+ delete img->loader;
+ delete img;
+ images[slot] = NULL;
}
void ImageManager::device_update(Device *device, Scene *scene, Progress &progress)
@@ -929,24 +817,14 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
}
TaskPool pool;
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (!images[type][slot])
- continue;
-
- if (images[type][slot]->users == 0) {
- device_free_image(device, (ImageDataType)type, slot);
- }
- else if (images[type][slot]->need_load) {
- if (!osl_texture_system || images[type][slot]->key.builtin_data)
- pool.push(function_bind(&ImageManager::device_load_image,
- this,
- device,
- scene,
- (ImageDataType)type,
- slot,
- &progress));
- }
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ Image *img = images[slot];
+ if (img && img->users == 0) {
+ device_free_image(device, slot);
+ }
+ else if (img && img->need_load) {
+ pool.push(
+ function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
}
}
@@ -955,23 +833,16 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
need_update = false;
}
-void ImageManager::device_update_slot(Device *device,
- Scene *scene,
- int flat_slot,
- Progress *progress)
+void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
{
- ImageDataType type;
- int slot = flattened_slot_to_type_index(flat_slot, &type);
+ Image *img = images[slot];
+ assert(img != NULL);
- Image *image = images[type][slot];
- assert(image != NULL);
-
- if (image->users == 0) {
- device_free_image(device, type, slot);
+ if (img->users == 0) {
+ device_free_image(device, slot);
}
- else if (image->need_load) {
- if (!osl_texture_system || image->key.builtin_data)
- device_load_image(device, scene, type, slot, progress);
+ else if (img->need_load) {
+ device_load_image(device, scene, slot, progress);
}
}
@@ -984,22 +855,11 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p
}
TaskPool pool;
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (!images[type][slot])
- continue;
-
- if (images[type][slot]->need_load) {
- if (images[type][slot]->key.builtin_data) {
- pool.push(function_bind(&ImageManager::device_load_image,
- this,
- device,
- scene,
- (ImageDataType)type,
- slot,
- &progress));
- }
- }
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ Image *img = images[slot];
+ if (img && img->need_load && img->builtin) {
+ pool.push(
+ function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
}
}
@@ -1008,31 +868,27 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p
void ImageManager::device_free_builtin(Device *device)
{
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] && images[type][slot]->key.builtin_data)
- device_free_image(device, (ImageDataType)type, slot);
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ Image *img = images[slot];
+ if (img && img->builtin) {
+ device_free_image(device, slot);
}
}
}
void ImageManager::device_free(Device *device)
{
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- for (size_t slot = 0; slot < images[type].size(); slot++) {
- device_free_image(device, (ImageDataType)type, slot);
- }
- images[type].clear();
+ for (size_t slot = 0; slot < images.size(); slot++) {
+ device_free_image(device, slot);
}
+ images.clear();
}
void ImageManager::collect_statistics(RenderStats *stats)
{
- for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
- foreach (const Image *image, images[type]) {
- stats->image.textures.add_entry(
- NamedSizeEntry(path_filename(image->key.filename), image->mem->memory_size()));
- }
+ foreach (const Image *image, images) {
+ stats->image.textures.add_entry(
+ NamedSizeEntry(image->loader->name(), image->mem->memory_size()));
}
}
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index ee60390d628..82f3e2759c6 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -22,7 +22,6 @@
#include "render/colorspace.h"
-#include "util/util_image.h"
#include "util/util_string.h"
#include "util/util_thread.h"
#include "util/util_unique_ptr.h"
@@ -31,91 +30,144 @@
CCL_NAMESPACE_BEGIN
class Device;
+class ImageHandle;
+class ImageKey;
+class ImageMetaData;
+class ImageManager;
class Progress;
class RenderStats;
class Scene;
class ColorSpaceProcessor;
-class ImageMetaData {
+/* Image Parameters */
+class ImageParams {
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;
- ustring colorspace;
- bool compress_as_srgb;
-
- ImageMetaData()
- : is_float(false),
- is_half(false),
- channels(0),
- width(0),
- height(0),
- depth(0),
- builtin_free_cache(false),
- type((ImageDataType)0),
- colorspace(u_colorspace_raw),
- compress_as_srgb(false)
- {
- }
-
- bool operator==(const ImageMetaData &other) const
- {
- return is_float == other.is_float && is_half == other.is_half && channels == other.channels &&
- width == other.width && height == other.height && depth == other.depth &&
- type == other.type && colorspace == other.colorspace &&
- compress_as_srgb == other.compress_as_srgb;
- }
-};
-
-class ImageKey {
- public:
- string filename;
- void *builtin_data;
bool animated;
InterpolationType interpolation;
ExtensionType extension;
ImageAlphaType alpha_type;
ustring colorspace;
+ float frame;
- ImageKey()
- : builtin_data(NULL),
- animated(false),
+ ImageParams()
+ : animated(false),
interpolation(INTERPOLATION_LINEAR),
extension(EXTENSION_CLIP),
alpha_type(IMAGE_ALPHA_AUTO),
- colorspace(u_colorspace_raw)
+ colorspace(u_colorspace_raw),
+ frame(0.0f)
{
}
- bool operator==(const ImageKey &other) const
+ bool operator==(const ImageParams &other) const
{
- return (filename == other.filename && builtin_data == other.builtin_data &&
- animated == other.animated && interpolation == other.interpolation &&
+ return (animated == other.animated && interpolation == other.interpolation &&
extension == other.extension && alpha_type == other.alpha_type &&
- colorspace == other.colorspace);
+ colorspace == other.colorspace && frame == other.frame);
}
};
+/* Image MetaData
+ *
+ * Information about the image that is available before the image pixels are loaded. */
+class ImageMetaData {
+ public:
+ /* Set by ImageLoader.load_metadata(). */
+ int channels;
+ size_t width, height, depth;
+ ImageDataType type;
+
+ /* Optional color space, defaults to raw. */
+ ustring colorspace;
+ const char *colorspace_file_format;
+
+ /* Automatically set. */
+ bool compress_as_srgb;
+
+ ImageMetaData();
+ bool operator==(const ImageMetaData &other) const;
+ bool is_float() const;
+ void detect_colorspace();
+};
+
+/* Image loader base class, that can be subclassed to load image data
+ * from custom sources (file, memory, procedurally generated, etc). */
+class ImageLoader {
+ public:
+ ImageLoader();
+ virtual ~ImageLoader(){};
+
+ /* Load metadata without actual image yet, should be fast. */
+ virtual bool load_metadata(ImageMetaData &metadata) = 0;
+
+ /* Load actual image contents. */
+ virtual bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) = 0;
+
+ /* Name for logs and stats. */
+ virtual string name() const = 0;
+
+ /* Optional for OSL texture cache. */
+ virtual ustring osl_filepath() const;
+
+ /* Free any memory used for loading metadata and pixels. */
+ virtual void cleanup(){};
+
+ /* Compare avoid loading the same image multiple times. */
+ virtual bool equals(const ImageLoader &other) const = 0;
+ static bool equals(const ImageLoader *a, const ImageLoader *b);
+
+ /* Work around for no RTTI. */
+};
+
+/* Image Handle
+ *
+ * Access handle for image in the image manager. Multiple shader nodes may
+ * share the same image, and this class handles reference counting for that. */
+class ImageHandle {
+ public:
+ ImageHandle();
+ ImageHandle(const ImageHandle &other);
+ ImageHandle &operator=(const ImageHandle &other);
+ ~ImageHandle();
+
+ bool operator==(const ImageHandle &other) const;
+
+ void clear();
+
+ bool empty();
+ int num_tiles();
+
+ ImageMetaData metadata();
+ int svm_slot(const int tile_index = 0) const;
+ device_memory *image_memory(const int tile_index = 0) const;
+
+ protected:
+ vector<int> tile_slots;
+ ImageManager *manager;
+
+ friend class ImageManager;
+};
+
+/* Image Manager
+ *
+ * Handles loading and storage of all images in the scene. This includes 2D
+ * texture images and 3D volume images. */
class ImageManager {
public:
explicit ImageManager(const DeviceInfo &info);
~ImageManager();
- int add_image(const ImageKey &key, float frame, ImageMetaData &metadata);
- void add_image_user(int flat_slot);
- void remove_image(int flat_slot);
- void remove_image(const ImageKey &key);
- void tag_reload_image(const ImageKey &key);
- bool get_image_metadata(const ImageKey &key, ImageMetaData &metadata);
- bool get_image_metadata(int flat_slot, ImageMetaData &metadata);
+ ImageHandle add_image(const string &filename, const ImageParams &params);
+ ImageHandle add_image(const string &filename,
+ const ImageParams &params,
+ const vector<int> &tiles);
+ ImageHandle add_image(ImageLoader *loader, const ImageParams &params);
void device_update(Device *device, Scene *scene, Progress &progress);
- void device_update_slot(Device *device, Scene *scene, int flat_slot, Progress *progress);
+ void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);
void device_free(Device *device);
void device_load_builtin(Device *device, Scene *scene, Progress &progress);
@@ -124,72 +176,49 @@ class ImageManager {
void set_osl_texture_system(void *texture_system);
bool set_animation_frame_update(int frame);
- device_memory *image_memory(int flat_slot);
-
void collect_statistics(RenderStats *stats);
bool need_update;
- /* NOTE: Here pixels_size is a size of storage, which equals to
- * width * height * depth.
- * Use this to avoid some nasty memory corruptions.
- */
- function<void(const string &filename, void *data, ImageMetaData &metadata)>
- builtin_image_info_cb;
- function<bool(const string &filename,
- void *data,
- int tile,
- unsigned char *pixels,
- const size_t pixels_size,
- const bool associate_alpha,
- const bool free_cache)>
- builtin_image_pixels_cb;
- function<bool(const string &filename,
- void *data,
- int tile,
- float *pixels,
- const size_t pixels_size,
- const bool associate_alpha,
- const bool free_cache)>
- builtin_image_float_pixels_cb;
-
struct Image {
- ImageKey key;
+ ImageParams params;
ImageMetaData metadata;
+ ImageLoader *loader;
float frame;
+ bool need_metadata;
bool need_load;
+ bool builtin;
string mem_name;
device_memory *mem;
int users;
+ thread_mutex mutex;
};
private:
- int tex_num_images[IMAGE_DATA_NUM_TYPES];
- int max_num_images;
bool has_half_images;
thread_mutex device_mutex;
int animation_frame;
- vector<Image *> images[IMAGE_DATA_NUM_TYPES];
+ vector<Image *> images;
void *osl_texture_system;
- bool file_load_image_generic(Image *img, unique_ptr<ImageInput> *in);
+ int add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
+ void add_image_user(int slot);
+ void remove_image_user(int slot);
+
+ void load_image_metadata(Image *img);
template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType>
- bool file_load_image(Image *img,
- ImageDataType type,
- int texture_limit,
- device_vector<DeviceType> &tex_img);
+ bool file_load_image(Image *img, int texture_limit, device_vector<DeviceType> &tex_img);
- void metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format);
+ void device_load_image(Device *device, Scene *scene, int slot, Progress *progress);
+ void device_free_image(Device *device, int slot);
- void device_load_image(
- Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress);
- void device_free_image(Device *device, ImageDataType type, int slot);
+ friend class ImageHandle;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_oiio.cpp b/intern/cycles/render/image_oiio.cpp
new file mode 100644
index 00000000000..c4f95c6b4bc
--- /dev/null
+++ b/intern/cycles/render/image_oiio.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2011-2020 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/image_oiio.h"
+
+#include "util/util_image.h"
+#include "util/util_logging.h"
+#include "util/util_path.h"
+
+CCL_NAMESPACE_BEGIN
+
+OIIOImageLoader::OIIOImageLoader(const string &filepath) : filepath(filepath)
+{
+}
+
+OIIOImageLoader::~OIIOImageLoader()
+{
+}
+
+bool OIIOImageLoader::load_metadata(ImageMetaData &metadata)
+{
+ /* Perform preliminary checks, with meaningful logging. */
+ if (!path_exists(filepath.string())) {
+ VLOG(1) << "File '" << filepath.string() << "' does not exist.";
+ return false;
+ }
+ if (path_is_directory(filepath.string())) {
+ VLOG(1) << "File '" << filepath.string() << "' is a directory, can't use as image.";
+ return false;
+ }
+
+ unique_ptr<ImageInput> in(ImageInput::create(filepath.string()));
+
+ if (!in) {
+ return false;
+ }
+
+ ImageSpec spec;
+ if (!in->open(filepath.string(), spec)) {
+ return false;
+ }
+
+ metadata.width = spec.width;
+ metadata.height = spec.height;
+ metadata.depth = spec.depth;
+ metadata.compress_as_srgb = false;
+
+ /* Check the main format, and channel formats. */
+ size_t channel_size = spec.format.basesize();
+
+ bool is_float = false;
+ bool is_half = false;
+
+ if (spec.format.is_floating_point()) {
+ is_float = true;
+ }
+
+ for (size_t channel = 0; channel < spec.channelformats.size(); channel++) {
+ channel_size = max(channel_size, spec.channelformats[channel].basesize());
+ if (spec.channelformats[channel].is_floating_point()) {
+ is_float = true;
+ }
+ }
+
+ /* check if it's half float */
+ if (spec.format == TypeDesc::HALF) {
+ is_half = true;
+ }
+
+ /* set type and channels */
+ metadata.channels = spec.nchannels;
+
+ if (is_half) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
+ }
+ else if (is_float) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
+ }
+ else if (spec.format == TypeDesc::USHORT) {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT;
+ }
+ else {
+ metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ }
+
+ metadata.colorspace_file_format = in->format_name();
+
+ in->close();
+
+ return true;
+}
+
+template<TypeDesc::BASETYPE FileFormat, typename StorageType>
+static void oiio_load_pixels(const ImageMetaData &metadata,
+ const unique_ptr<ImageInput> &in,
+ StorageType *pixels)
+{
+ const int width = metadata.width;
+ const int height = metadata.height;
+ const int depth = metadata.depth;
+ const int components = metadata.channels;
+
+ /* Read pixels through OpenImageIO. */
+ StorageType *readpixels = pixels;
+ vector<StorageType> tmppixels;
+ if (components > 4) {
+ tmppixels.resize(((size_t)width) * height * components);
+ readpixels = &tmppixels[0];
+ }
+
+ if (depth <= 1) {
+ size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
+ in->read_image(FileFormat,
+ (uchar *)readpixels + (height - 1) * scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
+ }
+ else {
+ in->read_image(FileFormat, (uchar *)readpixels);
+ }
+
+ if (components > 4) {
+ size_t dimensions = ((size_t)width) * height;
+ for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
+ pixels[i * 4 + 3] = tmppixels[i * components + 3];
+ pixels[i * 4 + 2] = tmppixels[i * components + 2];
+ pixels[i * 4 + 1] = tmppixels[i * components + 1];
+ pixels[i * 4 + 0] = tmppixels[i * components + 0];
+ }
+ tmppixels.clear();
+ }
+
+ /* CMYK to RGBA. */
+ const bool cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
+ if (cmyk) {
+ const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
+
+ const size_t num_pixels = ((size_t)width) * height * depth;
+ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ float c = util_image_cast_to_float(pixels[i * 4 + 0]);
+ float m = util_image_cast_to_float(pixels[i * 4 + 1]);
+ float y = util_image_cast_to_float(pixels[i * 4 + 2]);
+ float k = util_image_cast_to_float(pixels[i * 4 + 3]);
+ pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k));
+ pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k));
+ pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k));
+ pixels[i * 4 + 3] = one;
+ }
+ }
+}
+
+bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t,
+ const bool associate_alpha)
+{
+ unique_ptr<ImageInput> in = NULL;
+
+ /* NOTE: Error logging is done in meta data acquisition. */
+ if (!path_exists(filepath.string()) || path_is_directory(filepath.string())) {
+ return false;
+ }
+
+ /* load image from file through OIIO */
+ in = unique_ptr<ImageInput>(ImageInput::create(filepath.string()));
+ if (!in) {
+ return false;
+ }
+
+ ImageSpec spec = ImageSpec();
+ ImageSpec config = ImageSpec();
+
+ if (!associate_alpha) {
+ config.attribute("oiio:UnassociatedAlpha", 1);
+ }
+
+ if (!in->open(filepath.string(), spec, config)) {
+ return false;
+ }
+
+ switch (metadata.type) {
+ case IMAGE_DATA_TYPE_BYTE:
+ case IMAGE_DATA_TYPE_BYTE4:
+ oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_USHORT:
+ case IMAGE_DATA_TYPE_USHORT4:
+ oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_HALF:
+ case IMAGE_DATA_TYPE_HALF4:
+ oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels);
+ break;
+ case IMAGE_DATA_TYPE_FLOAT:
+ case IMAGE_DATA_TYPE_FLOAT4:
+ oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels);
+ break;
+ case IMAGE_DATA_NUM_TYPES:
+ break;
+ }
+
+ in->close();
+ return true;
+}
+
+string OIIOImageLoader::name() const
+{
+ return path_filename(filepath.string());
+}
+
+ustring OIIOImageLoader::osl_filepath() const
+{
+ return filepath;
+}
+
+bool OIIOImageLoader::equals(const ImageLoader &other) const
+{
+ const OIIOImageLoader &other_loader = (const OIIOImageLoader &)other;
+ return filepath == other_loader.filepath;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_oiio.h b/intern/cycles/render/image_oiio.h
new file mode 100644
index 00000000000..a234b968557
--- /dev/null
+++ b/intern/cycles/render/image_oiio.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2020 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 __IMAGE_OIIO__
+#define __IMAGE_OIIO__
+
+#include "render/image.h"
+
+CCL_NAMESPACE_BEGIN
+
+class OIIOImageLoader : public ImageLoader {
+ public:
+ OIIOImageLoader(const string &filepath);
+ ~OIIOImageLoader();
+
+ bool load_metadata(ImageMetaData &metadata) override;
+
+ bool load_pixels(const ImageMetaData &metadata,
+ void *pixels,
+ const size_t pixels_size,
+ const bool associate_alpha) override;
+
+ string name() const override;
+
+ ustring osl_filepath() const override;
+
+ bool equals(const ImageLoader &other) const override;
+
+ protected:
+ ustring filepath;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __IMAGE_OIIO__ */
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 509637aedd9..8263f68fa9c 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -577,8 +577,8 @@ void LightManager::device_update_background(Device *device,
if (node->type == EnvironmentTextureNode::node_type) {
EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
ImageMetaData metadata;
- if (env->image_manager && !env->slots.empty() &&
- env->image_manager->get_image_metadata(env->slots[0], metadata)) {
+ if (!env->handle.empty()) {
+ ImageMetaData metadata = env->handle.metadata();
res.x = max(res.x, metadata.width);
res.y = max(res.y, metadata.height);
}
diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp
index 74c6a7759a6..3c91aba511d 100644
--- a/intern/cycles/render/mesh_volume.cpp
+++ b/intern/cycles/render/mesh_volume.cpp
@@ -362,7 +362,7 @@ struct VoxelAttributeGrid {
int channels;
};
-void GeometryManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress)
+void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress)
{
string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
progress.set_status("Updating Mesh", msg);
@@ -378,8 +378,8 @@ void GeometryManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &pro
continue;
}
- VoxelAttribute *voxel = attr.data_voxel();
- device_memory *image_memory = scene->image_manager->image_memory(voxel->slot);
+ ImageHandle &handle = attr.data_voxel();
+ device_memory *image_memory = handle.image_memory();
int3 resolution = make_int3(
image_memory->data_width, image_memory->data_height, image_memory->data_depth);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 3967b4ef00e..26b816b65e9 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -206,27 +206,6 @@ void TextureMapping::compile(OSLCompiler &compiler)
/* Image Texture */
-ImageSlotTextureNode::~ImageSlotTextureNode()
-{
- if (image_manager) {
- foreach (int slot, slots) {
- if (slot != -1) {
- image_manager->remove_image(slot);
- }
- }
- }
-}
-
-void ImageSlotTextureNode::add_image_user() const
-{
- /* Increase image user count for new node. */
- foreach (int slot, slots) {
- if (slot != -1) {
- image_manager->add_image_user(slot);
- }
- }
-}
-
NODE_DEFINE(ImageTextureNode)
{
NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER);
@@ -276,34 +255,27 @@ NODE_DEFINE(ImageTextureNode)
ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
{
- is_float = false;
- compress_as_srgb = false;
colorspace = u_colorspace_raw;
- builtin_data = NULL;
animated = false;
tiles.push_back(1001);
}
ShaderNode *ImageTextureNode::clone() const
{
- add_image_user();
- return new ImageTextureNode(*this);
+ ImageTextureNode *node = new ImageTextureNode(*this);
+ node->handle = handle;
+ return node;
}
-ImageKey ImageTextureNode::image_key(const int tile) const
+ImageParams ImageTextureNode::image_params() const
{
- ImageKey key;
- key.filename = filename.string();
- if (tile != 0) {
- string_replace(key.filename, "<UDIM>", string_printf("%04d", tile));
- }
- key.builtin_data = builtin_data;
- key.animated = animated;
- key.interpolation = interpolation;
- key.extension = extension;
- key.alpha_type = alpha_type;
- key.colorspace = colorspace;
- return key;
+ ImageParams params;
+ params.animated = animated;
+ params.interpolation = interpolation;
+ params.extension = extension;
+ params.alpha_type = alpha_type;
+ params.colorspace = colorspace;
+ return params;
}
void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
@@ -388,113 +360,80 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
- image_manager = compiler.scene->image_manager;
- if (slots.empty()) {
+ if (handle.empty()) {
cull_tiles(compiler.scene, compiler.current_graph);
- slots.reserve(tiles.size());
-
- bool have_metadata = false;
- foreach (int tile, tiles) {
- ImageKey key = image_key(tile);
- ImageMetaData metadata;
- int slot = image_manager->add_image(key, 0, metadata);
- slots.push_back(slot);
-
- /* We assume that all tiles have the same metadata. */
- if (!have_metadata) {
- is_float = metadata.is_float;
- compress_as_srgb = metadata.compress_as_srgb;
- known_colorspace = metadata.colorspace;
- have_metadata = true;
- }
- }
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params(), tiles);
}
- bool has_image = false;
- foreach (int slot, slots) {
- if (slot != -1) {
- has_image = true;
- break;
- }
- }
+ /* All tiles have the same metadata. */
+ const ImageMetaData metadata = handle.metadata();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ uint flags = 0;
- if (has_image) {
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- uint flags = 0;
+ if (compress_as_srgb) {
+ flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
+ }
+ if (!alpha_out->links.empty()) {
+ const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
+ alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
+ alpha_type == IMAGE_ALPHA_IGNORE);
- if (compress_as_srgb) {
- flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
+ if (unassociate_alpha) {
+ flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
}
- if (!alpha_out->links.empty()) {
- const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
- alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
- alpha_type == IMAGE_ALPHA_IGNORE);
+ }
- if (unassociate_alpha) {
- flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
- }
+ if (projection != NODE_IMAGE_PROJ_BOX) {
+ /* If there only is one image (a very common case), we encode it as a negative value. */
+ int num_nodes;
+ if (handle.num_tiles() == 1) {
+ num_nodes = -handle.svm_slot();
+ }
+ else {
+ num_nodes = divide_up(handle.num_tiles(), 2);
}
- if (projection != NODE_IMAGE_PROJ_BOX) {
- /* If there only is one image (a very common case), we encode it as a negative value. */
- int num_nodes;
- if (slots.size() == 1) {
- num_nodes = -slots[0];
- }
- else {
- num_nodes = divide_up(slots.size(), 2);
- }
+ compiler.add_node(NODE_TEX_IMAGE,
+ num_nodes,
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out),
+ flags),
+ projection);
- compiler.add_node(NODE_TEX_IMAGE,
- num_nodes,
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out),
- flags),
- projection);
-
- if (num_nodes > 0) {
- for (int i = 0; i < num_nodes; i++) {
- int4 node;
- node.x = tiles[2 * i];
- node.y = slots[2 * i];
- if (2 * i + 1 < slots.size()) {
- node.z = tiles[2 * i + 1];
- node.w = slots[2 * i + 1];
- }
- else {
- node.z = -1;
- node.w = -1;
- }
- compiler.add_node(node.x, node.y, node.z, node.w);
+ if (num_nodes > 0) {
+ for (int i = 0; i < num_nodes; i++) {
+ int4 node;
+ node.x = tiles[2 * i];
+ node.y = handle.svm_slot(2 * i);
+ if (2 * i + 1 < tiles.size()) {
+ node.z = tiles[2 * i + 1];
+ node.w = handle.svm_slot(2 * i + 1);
}
+ else {
+ node.z = -1;
+ node.w = -1;
+ }
+ compiler.add_node(node.x, node.y, node.z, node.w);
}
}
- else {
- assert(slots.size() == 1);
- compiler.add_node(NODE_TEX_IMAGE_BOX,
- slots[0],
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out),
- flags),
- __float_as_int(projection_blend));
- }
-
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
else {
- /* image not found */
- if (!color_out->links.empty()) {
- compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
- compiler.add_node(
- NODE_VALUE_V,
- make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B));
- }
- if (!alpha_out->links.empty())
- compiler.add_node(
- NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out));
+ assert(handle.num_tiles() == 1);
+ compiler.add_node(NODE_TEX_IMAGE_BOX,
+ handle.svm_slot(),
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out),
+ flags),
+ __float_as_int(projection_blend));
}
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void ImageTextureNode::compile(OSLCompiler &compiler)
@@ -503,29 +442,22 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler);
- image_manager = compiler.scene->image_manager;
- if (slots.size() == 0) {
- ImageMetaData metadata;
- if (builtin_data == NULL) {
- ImageKey key = image_key(1001);
- image_manager->get_image_metadata(key, metadata);
- slots.push_back(-1);
- }
- else {
- int slot = image_manager->add_image(image_key(), 0, metadata);
- slots.push_back(slot);
- }
- is_float = metadata.is_float;
- compress_as_srgb = metadata.compress_as_srgb;
- known_colorspace = metadata.colorspace;
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
}
- if (slots[0] == -1) {
+ const ImageMetaData metadata = handle.metadata();
+ const bool is_float = metadata.is_float();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
+
+ if (handle.svm_slot() == -1) {
compiler.parameter_texture(
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
- compiler.parameter_texture("filename", slots[0]);
+ compiler.parameter_texture("filename", handle.svm_slot());
}
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
@@ -587,30 +519,26 @@ NODE_DEFINE(EnvironmentTextureNode)
EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_type)
{
- is_float = false;
- compress_as_srgb = false;
colorspace = u_colorspace_raw;
- builtin_data = NULL;
animated = false;
}
ShaderNode *EnvironmentTextureNode::clone() const
{
- add_image_user();
- return new EnvironmentTextureNode(*this);
+ EnvironmentTextureNode *node = new EnvironmentTextureNode(*this);
+ node->handle = handle;
+ return node;
}
-ImageKey EnvironmentTextureNode::image_key() const
+ImageParams EnvironmentTextureNode::image_params() const
{
- ImageKey key;
- key.filename = filename.string();
- key.builtin_data = builtin_data;
- key.animated = animated;
- key.interpolation = interpolation;
- key.extension = EXTENSION_REPEAT;
- key.alpha_type = alpha_type;
- key.colorspace = colorspace;
- return key;
+ ImageParams params;
+ params.animated = animated;
+ params.interpolation = interpolation;
+ params.extension = EXTENSION_REPEAT;
+ params.alpha_type = alpha_type;
+ params.colorspace = colorspace;
+ return params;
}
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -632,77 +560,53 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
- image_manager = compiler.scene->image_manager;
- if (slots.empty()) {
- ImageMetaData metadata;
- int slot = image_manager->add_image(image_key(), 0, metadata);
- slots.push_back(slot);
- is_float = metadata.is_float;
- compress_as_srgb = metadata.compress_as_srgb;
- known_colorspace = metadata.colorspace;
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
}
- if (slots[0] != -1) {
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- uint flags = 0;
+ const ImageMetaData metadata = handle.metadata();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
- if (compress_as_srgb) {
- flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
- }
-
- compiler.add_node(NODE_TEX_ENVIRONMENT,
- slots[0],
- compiler.encode_uchar4(vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(alpha_out),
- flags),
- projection);
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ uint flags = 0;
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
- }
- else {
- /* image not found */
- if (!color_out->links.empty()) {
- compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
- compiler.add_node(
- NODE_VALUE_V,
- make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B));
- }
- if (!alpha_out->links.empty())
- compiler.add_node(
- NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out));
+ if (compress_as_srgb) {
+ flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
}
+
+ compiler.add_node(NODE_TEX_ENVIRONMENT,
+ handle.svm_slot(),
+ compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(color_out),
+ compiler.stack_assign_if_linked(alpha_out),
+ flags),
+ projection);
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
void EnvironmentTextureNode::compile(OSLCompiler &compiler)
{
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+
tex_mapping.compile(compiler);
- /* See comments in ImageTextureNode::compile about support
- * of builtin images.
- */
- image_manager = compiler.scene->image_manager;
- if (slots.empty()) {
- ImageMetaData metadata;
- if (builtin_data == NULL) {
- image_manager->get_image_metadata(image_key(), metadata);
- slots.push_back(-1);
- }
- else {
- int slot = image_manager->add_image(image_key(), 0, metadata);
- slots.push_back(slot);
- }
- is_float = metadata.is_float;
- compress_as_srgb = metadata.compress_as_srgb;
- known_colorspace = metadata.colorspace;
- }
+ const ImageMetaData metadata = handle.metadata();
+ const bool is_float = metadata.is_float();
+ const bool compress_as_srgb = metadata.compress_as_srgb;
+ const ustring known_colorspace = metadata.colorspace;
- if (slots[0] == -1) {
+ if (handle.svm_slot() == -1) {
compiler.parameter_texture(
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
- compiler.parameter_texture("filename", slots[0]);
+ compiler.parameter_texture("filename", handle.svm_slot());
}
compiler.parameter(this, "projection");
@@ -1741,16 +1645,10 @@ NODE_DEFINE(PointDensityTextureNode)
PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(node_type)
{
- image_manager = NULL;
- slot = -1;
- builtin_data = NULL;
}
PointDensityTextureNode::~PointDensityTextureNode()
{
- if (image_manager) {
- image_manager->remove_image(image_key());
- }
}
ShaderNode *PointDensityTextureNode::clone() const
@@ -1758,10 +1656,9 @@ ShaderNode *PointDensityTextureNode::clone() const
/* Increase image user count for new node. We need to ensure to not call
* add_image again, to work around access of freed data on the Blender
* side. A better solution should be found to avoid this. */
- if (slot != -1) {
- image_manager->add_image_user(slot);
- }
- return new PointDensityTextureNode(*this);
+ PointDensityTextureNode *node = new PointDensityTextureNode(*this);
+ node->handle = handle; /* TODO: not needed? */
+ return node;
}
void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -1772,21 +1669,11 @@ void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *at
ShaderNode::attributes(shader, attributes);
}
-void PointDensityTextureNode::add_image()
-{
- if (slot == -1) {
- ImageMetaData metadata;
- slot = image_manager->add_image(image_key(), 0, metadata);
- }
-}
-
-ImageKey PointDensityTextureNode::image_key() const
+ImageParams PointDensityTextureNode::image_params() const
{
- ImageKey key;
- key.filename = filename.string();
- key.builtin_data = builtin_data;
- key.interpolation = interpolation;
- return key;
+ ImageParams params;
+ params.interpolation = interpolation;
+ return params;
}
void PointDensityTextureNode::compile(SVMCompiler &compiler)
@@ -1798,11 +1685,13 @@ void PointDensityTextureNode::compile(SVMCompiler &compiler)
const bool use_density = !density_out->links.empty();
const bool use_color = !color_out->links.empty();
- image_manager = compiler.scene->image_manager;
-
if (use_density || use_color) {
- add_image();
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
+ const int slot = handle.svm_slot();
if (slot != -1) {
compiler.stack_assign(vector_in);
compiler.add_node(NODE_TEX_VOXEL,
@@ -1839,12 +1728,13 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
const bool use_density = !density_out->links.empty();
const bool use_color = !color_out->links.empty();
- image_manager = compiler.scene->image_manager;
-
if (use_density || use_color) {
- add_image();
+ if (handle.empty()) {
+ ImageManager *image_manager = compiler.scene->image_manager;
+ handle = image_manager->add_image(filename.string(), image_params());
+ }
- compiler.parameter_texture("filename", slot);
+ compiler.parameter_texture("filename", handle.svm_slot());
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
@@ -3358,7 +3248,7 @@ NODE_DEFINE(PrincipledVolumeNode)
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(temperature, "Temperature", 1000.0f);
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(volume, "Volume");
@@ -3369,6 +3259,8 @@ NODE_DEFINE(PrincipledVolumeNode)
PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+ density_attribute = ustring("density");
+ temperature_attribute = ustring("temperature");
}
void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 1d76cb5e828..1f52a2a49ab 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -78,12 +78,15 @@ class ImageSlotTextureNode : public TextureNode {
explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
- image_manager = NULL;
}
- ~ImageSlotTextureNode();
- void add_image_user() const;
- ImageManager *image_manager;
- vector<int> slots;
+
+ virtual bool equals(const ShaderNode &other)
+ {
+ const ImageSlotTextureNode &other_node = (const ImageSlotTextureNode &)other;
+ return TextureNode::equals(other) && handle == other_node.handle;
+ }
+
+ ImageHandle handle;
};
class ImageTextureNode : public ImageSlotTextureNode {
@@ -98,16 +101,14 @@ class ImageTextureNode : public ImageSlotTextureNode {
virtual bool equals(const ShaderNode &other)
{
- const ImageTextureNode &image_node = (const ImageTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data &&
- animated == image_node.animated;
+ const ImageTextureNode &other_node = (const ImageTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && animated == other_node.animated;
}
- ImageKey image_key(const int tile = 0) const;
+ ImageParams image_params() const;
/* Parameters. */
ustring filename;
- void *builtin_data;
ustring colorspace;
ImageAlphaType alpha_type;
NodeImageProjection projection;
@@ -118,11 +119,6 @@ class ImageTextureNode : public ImageSlotTextureNode {
float3 vector;
ccl::vector<int> tiles;
- /* Runtime. */
- bool is_float;
- bool compress_as_srgb;
- ustring known_colorspace;
-
protected:
void cull_tiles(Scene *scene, ShaderGraph *graph);
};
@@ -143,27 +139,20 @@ class EnvironmentTextureNode : public ImageSlotTextureNode {
virtual bool equals(const ShaderNode &other)
{
- const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data &&
- animated == env_node.animated;
+ const EnvironmentTextureNode &other_node = (const EnvironmentTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && animated == other_node.animated;
}
- ImageKey image_key() const;
+ ImageParams image_params() const;
/* Parameters. */
ustring filename;
- void *builtin_data;
ustring colorspace;
ImageAlphaType alpha_type;
NodeEnvironmentProjection projection;
InterpolationType interpolation;
bool animated;
float3 vector;
-
- /* Runtime. */
- bool is_float;
- bool compress_as_srgb;
- ustring known_colorspace;
};
class SkyTextureNode : public TextureNode {
@@ -370,26 +359,22 @@ class PointDensityTextureNode : public ShaderNode {
return true;
}
- void add_image();
-
- ImageKey image_key() const;
-
/* Parameters. */
ustring filename;
NodeTexVoxelSpace space;
InterpolationType interpolation;
Transform tfm;
float3 vector;
- void *builtin_data;
/* Runtime. */
- ImageManager *image_manager;
- int slot;
+ ImageHandle handle;
+
+ ImageParams image_params() const;
virtual bool equals(const ShaderNode &other)
{
- const PointDensityTextureNode &point_dendity_node = (const PointDensityTextureNode &)other;
- return ShaderNode::equals(other) && builtin_data == point_dendity_node.builtin_data;
+ const PointDensityTextureNode &other_node = (const PointDensityTextureNode &)other;
+ return ShaderNode::equals(other) && handle == other_node.handle;
}
};
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index b3916a67f0c..d17d7270cd5 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -102,8 +102,8 @@ void OSLShaderManager::device_update(Device *device,
device_free(device, dscene, scene);
- /* determine which shaders are in use */
- device_update_shaders_used(scene);
+ /* set texture system */
+ scene->image_manager->set_osl_texture_system((void *)ts);
/* create shaders */
OSLGlobals *og = (OSLGlobals *)device->osl_memory();
@@ -142,9 +142,6 @@ void OSLShaderManager::device_update(Device *device,
need_update = false;
- /* set texture system */
- scene->image_manager->set_osl_texture_system((void *)ts);
-
/* add special builtin texture types */
services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
services->textures.insert(ustring("@bevel"), new OSLTextureHandle(OSLTextureHandle::BEVEL));
@@ -440,27 +437,35 @@ const char *OSLShaderManager::shader_load_bytecode(const string &hash, const str
return loaded_shaders.find(hash)->first.c_str();
}
-OSLNode *OSLShaderManager::osl_node(const std::string &filepath,
+/* This is a static function to avoid RTTI link errors with only this
+ * file being compiled without RTTI to match OSL and LLVM libraries. */
+OSLNode *OSLShaderManager::osl_node(ShaderManager *manager,
+ const std::string &filepath,
const std::string &bytecode_hash,
const std::string &bytecode)
{
+ if (!manager->use_osl()) {
+ return NULL;
+ }
+
/* create query */
+ OSLShaderManager *osl_manager = static_cast<OSLShaderManager *>(manager);
const char *hash;
if (!filepath.empty()) {
- hash = shader_load_filepath(filepath);
+ hash = osl_manager->shader_load_filepath(filepath);
}
else {
- hash = shader_test_loaded(bytecode_hash);
+ hash = osl_manager->shader_test_loaded(bytecode_hash);
if (!hash)
- hash = shader_load_bytecode(bytecode_hash, bytecode);
+ hash = osl_manager->shader_load_bytecode(bytecode_hash, bytecode);
}
if (!hash) {
return NULL;
}
- OSLShaderInfo *info = shader_loaded_info(hash);
+ OSLShaderInfo *info = osl_manager->shader_loaded_info(hash);
/* count number of inputs */
size_t num_inputs = 0;
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 62cbfebf7eb..4dd9f6630f2 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -93,9 +93,10 @@ class OSLShaderManager : public ShaderManager {
OSLShaderInfo *shader_loaded_info(const string &hash);
/* create OSL node using OSLQuery */
- OSLNode *osl_node(const std::string &filepath,
- const std::string &bytecode_hash = "",
- const std::string &bytecode = "");
+ static OSLNode *osl_node(ShaderManager *manager,
+ const std::string &filepath,
+ const std::string &bytecode_hash = "",
+ const std::string &bytecode = "");
protected:
void texture_system_init();
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 7fab2fdedeb..1e20513e88a 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -104,9 +104,11 @@ Scene::Scene(const SceneParams &params_, Device *device)
/* OSL only works on the CPU */
if (device->info.has_osl)
- shader_manager = ShaderManager::create(this, params.shadingsystem);
+ shader_manager = ShaderManager::create(params.shadingsystem);
else
- shader_manager = ShaderManager::create(this, SHADINGSYSTEM_SVM);
+ shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
+
+ shader_manager->add_default(this);
}
Scene::~Scene()
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 1dceb93aef7..d2570138b53 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -230,6 +230,7 @@ class Scene {
/* default shaders */
Shader *default_surface;
+ Shader *default_volume;
Shader *default_light;
Shader *default_background;
Shader *default_empty;
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 6bf2160f9fa..b5d434a604c 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -987,7 +987,8 @@ bool Session::update_scene()
/* update scene */
if (scene->need_update()) {
- bool new_kernels_needed = load_kernels(false);
+ /* Updated used shader tag so we know which features are need for the kernel. */
+ scene->shader_manager->update_shaders_used(scene);
/* Update max_closures. */
KernelIntegrator *kintegrator = &scene->dscene.data.integrator;
@@ -999,6 +1000,9 @@ bool Session::update_scene()
kintegrator->max_closures = MAX_CLOSURE;
}
+ /* Load render kernels, before device update where we upload data to the GPU. */
+ bool new_kernels_needed = load_kernels(false);
+
progress.set_status("Updating Scene");
MEM_GUARDED_CALL(&progress, scene->device_update, device, progress);
@@ -1271,8 +1275,11 @@ int Session::get_max_closure_count()
int max_closures = 0;
for (int i = 0; i < scene->shaders.size(); i++) {
- int num_closures = scene->shaders[i]->graph->get_num_closures();
- max_closures = max(max_closures, num_closures);
+ Shader *shader = scene->shaders[i];
+ if (shader->used) {
+ int num_closures = shader->graph->get_num_closures();
+ max_closures = max(max_closures, num_closures);
+ }
}
max_closure_global = max(max_closure_global, max_closures);
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 60f38aa14da..cc6eb2e5e7f 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -168,7 +168,7 @@ NODE_DEFINE(Shader)
SOCKET_ENUM(volume_sampling_method,
"Volume Sampling Method",
volume_sampling_method_enum,
- VOLUME_SAMPLING_DISTANCE);
+ VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
static NodeEnum volume_interpolation_method_enum;
volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR);
@@ -415,7 +415,7 @@ ShaderManager::~ShaderManager()
{
}
-ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem)
+ShaderManager *ShaderManager::create(int shadingsystem)
{
ShaderManager *manager;
@@ -431,8 +431,6 @@ ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem)
manager = new SVMShaderManager();
}
- add_default(scene);
-
return manager;
}
@@ -471,8 +469,12 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth)
return id;
}
-void ShaderManager::device_update_shaders_used(Scene *scene)
+void ShaderManager::update_shaders_used(Scene *scene)
{
+ if (!need_update) {
+ return;
+ }
+
/* figure out which shaders are in use, so SVM/OSL can skip compiling them
* for speed and avoid loading image textures into memory */
uint id = 0;
@@ -623,9 +625,27 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = new Shader();
shader->name = "default_surface";
- shader->graph = graph;
+ shader->set_graph(graph);
scene->shaders.push_back(shader);
scene->default_surface = shader;
+ shader->tag_update(scene);
+ }
+
+ /* default volume */
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ PrincipledVolumeNode *principled = new PrincipledVolumeNode();
+ graph->add(principled);
+
+ graph->connect(principled->output("Volume"), graph->output()->input("Volume"));
+
+ Shader *shader = new Shader();
+ shader->name = "default_volume";
+ shader->set_graph(graph);
+ scene->shaders.push_back(shader);
+ scene->default_volume = shader;
+ shader->tag_update(scene);
}
/* default light */
@@ -641,9 +661,10 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = new Shader();
shader->name = "default_light";
- shader->graph = graph;
+ shader->set_graph(graph);
scene->shaders.push_back(shader);
scene->default_light = shader;
+ shader->tag_update(scene);
}
/* default background */
@@ -652,9 +673,10 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = new Shader();
shader->name = "default_background";
- shader->graph = graph;
+ shader->set_graph(graph);
scene->shaders.push_back(shader);
scene->default_background = shader;
+ shader->tag_update(scene);
}
/* default empty */
@@ -663,9 +685,10 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = new Shader();
shader->name = "default_empty";
- shader->graph = graph;
+ shader->set_graph(graph);
scene->shaders.push_back(shader);
scene->default_empty = shader;
+ shader->tag_update(scene);
}
}
@@ -704,6 +727,10 @@ void ShaderManager::get_requested_features(Scene *scene,
requested_features->nodes_features = 0;
for (int i = 0; i < scene->shaders.size(); i++) {
Shader *shader = scene->shaders[i];
+ if (!shader->used) {
+ continue;
+ }
+
/* Gather requested features from all the nodes from the graph nodes. */
get_requested_graph_features(shader->graph, requested_features);
ShaderNode *output_node = shader->graph->output();
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index c6f40bb7833..5a5b42de994 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -163,7 +163,7 @@ class ShaderManager {
public:
bool need_update;
- static ShaderManager *create(Scene *scene, int shadingsystem);
+ static ShaderManager *create(int shadingsystem);
virtual ~ShaderManager();
virtual void reset(Scene *scene) = 0;
@@ -180,7 +180,6 @@ class ShaderManager {
Progress &progress) = 0;
virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0;
- void device_update_shaders_used(Scene *scene);
void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
void device_free_common(Device *device, DeviceScene *dscene, Scene *scene);
@@ -196,6 +195,7 @@ class ShaderManager {
static void add_default(Scene *scene);
/* Selective nodes compilation. */
+ void update_shaders_used(Scene *scene);
void get_requested_features(Scene *scene, DeviceRequestedFeatures *requested_features);
static void free_memory();
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 7c33f6c04ae..2946614a3b7 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -85,9 +85,6 @@ void SVMShaderManager::device_update(Device *device,
/* test if we need to update */
device_free(device, dscene, scene);
- /* determine which shaders are in use */
- device_update_shaders_used(scene);
-
/* Build all shaders. */
TaskPool task_pool;
vector<array<int4>> shader_svm_nodes(num_shaders);
diff --git a/intern/cycles/util/util_profiling.cpp b/intern/cycles/util/util_profiling.cpp
index bbefbadd0fe..dc5bc35c48d 100644
--- a/intern/cycles/util/util_profiling.cpp
+++ b/intern/cycles/util/util_profiling.cpp
@@ -15,6 +15,7 @@
*/
#include "util/util_algorithm.h"
+#include "util/util_foreach.h"
#include "util/util_profiling.h"
#include "util/util_set.h"
diff --git a/intern/cycles/util/util_profiling.h b/intern/cycles/util/util_profiling.h
index f5f500239f2..ceec08ed894 100644
--- a/intern/cycles/util/util_profiling.h
+++ b/intern/cycles/util/util_profiling.h
@@ -19,7 +19,6 @@
#include <atomic>
-#include "util/util_foreach.h"
#include "util/util_map.h"
#include "util/util_thread.h"
#include "util/util_vector.h"
diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h
index d43852480d1..d0672886cba 100644
--- a/intern/cycles/util/util_texture.h
+++ b/intern/cycles/util/util_texture.h
@@ -91,12 +91,15 @@ typedef enum ExtensionType {
typedef struct TextureInfo {
/* Pointer, offset or texture depending on device. */
uint64_t data;
+ /* Data Type */
+ uint data_type;
/* Buffer number for OpenCL. */
uint cl_buffer;
/* Interpolation and extension type. */
uint interpolation, extension;
/* Dimensions. */
uint width, height, depth;
+ uint pad[3];
} TextureInfo;
CCL_NAMESPACE_END
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 5bf40ba33d0..d03b9343eab 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1052,7 +1052,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
/* Unlike on Linux, not all keys can send repeat events. E.g. modifier keys don't. */
if (keyDown) {
if (system->m_keycode_last_repeat_key == vk) {
- is_repeat = true;
+ is_repeat = true;
}
system->m_keycode_last_repeat_key = vk;
}
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index f97397715bf..2d97489f657 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -1,16 +1,36 @@
+# see "cmake --help-policy CMP0003"
+# So library linking is more sane
cmake_policy(SET CMP0003 NEW)
+
+# So BUILDINFO and BLENDERPATH strings are automatically quoted
cmake_policy(SET CMP0005 NEW)
-cmake_minimum_required(VERSION 2.8)
+# So syntax problems are errors
+cmake_policy(SET CMP0010 NEW)
+
+# Input directories must have CMakeLists.txt
+cmake_policy(SET CMP0014 NEW)
+
+cmake_minimum_required(VERSION 3.5)
+
+project(GhostMultiTest)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../..//build_files/cmake/Modules")
set(WITH_GUARDEDALLOC ON)
+add_executable(datatoc
+ "${CMAKE_SOURCE_DIR}/../../../source/blender/datatoc/datatoc.c")
+
+# Fake the current source dir for includes.
+set(_CMAKE_CURRENT_SOURCE_DIR_INIT "${CMAKE_CURRENT_SOURCE_DIR}")
+
# -----------------------------------------------------------------------------
# Macros
+# For data_to_c macro.
+# include(../../../build_files/cmake/macros.cmake)
# stub macro, does nothing
macro(blender_add_lib
@@ -18,6 +38,7 @@ macro(blender_add_lib
sources
includes
includes_sys
+ library_deps # ignored.
)
endmacro()
@@ -28,10 +49,15 @@ macro(suffix_relpaths
set(${new_files})
foreach(_file ${files})
- if(IS_ABSOLUTE _file)
+ if(IS_ABSOLUTE "${_file}")
list(APPEND ${new_files} ${_file})
else()
- list(APPEND ${new_files} "${prefix}${_file}")
+ set(_file_to "${prefix}${_file}")
+ list(APPEND ${new_files} ${_file_to})
+ get_source_file_property(_is_generated ${_file} GENERATED)
+ set_source_files_properties(${_file_to} PROPERTIES GENERATED ${_is_generated})
+ unset(_file_to)
+ unset(_is_generated)
endif()
endforeach()
unset(_file)
@@ -48,11 +74,39 @@ macro(data_to_c
add_custom_command(
OUTPUT ${file_to}
COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
- COMMAND ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/datatoc ${file_from} ${file_to}
+ COMMAND "$<TARGET_FILE:datatoc>" ${file_from} ${file_to}
DEPENDS ${file_from} datatoc)
unset(_file_to_path)
endmacro()
+# same as above but generates the var name and output automatic.
+function(data_to_c_simple
+ file_from
+ list_to_add
+ )
+
+ # remove ../'s
+ get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH)
+ get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c REALPATH)
+
+
+ list(APPEND ${list_to_add} ${_file_to})
+ source_group(Generated FILES ${_file_to})
+ list(APPEND ${list_to_add} ${file_from})
+ set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
+
+ get_filename_component(_file_to_path ${_file_to} PATH)
+
+ message(OUTPUT " ${_file_to}")
+ add_custom_command(
+ OUTPUT ${_file_to}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
+ COMMAND "$<TARGET_FILE:datatoc>" ${_file_from} ${_file_to}
+ DEPENDS ${_file_from} datatoc)
+
+ set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
+endfunction()
+
# -----------------------------------------------------------------------------
# Defines
@@ -96,6 +150,13 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../string/")
include_directories(${INC_NEW})
add_library(string_lib ${SRC_NEW})
+# numaapi (for 'bli_lib')
+include(${CMAKE_SOURCE_DIR}/../../numaapi/CMakeLists.txt)
+suffix_relpaths(INC_NEW "${INC}" "../../numaapi/")
+suffix_relpaths(SRC_NEW "${SRC}" "../../numaapi/")
+include_directories(${INC_NEW})
+add_library(numaapi_lib ${SRC_NEW})
+
# guardedalloc
include(${CMAKE_SOURCE_DIR}/../../guardedalloc/CMakeLists.txt)
suffix_relpaths(INC_NEW "${INC}" "../../guardedalloc/")
@@ -103,6 +164,25 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../guardedalloc/")
include_directories(${INC_NEW})
add_library(guardedalloc_lib ${SRC_NEW})
+# gpu (used by blenfont)
+add_definitions(-DGPU_STANDALONE)
+set(CMAKE_CURRENT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../../source/blender/gpu")
+include(${CMAKE_SOURCE_DIR}/../../../source/blender/gpu/CMakeLists.txt)
+suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/gpu/")
+suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/gpu/")
+include_directories(${INC_NEW})
+add_library(gpu_lib ${SRC_NEW})
+set(CMAKE_CURRENT_SOURCE_DIR "${_CMAKE_CURRENT_SOURCE_DIR_INIT}")
+
+# imbuf (used by )
+# set(CMAKE_CURRENT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../../source/blender/imbuf")
+# include(${CMAKE_SOURCE_DIR}/../../../source/blender/imbuf/CMakeLists.txt)
+# suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/imbuf/")
+# suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/imbuf/")
+# include_directories(${INC_NEW})
+# add_library(imbuf_lib ${SRC_NEW})
+# set(CMAKE_CURRENT_SOURCE_DIR "${_CMAKE_CURRENT_SOURCE_DIR_INIT}")
+
# blenfont
include(${CMAKE_SOURCE_DIR}/../../../source/blender/blenfont/CMakeLists.txt)
suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/blenfont/")
@@ -128,6 +208,10 @@ add_library(glewmx_lib ${SRC_NEW})
include_directories(
"../../../source/blender/blenlib"
)
+
+# Needed for math_matrix.c to avoid eigen_capi.h dep.
+add_definitions(-DMATH_STANDALONE)
+
add_library(bli_lib
"../../../source/blender/blenlib/intern/fileops.c"
"../../../source/blender/blenlib/intern/gsqueue.c"
@@ -136,15 +220,23 @@ add_library(bli_lib
"../../../source/blender/blenlib/intern/string_utf8.c"
"../../../source/blender/blenlib/intern/listbase.c"
"../../../source/blender/blenlib/intern/math_color.c"
+ "../../../source/blender/blenlib/intern/math_geom.c"
+ "../../../source/blender/blenlib/intern/math_matrix.c"
+ "../../../source/blender/blenlib/intern/math_rotation.c"
+ "../../../source/blender/blenlib/intern/math_vector.c"
"../../../source/blender/blenlib/intern/storage.c"
"../../../source/blender/blenlib/intern/task.c"
"../../../source/blender/blenlib/intern/threads.c"
"../../../source/blender/blenlib/intern/time.c"
"../../../source/blender/blenlib/intern/path_util.c"
"../../../source/blender/blenlib/intern/BLI_dynstr.c"
+ "../../../source/blender/blenlib/intern/BLI_ghash.c"
+ "../../../source/blender/blenlib/intern/BLI_ghash_utils.c"
"../../../source/blender/blenlib/intern/BLI_linklist.c"
"../../../source/blender/blenlib/intern/BLI_memarena.c"
"../../../source/blender/blenlib/intern/BLI_mempool.c"
+ "../../../source/blender/blenlib/intern/hash_mm2a.c"
+ "../../../source/blender/blenlib/intern/string_utils.c"
"../../../source/blender/blenlib/intern/system.c"
)
@@ -190,10 +282,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS}")
# -----------------------------------------------------------------------------
# Executables
-# DataToC
-add_executable(datatoc
- ${CMAKE_SOURCE_DIR}/../../../source/blender/datatoc/datatoc.c)
-
# Gears (C)
add_executable(gears_c
${CMAKE_SOURCE_DIR}/gears/GHOST_C-Test.c)
@@ -224,8 +312,11 @@ target_link_libraries(gears_cpp
# MultiTest (C)
set(data_to_c_files)
-data_to_c(${CMAKE_SOURCE_DIR}/../../../release/datafiles/bfont.ttf
- ${CMAKE_CURRENT_BINARY_DIR}/bfont.ttf.c data_to_c_files)
+data_to_c(
+ ${CMAKE_SOURCE_DIR}/../../../release/datafiles/bfont.ttf
+ ${CMAKE_CURRENT_BINARY_DIR}/bfont.ttf.c
+ data_to_c_files
+)
add_executable(multitest_c
${CMAKE_SOURCE_DIR}/multitest/Basic.c
@@ -240,16 +331,20 @@ add_executable(multitest_c
target_link_libraries(multitest_c
- blenfont_lib
- bli_lib
- ghost_lib
- glewmx_lib
- string_lib
- guardedalloc_lib
- wcwidth_lib
- ${OPENGL_gl_LIBRARY}
- ${FREETYPE_LIBRARY}
- ${ZLIB_LIBRARIES}
- ${CMAKE_DL_LIBS}
- ${PLATFORM_LINKLIBS}
- )
+ blenfont_lib
+ bli_lib
+ gpu_lib
+ # imbuf_lib
+ ghost_lib
+ bli_lib # again...
+ glewmx_lib
+ string_lib
+ numaapi_lib
+ guardedalloc_lib
+ wcwidth_lib
+ ${OPENGL_gl_LIBRARY}
+ ${FREETYPE_LIBRARY}
+ ${ZLIB_LIBRARIES}
+ ${CMAKE_DL_LIBS}
+ ${PLATFORM_LINKLIBS}
+)
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index 21d706966c1..374c7170dc6 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -16,7 +16,18 @@
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*/
-#define FALSE 0
+
+/* Developers Note:
+ *
+ * This test currently only creates windows and draws a 'dot' under the cursor on LMB,
+ * quits when Q is pressed.
+ *
+ * More work is needed for logging drawing to work properly.
+ *
+ * - Use GPU_matrix API.
+ * - Replace old OpenGL calls to glColor, etc with 'imm' API.
+ * - Investigate BLF font flushing (UI_widgetbase_draw_cache_flush) which is currently disabled.
+ */
#ifdef _MSC_VER
# pragma warning(disable : 4244 4305)
@@ -27,22 +38,14 @@
#include <stdio.h>
#include <math.h>
+#include <GL/glew.h>
#include "GL.h"
#include "MEM_guardedalloc.h"
#include "GHOST_C-api.h"
-#ifdef USE_BMF
-# include "BMF_Api.h"
-#else
-# include "BLF_api.h"
-extern int datatoc_bfont_ttf_size;
-extern char datatoc_bfont_ttf[];
-
-/* cheat */
-char U[1024] = {0};
-#endif
+#include "BLF_api.h"
#include "Util.h"
#include "Basic.h"
@@ -51,7 +54,13 @@ char U[1024] = {0};
#include "WindowData.h"
-/***/
+/* GPU API. */
+#include "GPU_immediate.h"
+#include "GPU_context.h"
+#include "GPU_init_exit.h"
+
+extern int datatoc_bfont_ttf_size;
+extern char datatoc_bfont_ttf[];
typedef struct _LoggerWindow LoggerWindow;
typedef struct _MultiTestApp MultiTestApp;
@@ -128,6 +137,7 @@ typedef struct {
MultiTestApp *app;
GHOST_WindowHandle win;
+ GPUContext *gpu_context;
int size[2];
@@ -144,6 +154,7 @@ static void mainwindow_log(MainWindow *mw, char *str)
static void mainwindow_do_draw(MainWindow *mw)
{
GHOST_ActivateWindowDrawingContext(mw->win);
+ GPU_context_active_set(mw->gpu_context);
if (mw->lmbut[0]) {
glClearColor(0.5, 0.5, 0.5, 1);
@@ -164,6 +175,7 @@ static void mainwindow_do_reshape(MainWindow *mw)
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(mw->win);
GHOST_ActivateWindowDrawingContext(mw->win);
+ GPU_context_active_set(mw->gpu_context);
mw->size[0] = GHOST_GetWidthRectangle(bounds);
mw->size[1] = GHOST_GetHeightRectangle(bounds);
@@ -317,6 +329,11 @@ MainWindow *mainwindow_new(MultiTestApp *app)
if (win) {
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
+
+ GLuint default_fb = GHOST_GetDefaultOpenGLFramebuffer(win);
+ mw->gpu_context = GPU_context_create(default_fb);
+ GPU_init();
+
mw->app = app;
mw->win = win;
@@ -348,13 +365,9 @@ struct _LoggerWindow {
MultiTestApp *app;
GHOST_WindowHandle win;
+ GPUContext *gpu_context;
-#ifdef USE_BMF
- BMF_Font *font;
-#else
int font;
-#endif
- int fonttexid;
int fontheight;
int size[2];
@@ -411,6 +424,7 @@ static void loggerwindow_do_reshape(LoggerWindow *lw)
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win);
GHOST_ActivateWindowDrawingContext(lw->win);
+ GPU_context_active_set(lw->gpu_context);
lw->size[0] = GHOST_GetWidthRectangle(bounds);
lw->size[1] = GHOST_GetHeightRectangle(bounds);
@@ -425,6 +439,8 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
int sb_rect[2][2], sb_thumb[2][2];
GHOST_ActivateWindowDrawingContext(lw->win);
+ GPU_context_active_set(lw->gpu_context);
+ immActivate();
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
@@ -449,13 +465,6 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1);
ndisplines = min_i(lw->ndisplines, lw->nloglines - startline);
- if (lw->fonttexid != -1) {
- glBindTexture(GL_TEXTURE_2D, lw->fonttexid);
-
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glEnable(GL_TEXTURE_2D);
- }
glColor3f(0, 0, 0);
for (i = 0; i < ndisplines; i++) {
/* stored in reverse order */
@@ -463,28 +472,13 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
int x_pos = lw->textarea[0][0] + 4;
int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight;
-#ifdef USE_BMF
- if (lw->fonttexid == -1) {
- glRasterPos2i(x_pos, y_pos);
- BMF_DrawString(lw->font, line);
- }
- else {
- BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0);
- }
-#else
BLF_position(lw->font, x_pos, y_pos, 0.0);
BLF_draw(lw->font, line, 256); // XXX
-#endif
}
-#ifdef USE_BMF
- if (lw->fonttexid != -1) {
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
- }
-#endif
-
GHOST_SwapWindowBuffers(lw->win);
+
+ immDeactivate();
}
static void loggerwindow_do_move(LoggerWindow *lw, int x, int y)
@@ -592,21 +586,18 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
if (win) {
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
+
+ GLuint default_fb = GHOST_GetDefaultOpenGLFramebuffer(win);
+ lw->gpu_context = GPU_context_create(default_fb);
+ GPU_init();
+
int bbox[2][2];
lw->app = app;
lw->win = win;
-#ifdef USE_BMF
- lw->font = BMF_GetFont(BMF_kScreen12);
- lw->fonttexid = BMF_GetFontTexture(lw->font);
-
- BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]);
- lw->fontheight = rect_height(bbox);
-#else
lw->font = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
BLF_size(lw->font, 11, 72);
lw->fontheight = BLF_height(lw->font, "A_", 2);
-#endif
lw->nloglines = lw->logsize = 0;
lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines");
@@ -659,6 +650,7 @@ typedef struct {
MultiTestApp *app;
GHOST_WindowHandle win;
+ GPUContext *gpu_context;
int size[2];
} ExtraWindow;
@@ -666,6 +658,7 @@ typedef struct {
static void extrawindow_do_draw(ExtraWindow *ew)
{
GHOST_ActivateWindowDrawingContext(ew->win);
+ GPU_context_active_set(ew->gpu_context);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
@@ -681,6 +674,7 @@ static void extrawindow_do_reshape(ExtraWindow *ew)
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(ew->win);
GHOST_ActivateWindowDrawingContext(ew->win);
+ GPU_context_active_set(ew->gpu_context);
ew->size[0] = GHOST_GetWidthRectangle(bounds);
ew->size[1] = GHOST_GetHeightRectangle(bounds);
@@ -793,6 +787,11 @@ ExtraWindow *extrawindow_new(MultiTestApp *app)
if (win) {
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
+
+ GLuint default_fb = GHOST_GetDefaultOpenGLFramebuffer(win);
+ ew->gpu_context = GPU_context_create(default_fb);
+ GPU_init();
+
ew->app = app;
ew->win = win;
@@ -932,6 +931,9 @@ void multitestapp_run(MultiTestApp *app)
void multitestapp_free(MultiTestApp *app)
{
+ BLF_exit();
+ GPU_exit();
+
mainwindow_free(app->main);
loggerwindow_free(app->logger);
GHOST_DisposeSystem(app->sys);
@@ -944,9 +946,7 @@ int main(int argc, char **argv)
{
MultiTestApp *app;
-#ifndef USE_BMF
BLF_init();
-#endif
app = multitestapp_new();
diff --git a/intern/ghost/test/multitest/stubs.c b/intern/ghost/test/multitest/stubs.c
index f0b076eeba0..151cdc71777 100644
--- a/intern/ghost/test/multitest/stubs.c
+++ b/intern/ghost/test/multitest/stubs.c
@@ -23,6 +23,7 @@
#include "IMB_imbuf.h"
struct ImBuf;
+struct ColorSpace;
void IMB_freeImBuf(struct ImBuf *UNUSED(ibuf))
{
@@ -31,3 +32,31 @@ void IMB_colormanagement_display_to_scene_linear_v3(float UNUSED(pixel[3]),
struct ColorManagedDisplay *UNUSED(display))
{
}
+
+bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace)
+{
+ return false;
+}
+
+bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace)
+{
+ return false;
+}
+
+void BKE_material_defaults_free_gpu(void)
+{
+}
+
+/* Variables. */
+int G;
+
+/* Functions which aren't called. */
+void *BKE_image_free_buffers = NULL;
+void *BKE_image_get_tile = NULL;
+void *BKE_image_get_tile_from_iuser = NULL;
+void *BKE_tempdir_session = NULL;
+void *DRW_deferred_shader_remove = NULL;
+void *datatoc_common_view_lib_glsl = NULL;
+void *ntreeFreeLocalTree = NULL;
+void *ntreeGPUMaterialNodes = NULL;
+void *ntreeLocalize = NULL;
diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h
index 5ed94d99edd..48d42504994 100644
--- a/intern/mantaflow/extern/manta_fluid_API.h
+++ b/intern/mantaflow/extern/manta_fluid_API.h
@@ -132,14 +132,14 @@ void manta_smoke_turbulence_export(struct MANTA *smoke,
float **tcw2);
void manta_smoke_get_rgba(struct MANTA *smoke, float *data, int sequential);
void manta_smoke_turbulence_get_rgba(struct MANTA *smoke, float *data, int sequential);
-void manta_smoke_get_rgba_from_density(struct MANTA *smoke,
- float color[3],
- float *data,
- int sequential);
-void manta_smoke_turbulence_get_rgba_from_density(struct MANTA *smoke,
- float color[3],
- float *data,
- int sequential);
+void manta_smoke_get_rgba_fixed_color(struct MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential);
+void manta_smoke_turbulence_get_rgba_fixed_color(struct MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential);
void manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *mmd);
void manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *mmd);
void manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *mmd);
diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp
index 7e3e4520485..89c69bebc51 100644
--- a/intern/mantaflow/intern/manta_fluid_API.cpp
+++ b/intern/mantaflow/intern/manta_fluid_API.cpp
@@ -455,14 +455,9 @@ static void get_rgba(
for (i = 0; i < total_cells; i++) {
float alpha = a[i];
- if (alpha) {
- data[i * m] = r[i];
- data[i * m + i_g] = g[i];
- data[i * m + i_b] = b[i];
- }
- else {
- data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
- }
+ data[i * m] = r[i] * alpha;
+ data[i * m + i_g] = g[i] * alpha;
+ data[i * m + i_b] = b[i] * alpha;
data[i * m + i_a] = alpha;
}
}
@@ -489,8 +484,7 @@ void manta_smoke_turbulence_get_rgba(MANTA *smoke, float *data, int sequential)
sequential);
}
-static void get_rgba_from_density(
- float color[3], float *a, int total_cells, float *data, int sequential)
+static void get_rgba_fixed_color(float color[3], int total_cells, float *data, int sequential)
{
int i;
int m = 4, i_g = 1, i_b = 2, i_a = 3;
@@ -502,31 +496,24 @@ static void get_rgba_from_density(
}
for (i = 0; i < total_cells; i++) {
- float alpha = a[i];
- if (alpha) {
- data[i * m] = color[0] * alpha;
- data[i * m + i_g] = color[1] * alpha;
- data[i * m + i_b] = color[2] * alpha;
- }
- else {
- data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
- }
- data[i * m + i_a] = alpha;
+ data[i * m] = color[0];
+ data[i * m + i_g] = color[1];
+ data[i * m + i_b] = color[2];
+ data[i * m + i_a] = 1.0f;
}
}
-void manta_smoke_get_rgba_from_density(MANTA *smoke, float color[3], float *data, int sequential)
+void manta_smoke_get_rgba_fixed_color(MANTA *smoke, float color[3], float *data, int sequential)
{
- get_rgba_from_density(color, smoke->getDensity(), smoke->getTotalCells(), data, sequential);
+ get_rgba_fixed_color(color, smoke->getTotalCells(), data, sequential);
}
-void manta_smoke_turbulence_get_rgba_from_density(MANTA *smoke,
- float color[3],
- float *data,
- int sequential)
+void manta_smoke_turbulence_get_rgba_fixed_color(MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential)
{
- get_rgba_from_density(
- color, smoke->getDensityHigh(), smoke->getTotalCellsHigh(), data, sequential);
+ get_rgba_fixed_color(color, smoke->getTotalCellsHigh(), data, sequential);
}
void manta_smoke_ensure_heat(MANTA *smoke, struct FluidModifierData *mmd)
diff --git a/release/scripts/modules/bl_ui_utils/bug_report_url.py b/release/scripts/modules/bl_ui_utils/bug_report_url.py
index 008eafc2c46..2adee70bc86 100644
--- a/release/scripts/modules/bl_ui_utils/bug_report_url.py
+++ b/release/scripts/modules/bl_ui_utils/bug_report_url.py
@@ -57,7 +57,7 @@ def url_prefill_from_blender(addon_info=None):
)
)
fh.write(
- "Worked: (optional)\n"
+ "Worked: (newest version of Blender that worked as expected)\n"
)
if addon_info:
fh.write(
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 3cefbee8c17..99508bf8fab 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -725,6 +725,19 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "size")
col.prop(md, "spatial_size")
+ layout.separator()
+
+ layout.prop(md, "spectrum")
+
+ if md.spectrum in {'TEXEL_MARSEN_ARSLOE', 'JONSWAP'}:
+ split = layout.split()
+
+ col = split.column()
+ col.prop(md, "sharpen_peak_jonswap")
+
+ col = split.column()
+ col.prop(md, "fetch_jonswap")
+
layout.label(text="Waves:")
split = layout.split()
@@ -2028,13 +2041,22 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
sub.prop(md, "frame_start", text="Start")
sub.prop(md, "frame_end", text="End")
- col = layout.column()
- col.separator()
- col.label(text="Layer:")
- row = col.row(align=True)
+ layout.label(text="Influence Filters:")
+
+ split = layout.split(factor=0.25)
+
+ col1 = split.column()
+
+ col1.label(text="Layer:")
+
+ col2 = split.column()
+
+ split = col2.split(factor=0.6)
+ row = split.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
- row = layout.row(align=True)
+
+ row = split.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 8117445e4af..76ba4dfb78e 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -252,15 +252,25 @@ class DOPESHEET_HT_editor_buttons(Header):
# Layer management
if st.mode == 'GPENCIL':
- row = layout.row(align=True)
- row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
- row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+ ob = context.active_object
+ selected = st.dopesheet.show_only_selected
+ enable_but = selected and ob is not None and ob.type == 'GPENCIL'
row = layout.row(align=True)
+ row.enabled = enable_but
row.operator("gpencil.layer_add", icon='ADD', text="")
row.operator("gpencil.layer_remove", icon='REMOVE', text="")
+ row.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
- layout.separator_spacer()
+ row = layout.row(align=True)
+ row.enabled = enable_but
+ row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
+ row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
+ row = layout.row(align=True)
+ row.enabled = enable_but
+ row.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
+ row.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
layout.separator_spacer()
@@ -270,15 +280,8 @@ class DOPESHEET_HT_editor_buttons(Header):
dopesheet_filter(layout, context)
elif st.mode == 'GPENCIL':
row = layout.row(align=True)
- row.prop(st.dopesheet, "show_gpencil_3d_only", text="Active Only")
-
- if st.dopesheet.show_gpencil_3d_only:
- row = layout.row(align=True)
- row.prop(st.dopesheet, "show_only_selected", text="")
- row.prop(st.dopesheet, "show_hidden", text="")
-
- row = layout.row(align=True)
- row.prop(st.dopesheet, "filter_text", text="")
+ row.prop(st.dopesheet, "show_only_selected", text="")
+ row.prop(st.dopesheet, "show_hidden", text="")
layout.popover(
panel="DOPESHEET_PT_filters",
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 447386b8f9d..969f9b4bd1a 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -5888,7 +5888,9 @@ class VIEW3D_PT_overlay_guides(Panel):
sub.prop(overlay, "show_cursor", text="3D Cursor")
if shading.type == 'MATERIAL':
- col.prop(overlay, "show_look_dev")
+ row = col.row()
+ row.active = shading.render_pass == 'COMBINED'
+ row.prop(overlay, "show_look_dev")
col.prop(overlay, "show_annotation", text="Annotations")
@@ -6900,7 +6902,7 @@ class VIEW3D_PT_gpencil_sculpt_context_menu(Panel):
def draw(self, context):
ts = context.tool_settings
- settings = ts.gpencil_paint
+ settings = ts.gpencil_sculpt_paint
brush = settings.brush
layout = self.layout
@@ -6920,7 +6922,7 @@ class VIEW3D_PT_gpencil_weight_context_menu(Panel):
def draw(self, context):
ts = context.tool_settings
- settings = ts.gpencil_paint
+ settings = ts.gpencil_weight_paint
brush = settings.brush
layout = self.layout
diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt
index 6c786dfcc7a..0b1ce5149da 100644
--- a/source/blender/blendthumb/CMakeLists.txt
+++ b/source/blender/blendthumb/CMakeLists.txt
@@ -28,6 +28,8 @@ set(SRC
src/Dll.cpp
)
+set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /nodefaultlib:MSVCRT.lib")
+
add_library(BlendThumb SHARED ${SRC})
target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
diff --git a/source/blender/blendthumb/src/Dll.cpp b/source/blender/blendthumb/src/Dll.cpp
index 08b3d253be8..fec792ebfeb 100644
--- a/source/blender/blendthumb/src/Dll.cpp
+++ b/source/blender/blendthumb/src/Dll.cpp
@@ -159,7 +159,8 @@ struct REGISTRY_ENTRY {
PCWSTR pszKeyName;
PCWSTR pszValueName;
DWORD dwValueType;
- PCWSTR pszData;
+ PCWSTR pszData; // These two fields could/should have been a union, but C++
+ DWORD dwData; // only lets you initalize the first field in a union.
};
// Creates a registry key (if needed) and sets the default value of the key
@@ -187,7 +188,7 @@ HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
break;
case REG_DWORD:
size = sizeof(DWORD);
- data = (DWORD)pRegistryEntry->pszData;
+ data = pRegistryEntry->dwData;
lpData = (BYTE *)&data;
break;
default:
@@ -235,6 +236,7 @@ STDAPI DllRegisterServer()
L"Software\\Classes\\.blend\\",
L"Treatment",
REG_DWORD,
+ 0,
0}, // doesn't appear to do anything...
{HKEY_CURRENT_USER,
L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 725c4c0712d..5664b9ae0a0 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -47,11 +47,9 @@
#include "IMB_colormanagement.h"
-#ifndef BLF_STANDALONE
-# include "GPU_shader.h"
-# include "GPU_matrix.h"
-# include "GPU_immediate.h"
-#endif
+#include "GPU_shader.h"
+#include "GPU_matrix.h"
+#include "GPU_immediate.h"
#include "blf_internal_types.h"
#include "blf_internal.h"
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index f0afe184233..0f75d9b5ab0 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -230,8 +230,10 @@ void blf_batch_draw(void)
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+#ifndef BLF_STANDALONE
/* We need to flush widget base first to ensure correct ordering. */
UI_widgetbase_draw_cache_flush();
+#endif
GPUTexture *texture = blf_batch_cache_texture_load();
GPU_texture_bind(texture, 0);
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 3ab6814c531..3270eec58f9 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -46,10 +46,8 @@
#include "BLF_api.h"
-#ifndef BLF_STANDALONE
-# include "GPU_immediate.h"
-# include "GPU_extensions.h"
-#endif
+#include "GPU_immediate.h"
+#include "GPU_extensions.h"
#include "blf_internal_types.h"
#include "blf_internal.h"
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index b12803b1603..f3e15529f77 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -55,14 +55,14 @@ enum {
IDWALK_CB_INDIRECT_USAGE = (1 << 2),
/**
- * That ID is used as mere sub-data by its owner
- * (only case currently: those f***ing nodetrees in materials etc.).
- * This means callback shall not *do* anything,
- * only use this as informative data if it needs it.
+ * That ID is used as mere sub-data by its owner (only case currently: those root nodetrees in
+ * materials etc., and the Scene's master collections).
+ * This means callback shall not *do* anything, only use this as informative data if it needs it.
*/
- IDWALK_CB_PRIVATE = (1 << 3),
+ IDWALK_CB_EMBEDDED = (1 << 3),
- /** That ID is not really used by its owner, it's just an internal hint/helper.
+ /**
+ * That ID is not really used by its owner, it's just an internal hint/helper.
* This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from.
* How to handle that kind of cases totally depends on what caller code is doing... */
IDWALK_CB_LOOPBACK = (1 << 4),
@@ -89,11 +89,15 @@ enum {
typedef struct LibraryIDLinkCallbackData {
void *user_data;
- /* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a
- * private one. */
+ /**
+ * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an
+ * embedded one.
+ */
struct ID *id_owner;
- /* ID from which the current ID pointer is being processed. It may be a 'private' ID like master
- * collection or root node tree. */
+ /**
+ * ID from which the current ID pointer is being processed. It may be an embedded ID like master
+ * collection or root node tree.
+ */
struct ID *id_self;
struct ID **id_pointer;
int cb_flag;
@@ -112,6 +116,8 @@ enum {
IDWALK_READONLY = (1 << 0),
IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
IDWALK_INCLUDE_UI = (1 << 2), /* Include UI pointers (from WM and screens editors). */
+ /** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */
+ IDWALK_IGNORE_EMBEDDED_ID = (1 << 3),
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
};
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 6f1f68e1ef2..ed36d3892ac 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -391,9 +391,6 @@ struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
-/* node->id user count */
-void ntreeUserIncrefID(struct bNodeTree *ntree);
-void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id);
struct bNodeTree *ntreeFromID(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 3ba6486e6c5..d3ac825039d 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -84,6 +84,9 @@ void BKE_ocean_init(struct Ocean *o,
float alignment,
float depth,
float time,
+ int spectrum,
+ float fetch_jonswap,
+ float sharpen_peak_jonswap,
short do_height_field,
short do_chop,
short do_normals,
@@ -122,6 +125,11 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in
void BKE_ocean_free_cache(struct OceanCache *och);
void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
+/* ocean_spectrum.c */
+float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, const float kx, const float kz);
+float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float kx, const float kz);
+float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, const float kx, const float kz);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 90e5459b599..8018178fcee 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -215,6 +215,7 @@ int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
void BKE_scene_allocate_depsgraph_hash(struct Scene *scene);
void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_depsgraph_hash(struct Scene *scene);
+void BKE_scene_free_view_layer_depsgraph(struct Scene *scene, struct ViewLayer *view_layer);
struct Depsgraph *BKE_scene_get_depsgraph(struct Main *bmain,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index a6ed1274f19..2231cc36861 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -190,6 +190,8 @@ typedef struct ARegionType {
/* return without drawing.
* lock is set by region definition, and copied to do_lock by render. can become flag. */
short do_lock, lock;
+ /** Don't handle gizmos events behind #uiBlock's with #UI_BLOCK_CLIP_EVENTS flag set. */
+ bool clip_gizmo_events_by_ui;
/* call cursor function on each move event */
short event_cursor;
} ARegionType;
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 5edde7441de..83129bed5f7 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -170,7 +170,7 @@ void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
float r_point_co[3]);
/*
- * NULL initializers to local data
+ * NULL initializes to local data
*/
#define NULL_ShrinkwrapCalcData \
{ \
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 22123f05cab..135168a6de4 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -178,6 +178,7 @@ set(SRC
intern/object_facemap.c
intern/object_update.c
intern/ocean.c
+ intern/ocean_spectrum.c
intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 0580ad55e43..c23cb9231d7 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1008,12 +1008,12 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
* - These properties allow users to hand-animate the
* bone curve/shape, without having to resort to using
* extra bones
- * - The "bone" level offsets are for defining the restpose
+ * - The "bone" level offsets are for defining the rest-pose
* shape of the bone (e.g. for curved eyebrows for example).
* -> In the viewport, it's needed to define what the rest pose
* looks like
* -> For "rest == 0", we also still need to have it present
- * so that we can "cancel out" this restpose when it comes
+ * so that we can "cancel out" this rest-pose when it comes
* time to deform some geometry, it won't cause double transforms.
* - The "pchan" level offsets are the ones that animators actually
* end up animating
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 74c492573b1..67e9feac0cf 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -443,7 +443,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
- brush->gpencil_settings->hardeness = 0.211f;
+ brush->gpencil_settings->hardeness = 0.9f;
copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f);
brush->gpencil_tool = GPAINT_TOOL_DRAW;
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 5c4636db728..d9954323594 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -89,7 +89,7 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
const Collection *collection_src = (const Collection *)id_src;
BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) ==
- ((collection_src->id.flag & LIB_PRIVATE_DATA) != 0));
+ ((collection_src->id.flag & LIB_EMBEDDED_DATA) != 0));
/* Do not copy collection's preview (same behavior as for objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
@@ -366,7 +366,7 @@ Collection *BKE_collection_duplicate(Main *bmain,
const bool do_obdata)
{
/* It's not allowed to copy the master collection. */
- BLI_assert((collection->id.flag & LIB_PRIVATE_DATA) == 0);
+ BLI_assert((collection->id.flag & LIB_EMBEDDED_DATA) == 0);
BLI_assert((collection->flag & COLLECTION_IS_MASTER) == 0);
if (collection->flag & COLLECTION_IS_MASTER) {
return NULL;
@@ -514,7 +514,7 @@ Collection *BKE_collection_master_add()
/* Not an actual datablock, but owned by scene. */
Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
STRNCPY(master_collection->id.name, "GRMaster Collection");
- master_collection->id.flag |= LIB_PRIVATE_DATA;
+ master_collection->id.flag |= LIB_EMBEDDED_DATA;
master_collection->flag |= COLLECTION_IS_MASTER;
return master_collection;
}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 03c9cc7d151..9919a0d7385 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -2741,7 +2741,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
}
/* Optimization: Static liquid flow objects don't need emission computation after first
* frame.
- * TODO (sebbas): Also do not use static mode if inital velocities are enabled. */
+ * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
if (mfs->type == FLUID_FLOW_TYPE_LIQUID && is_static && !is_first_frame && !use_velocity) {
continue;
}
@@ -2961,7 +2961,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
if (is_liquid && !is_first_frame) {
/* Skip static liquid objects that are not on the first frame.
- * TODO (sebbas): Also do not use static mode if inital velocities are enabled. */
+ * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
if (is_static && !use_velocity) {
continue;
}
@@ -3222,7 +3222,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj
float cell_size_scaled[3];
/* Assign material + flags to new mesh.
- * If there are no faces in original mesj, keep materials and flags unchanged. */
+ * If there are no faces in original mesh, keep materials and flags unchanged. */
MPoly *mpoly;
MPoly mp_example = {0};
mpoly = orgmesh->mpoly;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 7a697f19b8b..4220408749a 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -3023,7 +3023,7 @@ Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
/* happens on reload, imagewindow cannot be image user when hidden*/
if (ima->id.us == 0) {
- id_us_plus(&ima->id);
+ id_us_ensure_real(&ima->id);
}
return ima;
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 919f249eea6..c342185d0b8 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -340,7 +340,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
int const cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_PRIVATE) {
+ if (cb_flag & IDWALK_CB_EMBEDDED) {
return IDWALK_RET_NOP;
}
@@ -1148,7 +1148,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
ID *new_id = *r_newid;
int flag = orig_flag;
- const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0;
+ const bool is_private_id_data = (id->flag & LIB_EMBEDDED_DATA) != 0;
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
@@ -1167,7 +1167,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
}
/* The id->flag bits to copy over. */
- const int copy_idflag_mask = LIB_PRIVATE_DATA;
+ const int copy_idflag_mask = LIB_EMBEDDED_DATA;
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
@@ -1744,7 +1744,7 @@ static void library_make_local_copying_check(ID *id,
}
/* Shapekeys are considered 'private' to their owner ID here, and never tagged
- * (since they cannot be linked), * so we have to switch effective parent to their owner.
+ * (since they cannot be linked), so we have to switch effective parent to their owner.
*/
if (GS(par_id->name) == ID_KE) {
par_id = ((Key *)par_id)->from;
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index ee27d0e546d..41d938e897d 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -137,11 +137,15 @@ enum {
typedef struct LibraryForeachIDData {
Main *bmain;
- /* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a
- * private one. */
+ /**
+ * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a
+ * private one.
+ */
ID *owner_id;
- /* ID from which the current ID pointer is being processed. It may be a 'private' ID like master
- * collection or root node tree. */
+ /**
+ * ID from which the current ID pointer is being processed. It may be an embedded ID like master
+ * collection or root node tree.
+ */
ID *self_id;
int flag;
@@ -343,8 +347,8 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas
/* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
* anyway... */
const int cb_flag = (lc->collection != NULL &&
- (lc->collection->id.flag & LIB_PRIVATE_DATA) != 0) ?
- IDWALK_CB_PRIVATE :
+ (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
+ IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP;
FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag);
library_foreach_layer_collection(data, &lc->layer_collections);
@@ -367,8 +371,8 @@ static void library_foreach_collection(LibraryForeachIDData *data, Collection *c
/* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
* anyway... */
const int cb_flag = ((parent->collection != NULL &&
- (parent->collection->id.flag & LIB_PRIVATE_DATA) != 0) ?
- IDWALK_CB_PRIVATE :
+ (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
+ IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP);
FOREACH_CALLBACK_INVOKE(
data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
@@ -484,13 +488,13 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are
FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP);
FOREACH_CALLBACK_INVOKE(
- data, snode->nodetree, is_private_nodetree ? IDWALK_CB_PRIVATE : IDWALK_CB_USER);
+ data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
FOREACH_CALLBACK_INVOKE(
- data, path->nodetree, is_private_nodetree ? IDWALK_CB_PRIVATE : IDWALK_CB_NOP);
+ data, path->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP);
}
else {
FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER);
@@ -527,10 +531,13 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp,
{
/* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
ID *id = *id_pp;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED);
BLI_assert(id == *id_pp);
- if (flag & IDWALK_RECURSE) {
+ if (flag & IDWALK_IGNORE_EMBEDDED_ID) {
+ /* Do Nothing. */
+ }
+ else if (flag & IDWALK_RECURSE) {
/* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in
* IDWALK_RECURSE case is troublesome, see T49553. */
/* XXX note that this breaks the 'owner id' thing now, we likely want to handle that
@@ -583,7 +590,12 @@ static void library_foreach_ID_link(Main *bmain,
for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
- data.owner_id = (id->flag & LIB_PRIVATE_DATA) ? id_owner : data.self_id;
+ /* Note that we may call this functions sometime directly on an embedded ID, without any
+ * knowledge of the owner ID then.
+ * While not great, and that should be probably sanitized at some point, we cal live with it
+ * for now. */
+ data.owner_id = ((id->flag & LIB_EMBEDDED_DATA) != 0 && id_owner != NULL) ? id_owner :
+ data.self_id;
/* inherit_data is non-NULL when this function is called for some sub-data ID
* (like root nodetree of a material).
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index d4b7696074a..1a22a6e6f79 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -68,7 +68,7 @@ typedef struct IDRemap {
ID *old_id;
ID *new_id;
/** The ID in which we are replacing old_id by new_id usages. */
- ID *id;
+ ID *id_owner;
short flag;
/* 'Output' data. */
@@ -94,16 +94,21 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_PRIVATE) {
+ if (cb_flag & IDWALK_CB_EMBEDDED) {
return IDWALK_RET_NOP;
}
+ ID *id_owner = cb_data->id_owner;
ID *id_self = cb_data->id_self;
ID **id_p = cb_data->id_pointer;
IDRemap *id_remap_data = cb_data->user_data;
ID *old_id = id_remap_data->old_id;
ID *new_id = id_remap_data->new_id;
- ID *id = id_remap_data->id;
+
+ /* Those asserts ensure the general sanity of ID tags regarding 'embedded' ID data (root
+ * nodetrees and co). */
+ BLI_assert(id_owner == id_remap_data->id_owner);
+ BLI_assert(id_self == id_owner || (id_self->flag & LIB_EMBEDDED_DATA) != 0);
if (!old_id) { /* Used to cleanup all IDs used by a specific one. */
BLI_assert(!new_id);
@@ -123,9 +128,10 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
* on the other hand since they get reset to lib data on file open/reload it is indirect too.
* Edit Mode is also a 'skip direct' case. */
- const bool is_obj = (GS(id->name) == ID_OB);
- const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
- const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
+ const bool is_obj = (GS(id_owner->name) == ID_OB);
+ const bool is_obj_proxy = (is_obj &&
+ (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner));
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0;
@@ -149,19 +155,19 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) &&
(cb_flag & IDWALK_CB_NEVER_NULL)) {
- id->tag |= LIB_TAG_DOIT;
+ id_owner->tag |= LIB_TAG_DOIT;
}
/* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
* (otherwise, we follow common NEVER_NULL flags).
* (skipped_indirect too). */
if ((is_never_null && skip_never_null) ||
- (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
+ (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) ||
(skip_indirect && is_indirect) || (is_reference && skip_reference)) {
if (is_indirect) {
id_remap_data->skipped_indirect++;
if (is_obj) {
- Object *ob = (Object *)id;
+ Object *ob = (Object *)id_owner;
if (ob->data == *id_p && ob->proxy != NULL) {
/* And another 'Proudly brought to you by Proxy Hell' hack!
* This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
@@ -189,6 +195,11 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
DEG_id_tag_update_ex(id_remap_data->bmain,
id_self,
ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ if (id_self != id_owner) {
+ DEG_id_tag_update_ex(id_remap_data->bmain,
+ id_owner,
+ ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
}
if (cb_flag & IDWALK_CB_USER) {
/* NOTE: We don't user-count IDs which are not in the main database.
@@ -215,7 +226,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
}
/* We need to remap proxy_from pointer of remapped proxy... sigh. */
if (is_obj_proxy && new_id != NULL) {
- Object *ob = (Object *)id;
+ Object *ob = (Object *)id_owner;
if (ob->proxy == (Object *)new_id) {
ob->proxy->proxy_from = ob;
}
@@ -228,11 +239,11 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
- switch (GS(r_id_remap_data->id->name)) {
+ switch (GS(r_id_remap_data->id_owner->name)) {
case ID_OB: {
ID *old_id = r_id_remap_data->old_id;
if (!old_id || GS(old_id->name) == ID_AR) {
- Object *ob = (Object *)r_id_remap_data->id;
+ Object *ob = (Object *)r_id_remap_data->id_owner;
/* Object's pose holds reference to armature bones... sic */
/* Note that in theory, we should have to bother about
* linked/non-linked/never-null/etc. flags/states.
@@ -371,7 +382,7 @@ static void libblock_remap_data(
r_id_remap_data->bmain = bmain;
r_id_remap_data->old_id = old_id;
r_id_remap_data->new_id = new_id;
- r_id_remap_data->id = NULL;
+ r_id_remap_data->id_owner = NULL;
r_id_remap_data->flag = remap_flags;
r_id_remap_data->status = 0;
r_id_remap_data->skipped_direct = 0;
@@ -382,7 +393,7 @@ static void libblock_remap_data(
#ifdef DEBUG_PRINT
printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
#endif
- r_id_remap_data->id = id;
+ r_id_remap_data->id_owner = id;
libblock_remap_data_preprocess(r_id_remap_data);
BKE_library_foreach_ID_link(
NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
@@ -398,7 +409,7 @@ static void libblock_remap_data(
/* Note that we cannot skip indirect usages of old_id here (if requested),
* we still need to check it for the user count handling...
* XXX No more true (except for debug usage of those skipping counters). */
- r_id_remap_data->id = id_curr;
+ r_id_remap_data->id_owner = id_curr;
libblock_remap_data_preprocess(r_id_remap_data);
BKE_library_foreach_ID_link(NULL,
id_curr,
@@ -642,7 +653,7 @@ void BKE_libblock_relink_ex(
static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_PRIVATE) {
+ if (cb_flag & IDWALK_CB_EMBEDDED) {
return IDWALK_RET_NOP;
}
diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c
index 26eb0b681a1..8b83482d685 100644
--- a/source/blender/blenkernel/intern/main_idmap.c
+++ b/source/blender/blenkernel/intern/main_idmap.c
@@ -124,6 +124,8 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
const bool existing_key = BLI_ghash_ensure_p(
id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v);
BLI_assert(existing_key == false);
+ UNUSED_VARS_NDEBUG(existing_key);
+
*id_ptr_v = id;
}
FOREACH_MAIN_ID_END;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 1feb20ec272..8ddb78bcc17 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1654,7 +1654,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
}
else {
ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
- ntree->id.flag |= LIB_PRIVATE_DATA;
+ ntree->id.flag |= LIB_EMBEDDED_DATA;
*((short *)ntree->id.name) = ID_NT;
BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
}
@@ -1682,21 +1682,6 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
return ntreeCopyTree_ex(ntree, bmain, true);
}
-void ntreeUserIncrefID(bNodeTree *ntree)
-{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- id_us_plus(node->id);
- }
-}
-void ntreeUserDecrefID(bNodeTree *ntree)
-{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- id_us_min(node->id);
- }
-}
-
/* *************** Node Preview *********** */
/* XXX this should be removed eventually ...
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index c27fb59835f..26485d10fbd 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -38,11 +38,11 @@
#include "BLI_path_util.h"
#include "BLI_rand.h"
#include "BLI_task.h"
-#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_image.h"
#include "BKE_ocean.h"
+#include "ocean_intern.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -54,95 +54,6 @@
#ifdef WITH_OCEANSIM
/* Ocean code */
-# include "fftw3.h"
-
-# define GRAVITY 9.81f
-
-typedef struct Ocean {
- /* ********* input parameters to the sim ********* */
- float _V;
- float _l;
- float _w;
- float _A;
- float _damp_reflections;
- float _wind_alignment;
- float _depth;
-
- float _wx;
- float _wz;
-
- float _L;
-
- /* dimensions of computational grid */
- int _M;
- int _N;
-
- /* spatial size of computational grid */
- float _Lx;
- float _Lz;
-
- float normalize_factor; /* init w */
- float time;
-
- short _do_disp_y;
- short _do_normals;
- short _do_chop;
- short _do_jacobian;
-
- /* mutex for threaded texture access */
- ThreadRWMutex oceanmutex;
-
- /* ********* sim data arrays ********* */
-
- /* two dimensional arrays of complex */
- fftw_complex *_fft_in; /* init w sim w */
- fftw_complex *_fft_in_x; /* init w sim w */
- fftw_complex *_fft_in_z; /* init w sim w */
- fftw_complex *_fft_in_jxx; /* init w sim w */
- fftw_complex *_fft_in_jzz; /* init w sim w */
- fftw_complex *_fft_in_jxz; /* init w sim w */
- fftw_complex *_fft_in_nx; /* init w sim w */
- fftw_complex *_fft_in_nz; /* init w sim w */
- fftw_complex *_htilda; /* init w sim w (only once) */
-
- /* fftw "plans" */
- fftw_plan _disp_y_plan; /* init w sim r */
- fftw_plan _disp_x_plan; /* init w sim r */
- fftw_plan _disp_z_plan; /* init w sim r */
- fftw_plan _N_x_plan; /* init w sim r */
- fftw_plan _N_z_plan; /* init w sim r */
- fftw_plan _Jxx_plan; /* init w sim r */
- fftw_plan _Jxz_plan; /* init w sim r */
- fftw_plan _Jzz_plan; /* init w sim r */
-
- /* two dimensional arrays of float */
- double *_disp_y; /* init w sim w via plan? */
- double *_N_x; /* init w sim w via plan? */
- /* all member of this array has same values,
- * so convert this array to a float to reduce memory usage (MEM01). */
- /*float * _N_y; */
- double _N_y; /* sim w ********* can be rearranged? */
- double *_N_z; /* init w sim w via plan? */
- double *_disp_x; /* init w sim w via plan? */
- double *_disp_z; /* init w sim w via plan? */
-
- /* two dimensional arrays of float */
- /* Jacobian and minimum eigenvalue */
- double *_Jxx; /* init w sim w */
- double *_Jzz; /* init w sim w */
- double *_Jxz; /* init w sim w */
-
- /* one dimensional float array */
- float *_kx; /* init w sim r */
- float *_kz; /* init w sim r */
-
- /* two dimensional complex array */
- fftw_complex *_h0; /* init w sim r */
- fftw_complex *_h0_minus; /* init w sim r */
-
- /* two dimensional float array */
- float *_k; /* init w sim r */
-} Ocean;
static float nextfr(RNG *rng, float min, float max)
{
@@ -285,7 +196,7 @@ float BKE_ocean_jminus_to_foam(float jminus, float coverage)
{
float foam = jminus * -0.005f + coverage;
CLAMP(foam, 0.0f, 1.0f);
- return foam * foam;
+ return foam;
}
void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v)
@@ -893,6 +804,9 @@ void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData
omd->wave_alignment,
omd->depth,
omd->time,
+ omd->spectrum,
+ omd->fetch_jonswap,
+ omd->sharpen_peak_jonswap,
do_heightfield,
do_chop,
do_normals,
@@ -913,6 +827,9 @@ void BKE_ocean_init(struct Ocean *o,
float alignment,
float depth,
float time,
+ int spectrum,
+ float fetch_jonswap,
+ float sharpen_peak_jonswap,
short do_height_field,
short do_chop,
short do_normals,
@@ -940,6 +857,13 @@ void BKE_ocean_init(struct Ocean *o,
o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */
o->time = time;
+ /* Spectrum to use. */
+ o->_spectrum = spectrum;
+
+ /* Common JONSWAP parameters. */
+ o->_fetch_jonswap = fetch_jonswap;
+ o->_sharpen_peak_jonswap = sharpen_peak_jonswap;
+
o->_do_disp_y = do_height_field;
o->_do_normals = do_normals;
o->_do_chop = do_chop;
@@ -1001,10 +925,46 @@ void BKE_ocean_init(struct Ocean *o,
fftw_complex r1r2;
init_complex(r1r2, r1, r2);
- mul_complex_f(
- o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f)));
- mul_complex_f(
- o->_h0_minus[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f)));
+ switch (o->_spectrum) {
+ case MOD_OCEAN_SPECTRUM_JONSWAP:
+ mul_complex_f(o->_h0[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(BLI_ocean_spectrum_jonswap(o, o->_kx[i], o->_kz[j]) / 2.0f)));
+ mul_complex_f(
+ o->_h0_minus[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(BLI_ocean_spectrum_jonswap(o, -o->_kx[i], -o->_kz[j]) / 2.0f)));
+ break;
+ case MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE:
+ mul_complex_f(
+ o->_h0[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, o->_kx[i], o->_kz[j]) / 2.0f)));
+ mul_complex_f(
+ o->_h0_minus[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, -o->_kx[i], -o->_kz[j]) /
+ 2.0f)));
+ break;
+ case MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ:
+ mul_complex_f(
+ o->_h0[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, o->_kx[i], o->_kz[j]) / 2.0f)));
+ mul_complex_f(
+ o->_h0_minus[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, -o->_kx[i], -o->_kz[j]) /
+ 2.0f)));
+ break;
+ default:
+ mul_complex_f(
+ o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f)));
+ mul_complex_f(o->_h0_minus[i * o->_N + j],
+ r1r2,
+ (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f)));
+ break;
+ }
}
}
@@ -1517,12 +1477,6 @@ void BKE_ocean_bake(struct Ocean *o,
#else /* WITH_OCEANSIM */
-/* stub */
-typedef struct Ocean {
- /* need some data here, C does not allow empty struct */
- int stub;
-} Ocean;
-
float BKE_ocean_jminus_to_foam(float UNUSED(jminus), float UNUSED(coverage))
{
return 0.0f;
@@ -1591,6 +1545,9 @@ void BKE_ocean_init(struct Ocean *UNUSED(o),
float UNUSED(alignment),
float UNUSED(depth),
float UNUSED(time),
+ int UNUSED(spectrum),
+ float UNUSED(fetch_jonswap),
+ float UNUSED(sharpen_peak_jonswap),
short UNUSED(do_height_field),
short UNUSED(do_chop),
short UNUSED(do_normals),
diff --git a/source/blender/blenkernel/intern/ocean_intern.h b/source/blender/blenkernel/intern/ocean_intern.h
new file mode 100644
index 00000000000..7da88419219
--- /dev/null
+++ b/source/blender/blenkernel/intern/ocean_intern.h
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#ifndef __BKE_OCEAN_INTERN_H__
+#define __BKE_OCEAN_INTERN_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WITH_OCEANSIM
+# include "BLI_threads.h"
+# include "fftw3.h"
+# define GRAVITY 9.81f
+
+typedef struct Ocean {
+ /* ********* input parameters to the sim ********* */
+ float _V;
+ float _l;
+ float _w;
+ float _A;
+ float _damp_reflections;
+ float _wind_alignment;
+ float _depth;
+
+ float _wx;
+ float _wz;
+
+ float _L;
+
+ /* dimensions of computational grid */
+ int _M;
+ int _N;
+
+ /* spatial size of computational grid */
+ float _Lx;
+ float _Lz;
+
+ float normalize_factor; /* init w */
+ float time;
+
+ short _do_disp_y;
+ short _do_normals;
+ short _do_chop;
+ short _do_jacobian;
+
+ /* Which spectral model we are using. */
+ int _spectrum;
+
+ /* JONSWAP common parameters. */
+ float _fetch_jonswap;
+ float _sharpen_peak_jonswap;
+
+ /* mutex for threaded texture access */
+ ThreadRWMutex oceanmutex;
+
+ /* ********* sim data arrays ********* */
+
+ /* two dimensional arrays of complex */
+ fftw_complex *_fft_in; /* init w sim w */
+ fftw_complex *_fft_in_x; /* init w sim w */
+ fftw_complex *_fft_in_z; /* init w sim w */
+ fftw_complex *_fft_in_jxx; /* init w sim w */
+ fftw_complex *_fft_in_jzz; /* init w sim w */
+ fftw_complex *_fft_in_jxz; /* init w sim w */
+ fftw_complex *_fft_in_nx; /* init w sim w */
+ fftw_complex *_fft_in_nz; /* init w sim w */
+ fftw_complex *_htilda; /* init w sim w (only once) */
+
+ /* fftw "plans" */
+ fftw_plan _disp_y_plan; /* init w sim r */
+ fftw_plan _disp_x_plan; /* init w sim r */
+ fftw_plan _disp_z_plan; /* init w sim r */
+ fftw_plan _N_x_plan; /* init w sim r */
+ fftw_plan _N_z_plan; /* init w sim r */
+ fftw_plan _Jxx_plan; /* init w sim r */
+ fftw_plan _Jxz_plan; /* init w sim r */
+ fftw_plan _Jzz_plan; /* init w sim r */
+
+ /* two dimensional arrays of float */
+ double *_disp_y; /* init w sim w via plan? */
+ double *_N_x; /* init w sim w via plan? */
+ /* all member of this array has same values,
+ * so convert this array to a float to reduce memory usage (MEM01). */
+ /*float * _N_y; */
+ double _N_y; /* sim w ********* can be rearranged? */
+ double *_N_z; /* init w sim w via plan? */
+ double *_disp_x; /* init w sim w via plan? */
+ double *_disp_z; /* init w sim w via plan? */
+
+ /* two dimensional arrays of float */
+ /* Jacobian and minimum eigenvalue */
+ double *_Jxx; /* init w sim w */
+ double *_Jzz; /* init w sim w */
+ double *_Jxz; /* init w sim w */
+
+ /* one dimensional float array */
+ float *_kx; /* init w sim r */
+ float *_kz; /* init w sim r */
+
+ /* two dimensional complex array */
+ fftw_complex *_h0; /* init w sim r */
+ fftw_complex *_h0_minus; /* init w sim r */
+
+ /* two dimensional float array */
+ float *_k; /* init w sim r */
+} Ocean;
+#else
+/* stub */
+typedef struct Ocean {
+ /* need some data here, C does not allow empty struct */
+ int stub;
+} Ocean;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c
new file mode 100644
index 00000000000..93018f4a5b0
--- /dev/null
+++ b/source/blender/blenkernel/intern/ocean_spectrum.c
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+#include "BKE_ocean.h"
+#include "ocean_intern.h"
+
+#ifdef WITH_OCEANSIM
+
+/* -------------------------------------------------------------------- */
+/** \name Ocean Spectrum from EncinoWaves
+ * \{ */
+
+/*
+ * Original code from EncinoWaves project Copyright (c) 2015 Christopher Jon Horvath
+ * Modifications made to work within blender.
+ *
+ * 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
+ */
+
+/**
+ * alpha_beta_spectrum is a common algorithm for the Pierson-Moskowitz, JONSWAP and TMA models.
+ * This is a modified implementation from the EncinoWaves project.
+ */
+static float alpha_beta_spectrum(const float alpha,
+ const float beta,
+ const float gamma,
+ const float omega,
+ const float peakomega)
+{
+ return (alpha * sqrt(gamma) / pow(omega, 5.0)) * exp(-beta * pow(peakomega / omega, 4.0));
+}
+
+static float peak_sharpen(const float omega, const float m_peakomega, const float m_gamma)
+{
+ const float peak_sharpening_sigma = (omega < m_peakomega) ? 0.07 : 0.09;
+ const float peak_sharpening = pow(
+ m_gamma, exp(-sqrt((omega - m_peakomega) / (peak_sharpening_sigma * m_peakomega)) / 2.0));
+
+ return peak_sharpening;
+}
+
+/**
+ * Spectrum-type independent modifications.
+ */
+static float ocean_spectrum_wind_and_damp(const Ocean *oc,
+ const float kx,
+ const float kz,
+ const float val)
+{
+ const float k2 = kx * kx + kz * kz;
+ const float k_mag_inv = 1.0f / k2;
+ const float k_dot_w = (kx * k_mag_inv * oc->_wx) + (kz * k_mag_inv * oc->_wz);
+
+ /* Bias towards wind dir. */
+ float newval = val * pow(fabs(k_dot_w), oc->_wind_alignment);
+
+ /* Eliminate wavelengths smaller than cutoff. */
+ /* val *= exp(-k2 * m_cutoff); */
+
+ /* Reduce reflected waves. */
+ if (k_dot_w < 0.0f) {
+ if (oc->_wind_alignment > 0.0) {
+ newval *= oc->_damp_reflections;
+ }
+ }
+
+ return newval;
+}
+
+static float jonswap(const Ocean *oc, const float k2)
+{
+ /* Get our basic JONSWAP value from #alpha_beta_spectrum. */
+ const float k_mag = sqrt(k2);
+
+ const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth);
+ const float omega = sqrt(m_omega);
+
+ const float m_fetch = oc->_fetch_jonswap;
+
+ /* Strictly, this should be a random value from a Gaussian (mean 3.3, variance 0.67),
+ * clamped 1.0 to 6.0. */
+ float m_gamma = oc->_sharpen_peak_jonswap;
+ if (m_gamma < 1.0) {
+ m_gamma = 1.00;
+ }
+ if (m_gamma > 6.0) {
+ m_gamma = 6.0;
+ }
+
+ const float m_windspeed = oc->_V;
+
+ const float m_dimensionlessFetch = fabs(GRAVITY * m_fetch / sqrt(m_windspeed));
+ const float m_alpha = 0.076 * pow(m_dimensionlessFetch, -0.22);
+
+ const float m_tau = M_PI * 2;
+ const float m_peakomega = m_tau * 3.5 * fabs(GRAVITY / oc->_V) *
+ pow(m_dimensionlessFetch, -0.33);
+
+ const float beta = 1.25f;
+
+ float val = alpha_beta_spectrum(m_alpha, beta, GRAVITY, omega, m_peakomega);
+
+ /* Peak sharpening */
+ val *= peak_sharpen(m_omega, m_peakomega, m_gamma);
+
+ return val;
+}
+
+/**
+ * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
+ * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
+ * for days over an area that includes hundreds of wavelengths on a side.
+ */
+float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz)
+{
+ const float k2 = kx * kx + kz * kz;
+
+ if (k2 == 0.0f) {
+ /* No DC component. */
+ return 0.0f;
+ }
+
+ /* Get Pierson-Moskowitz value from #alpha_beta_spectrum. */
+ const float peak_omega_PM = 0.87f * GRAVITY / oc->_V;
+
+ const float k_mag = sqrt(k2);
+ const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth);
+
+ const float omega = sqrt(m_omega);
+ const float alpha = 0.0081f;
+ const float beta = 1.291f;
+
+ float val = alpha_beta_spectrum(alpha, beta, GRAVITY, omega, peak_omega_PM);
+
+ val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
+
+ return val;
+}
+
+/**
+ * TMA extends the JONSWAP spectrum.
+ * This spectral model is best suited to shallow water.
+ */
+float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz)
+{
+ const float k2 = kx * kx + kz * kz;
+
+ if (k2 == 0.0f) {
+ /* No DC component. */
+ return 0.0f;
+ }
+
+ float val = jonswap(oc, k2);
+
+ val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
+
+ /* TMA modifications to JONSWAP. */
+ const float m_depth = oc->_depth;
+ const float gain = sqrt(m_depth / GRAVITY);
+
+ const float k_mag = sqrt(k2);
+
+ const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth);
+ const float omega = sqrt(m_omega);
+
+ const float kitaigorodskiiDepth_wh = omega * gain;
+ const float kitaigorodskiiDepth = 0.5 + (0.5 * tanh(1.8 * (kitaigorodskiiDepth_wh - 1.125)));
+
+ val *= kitaigorodskiiDepth;
+
+ val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
+
+ return val;
+}
+
+/**
+ * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
+ * function This enhancement is an artificial construct to address the problem that the wave
+ * spectrum is never fully developed.
+ *
+ * The fetch parameter represents the distance from a lee shore,
+ * called the fetch, or the distance over which the wind blows with constant velocity.
+ */
+float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz)
+{
+ const float k2 = kx * kx + kz * kz;
+
+ if (k2 == 0.0f) {
+ /* No DC component. */
+ return 0.0f;
+ }
+
+ float val = jonswap(oc, k2);
+
+ val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
+
+ return val;
+}
+
+/** \} */
+
+#endif /* WITH_OCEANSIM */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 90a4a2dee23..b0163436cc4 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1953,8 +1953,8 @@ static bool foreach_object_ptcache(
if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
return false;
}
- /* Consider all object in dupli groups to be part of the same object,
- * for baking with linking dupligroups. Once we have better overrides
+ /* Consider all object in dupli-groups to be part of the same object,
+ * for baking with linking dupli-groups. Once we have better overrides
* this can be revisited so users select the local objects directly. */
if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 37049014ef7..6ca14ec9197 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -395,9 +395,9 @@ static void scene_free_data(ID *id)
scene->master_collection = NULL;
}
- if (scene->eevee.light_cache) {
- EEVEE_lightcache_free(scene->eevee.light_cache);
- scene->eevee.light_cache = NULL;
+ if (scene->eevee.light_cache_data) {
+ EEVEE_lightcache_free(scene->eevee.light_cache_data);
+ scene->eevee.light_cache_data = NULL;
}
if (scene->display.shading.prop) {
@@ -583,7 +583,7 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src)
{
/* Copy eevee data between scenes. */
sce_dst->eevee = sce_src->eevee;
- sce_dst->eevee.light_cache = NULL;
+ sce_dst->eevee.light_cache_data = NULL;
sce_dst->eevee.light_cache_info[0] = '\0';
/* TODO Copy the cache. */
}
@@ -2057,6 +2057,14 @@ void BKE_scene_free_depsgraph_hash(Scene *scene)
scene->depsgraph_hash = NULL;
}
+void BKE_scene_free_view_layer_depsgraph(Scene *scene, ViewLayer *view_layer)
+{
+ if (scene->depsgraph_hash != NULL) {
+ DepsgraphKey key = {view_layer};
+ BLI_ghash_remove(scene->depsgraph_hash, &key, depsgraph_key_free, depsgraph_key_value_free);
+ }
+}
+
/* Query depsgraph for a specific contexts. */
Depsgraph *BKE_scene_get_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, bool allocate)
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index f1243330567..a9bd1d17567 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -621,7 +621,7 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
new_track->markers = MEM_dupallocN(new_track->markers);
- /* Orevent duplicate from being used for 2D stabilization.
+ /* Prevent duplicate from being used for 2D stabilization.
* If necessary, it shall be added explicitly.
*/
new_track->flag &= ~TRACK_USE_2D_STAB;
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index ee9ea15835b..b532202ebaa 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -191,10 +191,14 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
return ptr;
}
-/* Direct access. elem is element index inside the chosen chunk. */
+/* Direct access. elem is element index inside the chosen chunk.
+ * Double usage: You can set chunk to 0 and set the absolute elem index.
+ * The correct chunk will be retrieve. */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
{
BLI_assert(chunk < mblk->chunk_len);
- BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
+ int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
+ chunk += elem / elem_per_chunk;
+ elem = elem % elem_per_chunk;
return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 7e17d1235fe..3059caf83f1 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -157,6 +157,8 @@
#include "RE_engine.h"
+#include "engines/eevee/eevee_lightcache.h"
+
#include "readfile.h"
#include <errno.h>
@@ -1852,8 +1854,8 @@ void blo_make_scene_pointer_map(FileData *fd, Main *oldmain)
fd->scenemap = oldnewmap_new();
for (; sce; sce = sce->id.next) {
- if (sce->eevee.light_cache) {
- struct LightCache *light_cache = sce->eevee.light_cache;
+ if (sce->eevee.light_cache_data) {
+ struct LightCache *light_cache = sce->eevee.light_cache_data;
oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0);
}
}
@@ -1873,7 +1875,7 @@ void blo_end_scene_pointer_map(FileData *fd, Main *oldmain)
}
for (; sce; sce = sce->id.next) {
- sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache);
+ sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data);
}
}
@@ -5439,7 +5441,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
mmd->domain->fluid = NULL;
mmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- mmd->domain->tex = NULL;
+ mmd->domain->tex_density = NULL;
+ mmd->domain->tex_color = NULL;
mmd->domain->tex_shadow = NULL;
mmd->domain->tex_flame = NULL;
mmd->domain->tex_flame_coba = NULL;
@@ -6926,19 +6929,20 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (fd->memfile) {
/* If it's undo try to recover the cache. */
if (fd->scenemap) {
- sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache);
+ sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data);
}
else {
- sce->eevee.light_cache = NULL;
+ sce->eevee.light_cache_data = NULL;
}
}
else {
/* else try to read the cache from file. */
- sce->eevee.light_cache = newdataadr(fd, sce->eevee.light_cache);
- if (sce->eevee.light_cache) {
- direct_link_lightcache(fd, sce->eevee.light_cache);
+ sce->eevee.light_cache_data = newdataadr(fd, sce->eevee.light_cache_data);
+ if (sce->eevee.light_cache_data) {
+ direct_link_lightcache(fd, sce->eevee.light_cache_data);
}
}
+ EEVEE_lightcache_info_update(&sce->eevee);
direct_link_view3dshading(fd, &sce->display.shading);
@@ -7791,7 +7795,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
ID **id_pointer = cb_data->id_pointer;
- if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) {
+ if (cb_flag & IDWALK_CB_EMBEDDED || *id_pointer == NULL) {
return IDWALK_RET_NOP;
}
@@ -7802,7 +7806,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data)
Collection *collection = (Collection *)*id_pointer;
if (collection->flag & COLLECTION_IS_MASTER) {
/* We should never reach that point anymore, since master collection private ID should be
- * properly tagged with IDWALK_CB_PRIVATE. */
+ * properly tagged with IDWALK_CB_EMBEDDED. */
BLI_assert(0);
return IDWALK_RET_NOP;
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 34041b0ca22..0ce32d234a8 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -4091,7 +4091,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_MAIN_ID_BEGIN (bmain, id) {
bNodeTree *ntree = ntreeFromID(id);
if (ntree) {
- ntree->id.flag |= LIB_PRIVATE_DATA;
+ ntree->id.flag |= LIB_EMBEDDED_DATA;
}
}
FOREACH_MAIN_ID_END;
@@ -4108,7 +4108,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Older files do not have a master collection, which is then added through
* `BKE_collection_master_add()`, so everything is fine. */
if (scene->master_collection != NULL) {
- scene->master_collection->id.flag |= LIB_PRIVATE_DATA;
+ scene->master_collection->id.flag |= LIB_EMBEDDED_DATA;
}
}
}
@@ -4851,6 +4851,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ if (!DNA_struct_elem_find(fd->filesdna, "OceanModifierData", "float", "fetch_jonswap")) {
+ for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
+ for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Ocean) {
+ OceanModifierData *omd = (OceanModifierData *)md;
+ omd->fetch_jonswap = 120.0f;
+ }
+ }
+ }
+ }
+
if (!DNA_struct_find(fd->filesdna, "XrSessionSettings")) {
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
const View3D *v3d_default = DNA_struct_default_get(View3D);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 81df00ebdef..a9c5008062b 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2767,9 +2767,9 @@ static void write_scene(WriteData *wd, Scene *sce)
}
/* Eevee Lightcache */
- if (sce->eevee.light_cache && !wd->use_memfile) {
- writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache);
- write_lightcache(wd, sce->eevee.light_cache);
+ if (sce->eevee.light_cache_data && !wd->use_memfile) {
+ writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache_data);
+ write_lightcache(wd, sce->eevee.light_cache_data);
}
write_view3dshading(wd, &sce->display.shading);
diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
index 147c375aa6e..350473fa195 100644
--- a/source/blender/blentranslation/msgfmt/CMakeLists.txt
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -37,6 +37,10 @@ if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
endif()
+if(WIN32)
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /nodefaultlib:MSVCRT.lib")
+endif()
+
add_executable(msgfmt ${SRC})
target_link_libraries(msgfmt bf_blenlib)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 01d84f6b5d8..c512300200e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -319,6 +319,18 @@ void DepsgraphNodeBuilder::begin_build()
* them for new ID nodes. */
id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash");
for (IDNode *id_node : graph_->id_nodes) {
+ /* It is possible that the ID does not need to have CoW version in which case id_cow is the
+ * same as id_orig. Additionally, such ID might have been removed, which makes the check
+ * for whether id_cow is expanded to access freed memory. In orderr to deal with this we
+ * check whether CoW is needed based on a scalar value which does not lead to access of
+ * possibly deleted memory.
+ * Additionally, this saves some space in the map by skipping mapping for datablocks which
+ * do not need CoW, */
+ if (!deg_copy_on_write_is_needed(id_node->id_type)) {
+ id_node->id_cow = nullptr;
+ continue;
+ }
+
IDInfo *id_info = (IDInfo *)MEM_mallocN(sizeof(IDInfo), "depsgraph id info");
if (deg_copy_on_write_is_expanded(id_node->id_cow) && id_node->id_orig != id_node->id_cow) {
id_info->id_cow = id_node->id_cow;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index df61a1416bd..1296c87bbb0 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -37,6 +37,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_node_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -343,11 +344,13 @@ void depsgraph_ensure_view_layer(Depsgraph *graph)
* - It was tagged for update of CoW component.
* This allows us to have proper view layer pointer. */
Scene *scene_cow = graph->scene_cow;
- if (!deg_copy_on_write_is_expanded(&scene_cow->id) ||
- scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) {
- const IDNode *id_node = graph->find_id_node(&graph->scene->id);
- deg_update_copy_on_write_datablock(graph, id_node);
+ if (deg_copy_on_write_is_expanded(&scene_cow->id) &&
+ (scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) == 0) {
+ return;
}
+
+ const IDNode *scene_id_node = graph->find_id_node(&graph->scene->id);
+ deg_update_copy_on_write_datablock(graph, scene_id_node);
}
} // namespace
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 1841f5f024f..d8ce590c611 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
@@ -804,7 +804,7 @@ void update_id_after_copy(const Depsgraph *depsgraph,
Scene *scene_cow = (Scene *)id_cow;
const Scene *scene_orig = (const Scene *)id_orig;
scene_cow->toolsettings = scene_orig->toolsettings;
- scene_cow->eevee.light_cache = scene_orig->eevee.light_cache;
+ scene_cow->eevee.light_cache_data = scene_orig->eevee.light_cache_data;
scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast<Scene *>(id_cow));
update_scene_orig_pointers(scene_orig, scene_cow);
break;
@@ -914,8 +914,11 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
user_data.depsgraph = depsgraph;
user_data.node_builder = node_builder;
user_data.create_placeholders = create_placeholders;
- BKE_library_foreach_ID_link(
- nullptr, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP);
+ BKE_library_foreach_ID_link(nullptr,
+ id_cow,
+ foreach_libblock_remap_callback,
+ (void *)&user_data,
+ IDWALK_IGNORE_EMBEDDED_ID);
/* Correct or tweak some pointers which are not taken care by foreach
* from above. */
update_id_after_copy(depsgraph, id_node, id_orig, id_cow);
@@ -1000,7 +1003,7 @@ void discard_scene_pointers(ID *id_cow)
{
Scene *scene_cow = (Scene *)id_cow;
scene_cow->toolsettings = nullptr;
- scene_cow->eevee.light_cache = nullptr;
+ scene_cow->eevee.light_cache_data = nullptr;
}
/* nullptr-ify all edit mode pointers which points to data from
@@ -1113,6 +1116,11 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow)
bool deg_copy_on_write_is_needed(const ID *id_orig)
{
const ID_Type id_type = GS(id_orig->name);
+ return deg_copy_on_write_is_needed(id_type);
+}
+
+bool deg_copy_on_write_is_needed(const ID_Type id_type)
+{
return ID_TYPE_IS_COW(id_type);
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
index 1992c80e036..05464d11f13 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -25,6 +25,8 @@
#include <stddef.h>
+#include "DNA_ID.h"
+
struct ID;
/* Uncomment this to have verbose log about original and CoW pointers
@@ -94,5 +96,6 @@ bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
* This includes images.
*/
bool deg_copy_on_write_is_needed(const ID *id_orig);
+bool deg_copy_on_write_is_needed(const ID_Type id_type);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 0fbf658ceb3..cd25cc14069 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -103,6 +103,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
BLI_assert(id != nullptr);
/* Store ID-pointer. */
+ id_type = GS(id->name);
id_orig = (ID *)id;
eval_flags = 0;
previous_eval_flags = 0;
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 886c25b5a4e..6eea31ebff9 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -25,6 +25,7 @@
#include "intern/node/deg_node.h"
#include "BLI_sys_types.h"
+#include "DNA_ID.h"
struct GHash;
@@ -73,6 +74,10 @@ struct IDNode : public Node {
IDComponentsMask get_visible_components_mask() const;
/* ID Block referenced. */
+ /* Type of the ID stored separately, so it's possible to perform check whether CoW is needed
+ * without de-referencing the id_cow (which is not safe when ID is NOT covered by CoW and has
+ * been deleted from the main database.) */
+ ID_Type id_type;
ID *id_orig;
ID *id_cow;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 1f04739644e..a1213be4be0 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -97,19 +97,18 @@ set(SRC
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
- engines/workbench/solid_mode.c
- engines/workbench/transparent_mode.c
engines/workbench/workbench_data.c
- engines/workbench/workbench_deferred.c
- engines/workbench/workbench_effect_aa.c
+ engines/workbench/workbench_effect_antialiasing.c
+ engines/workbench/workbench_effect_cavity.c
engines/workbench/workbench_effect_dof.c
- engines/workbench/workbench_effect_fxaa.c
- engines/workbench/workbench_effect_taa.c
+ engines/workbench/workbench_effect_outline.c
engines/workbench/workbench_engine.c
- engines/workbench/workbench_forward.c
engines/workbench/workbench_materials.c
+ engines/workbench/workbench_opaque.c
engines/workbench/workbench_render.c
- engines/workbench/workbench_studiolight.c
+ engines/workbench/workbench_shader.c
+ engines/workbench/workbench_shadow.c
+ engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
engines/external/external_engine.c
engines/gpencil/gpencil_antialiasing.c
@@ -231,6 +230,7 @@ data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
@@ -247,28 +247,32 @@ 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(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 2b11a608bd0..35a45cc97f4 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -42,6 +42,7 @@
#include "eevee_private.h"
#include "GPU_context.h"
+#include "GPU_extensions.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -195,6 +196,16 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache)
return size;
}
+static bool eevee_lightcache_version_check(LightCache *lcache)
+{
+ switch (lcache->type) {
+ case LIGHTCACHE_TYPE_STATIC:
+ return lcache->version == LIGHTCACHE_STATIC_VERSION;
+ default:
+ return false;
+ }
+}
+
static int eevee_lightcache_irradiance_sample_count(LightCache *lcache)
{
int total_irr_samples = 0;
@@ -208,9 +219,23 @@ static int eevee_lightcache_irradiance_sample_count(LightCache *lcache)
void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
{
- LightCache *lcache = eevee->light_cache;
+ LightCache *lcache = eevee->light_cache_data;
if (lcache != NULL) {
+ if (!eevee_lightcache_version_check(lcache)) {
+ BLI_strncpy(eevee->light_cache_info,
+ TIP_("Incompatible Light cache version, please bake again"),
+ sizeof(eevee->light_cache_info));
+ return;
+ }
+
+ if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) {
+ BLI_strncpy(eevee->light_cache_info,
+ TIP_("Error: Light cache is too big for your GPU to be loaded"),
+ sizeof(eevee->light_cache_info));
+ return;
+ }
+
if (lcache->flag & LIGHTCACHE_BAKING) {
BLI_strncpy(
eevee->light_cache_info, TIP_("Baking light cache"), sizeof(eevee->light_cache_info));
@@ -266,8 +291,8 @@ static bool EEVEE_lightcache_validate(const LightCache *light_cache,
(irr_size[2] == light_cache->grid_tx.tex_size[2]) && (grid_len == light_cache->grid_len)) {
int mip_len = log2_floor_u(cube_res) - MIN_CUBE_LOD_LEVEL;
if ((cube_res == light_cache->cube_tx.tex_size[0]) &&
- (cube_len == light_cache->cube_tx.tex_size[2]) && (cube_len == light_cache->cube_len) &&
- (mip_len == light_cache->mips_len)) {
+ (cube_len == light_cache->cube_tx.tex_size[2] / 6) &&
+ (cube_len == light_cache->cube_len) && (mip_len == light_cache->mips_len)) {
return true;
}
}
@@ -283,6 +308,9 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
{
LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache");
+ light_cache->version = LIGHTCACHE_STATIC_VERSION;
+ light_cache->type = LIGHTCACHE_TYPE_STATIC;
+
light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe");
light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid");
@@ -292,13 +320,26 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
light_cache->grid_tx.tex_size[1] = irr_size[1];
light_cache->grid_tx.tex_size[2] = irr_size[2];
- light_cache->cube_tx.tex = DRW_texture_create_2d_array(
- cube_size, cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ int mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL;
+
+ if (GPU_arb_texture_cube_map_array_is_supported()) {
+ light_cache->cube_tx.tex = DRW_texture_create_cube_array(
+ cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ }
+ else {
+ light_cache->cube_tx.tex = DRW_texture_create_2d_array(cube_size,
+ cube_size,
+ cube_len * 6,
+ GPU_R11F_G11F_B10F,
+ DRW_TEX_FILTER | DRW_TEX_MIPMAP,
+ NULL);
+ }
+
light_cache->cube_tx.tex_size[0] = cube_size;
light_cache->cube_tx.tex_size[1] = cube_size;
- light_cache->cube_tx.tex_size[2] = cube_len;
+ light_cache->cube_tx.tex_size[2] = cube_len * 6;
- light_cache->mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL;
+ light_cache->mips_len = mips_len;
light_cache->vis_res = vis_size;
light_cache->ref_res = cube_size;
@@ -315,9 +356,19 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
return light_cache;
}
-void EEVEE_lightcache_load(LightCache *lcache)
+static bool eevee_lightcache_static_load(LightCache *lcache)
{
- if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) {
+ /* We use fallback if a texture is not setup and there is no data to restore it. */
+ if ((!lcache->grid_tx.tex && !lcache->grid_tx.data) ||
+ (!lcache->cube_tx.tex && !lcache->cube_tx.data)) {
+ return false;
+ }
+ /* If cache is too big for this GPU. */
+ if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) {
+ return false;
+ }
+
+ if (lcache->grid_tx.tex == NULL) {
lcache->grid_tx.tex = GPU_texture_create_nD(lcache->grid_tx.tex_size[0],
lcache->grid_tx.tex_size[1],
lcache->grid_tx.tex_size[2],
@@ -333,17 +384,28 @@ void EEVEE_lightcache_load(LightCache *lcache)
GPU_texture_unbind(lcache->grid_tx.tex);
}
- if (lcache->cube_tx.tex == NULL && lcache->cube_tx.data) {
- lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0],
- lcache->cube_tx.tex_size[1],
- lcache->cube_tx.tex_size[2],
- 2,
- lcache->cube_tx.data,
- GPU_R11F_G11F_B10F,
- GPU_DATA_10_11_11_REV,
- 0,
- false,
- NULL);
+ if (lcache->cube_tx.tex == NULL) {
+ if (GPU_arb_texture_cube_map_array_is_supported()) {
+ lcache->cube_tx.tex = GPU_texture_cube_create(lcache->cube_tx.tex_size[0],
+ lcache->cube_tx.tex_size[2] / 6,
+ lcache->cube_tx.data,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_10_11_11_REV,
+ NULL);
+ }
+ else {
+ lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0],
+ lcache->cube_tx.tex_size[1],
+ lcache->cube_tx.tex_size[2],
+ 2,
+ lcache->cube_tx.data,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_10_11_11_REV,
+ 0,
+ false,
+ NULL);
+ }
+
GPU_texture_bind(lcache->cube_tx.tex, 0);
GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
for (int mip = 0; mip < lcache->mips_len; mip++) {
@@ -352,6 +414,25 @@ void EEVEE_lightcache_load(LightCache *lcache)
}
GPU_texture_unbind(lcache->cube_tx.tex);
}
+ return true;
+}
+
+bool EEVEE_lightcache_load(LightCache *lcache)
+{
+ if (lcache == NULL) {
+ return false;
+ }
+
+ if (!eevee_lightcache_version_check(lcache)) {
+ return false;
+ }
+
+ switch (lcache->type) {
+ case LIGHTCACHE_TYPE_STATIC:
+ return eevee_lightcache_static_load(lcache);
+ default:
+ return false;
+ }
}
static void eevee_lightbake_readback_irradiance(LightCache *lcache)
@@ -457,7 +538,7 @@ static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake)
prb->grid_resolution_z;
lbake->grid_len++;
}
- else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE && lbake->cube_len < EEVEE_PROBE_MAX) {
lbake->cube_len++;
}
}
@@ -491,8 +572,7 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
irradiance_pool_size_get(lbake->vis_res, lbake->total_irr_samples, lbake->irr_size);
- lbake->ref_cube_res = octahedral_size_from_cubesize(lbake->rt_res);
-
+ lbake->ref_cube_res = lbake->rt_res;
lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr");
lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr");
@@ -506,12 +586,12 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
/* Ensure Light Cache is ready to accept new data. If not recreate one.
* WARNING: All the following must be threadsafe. It's currently protected
* by the DRW mutex. */
- lbake->lcache = eevee->light_cache;
+ lbake->lcache = eevee->light_cache_data;
/* TODO validate irradiance and reflection cache independently... */
if (!EEVEE_lightcache_validate(
lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size)) {
- eevee->light_cache = lbake->lcache = NULL;
+ eevee->light_cache_data = lbake->lcache = NULL;
}
if (lbake->lcache == NULL) {
@@ -522,10 +602,10 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
lbake->lcache->vis_res = lbake->vis_res;
lbake->own_light_cache = true;
- eevee->light_cache = lbake->lcache;
+ eevee->light_cache_data = lbake->lcache;
}
- EEVEE_lightcache_load(eevee->light_cache);
+ EEVEE_lightcache_load(eevee->light_cache_data);
lbake->lcache->flag |= LIGHTCACHE_BAKING;
lbake->lcache->cube_len = 1;
@@ -804,7 +884,7 @@ static void eevee_lightbake_render_world_sample(void *ved, void *user_data)
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
- LightCache *lcache = scene_eval->eevee.light_cache;
+ LightCache *lcache = scene_eval->eevee.light_cache_data;
float clamp = scene_eval->eevee.gi_glossy_clamp;
float filter_quality = scene_eval->eevee.gi_filter_quality;
@@ -920,7 +1000,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
EEVEE_LightGrid *egrid = lbake->grid;
LightProbe *prb = *lbake->probe;
Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
- LightCache *lcache = scene_eval->eevee.light_cache;
+ LightCache *lcache = scene_eval->eevee.light_cache_data;
int grid_loc[3], sample_id, sample_offset, stride;
float pos[3];
const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) ==
@@ -1002,7 +1082,7 @@ static void eevee_lightbake_render_probe_sample(void *ved, void *user_data)
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
- LightCache *lcache = scene_eval->eevee.light_cache;
+ LightCache *lcache = scene_eval->eevee.light_cache_data;
EEVEE_LightProbe *eprobe = lbake->cube;
LightProbe *prb = *lbake->probe;
float clamp = scene_eval->eevee.gi_glossy_clamp;
@@ -1083,7 +1163,7 @@ static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake)
{
Depsgraph *depsgraph = lbake->depsgraph;
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- LightCache *lcache = scene_eval->eevee.light_cache;
+ LightCache *lcache = scene_eval->eevee.light_cache_data;
/* At least one for the world */
int grid_len = 1;
@@ -1106,7 +1186,7 @@ static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake)
EEVEE_LightGrid *egrid = &lcache->grid_data[grid_len++];
EEVEE_lightprobes_grid_data_from_object(ob, egrid, &total_irr_samples);
}
- else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE && cube_len < EEVEE_PROBE_MAX) {
lbake->cube_prb[cube_len] = prb;
EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++];
EEVEE_lightprobes_cube_data_from_object(ob, eprobe);
@@ -1136,11 +1216,11 @@ void EEVEE_lightbake_update(void *custom_data)
Scene *scene_orig = lbake->scene;
/* If a new lightcache was created, free the old one and reference the new. */
- if (lbake->lcache && scene_orig->eevee.light_cache != lbake->lcache) {
- if (scene_orig->eevee.light_cache != NULL) {
- EEVEE_lightcache_free(scene_orig->eevee.light_cache);
+ if (lbake->lcache && scene_orig->eevee.light_cache_data != lbake->lcache) {
+ if (scene_orig->eevee.light_cache_data != NULL) {
+ EEVEE_lightcache_free(scene_orig->eevee.light_cache_data);
}
- scene_orig->eevee.light_cache = lbake->lcache;
+ scene_orig->eevee.light_cache_data = lbake->lcache;
lbake->own_light_cache = false;
}
@@ -1182,6 +1262,12 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
lbake->do_update = do_update;
lbake->progress = progress;
+ if (G.background) {
+ /* Make sure to init GL capabilities before counting probes. */
+ eevee_lightbake_context_enable(lbake);
+ eevee_lightbake_context_disable(lbake);
+ }
+
/* Count lightprobes */
eevee_lightbake_count_probes(lbake);
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index ede2de13dce..0db36ce0c2e 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -60,7 +60,7 @@ struct LightCache *EEVEE_lightcache_create(const int grid_len,
const int vis_size,
const int irr_size[3]);
void EEVEE_lightcache_free(struct LightCache *lcache);
-void EEVEE_lightcache_load(struct LightCache *lcache);
+bool EEVEE_lightcache_load(struct LightCache *lcache);
void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee);
#endif /* __EEVEE_LIGHTCACHE_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 4fbecfe3120..61ca2317572 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -37,6 +37,7 @@
#include "GPU_material.h"
#include "GPU_texture.h"
+#include "GPU_extensions.h"
#include "DEG_depsgraph_query.h"
@@ -171,32 +172,28 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
memset(stl->g_data->world_views, 0, sizeof(stl->g_data->world_views));
memset(stl->g_data->planar_views, 0, sizeof(stl->g_data->planar_views));
- /* Use fallback if we don't have gpu texture allocated an we cannot restore them. */
- bool use_fallback_lightcache = (scene_eval->eevee.light_cache == NULL) ||
- ((scene_eval->eevee.light_cache->grid_tx.tex == NULL) &&
- (scene_eval->eevee.light_cache->grid_tx.data == NULL)) ||
- ((scene_eval->eevee.light_cache->cube_tx.tex == NULL) &&
- (scene_eval->eevee.light_cache->cube_tx.data == NULL));
-
- if (use_fallback_lightcache && (sldata->fallback_lightcache == NULL)) {
+ if (EEVEE_lightcache_load(scene_eval->eevee.light_cache_data)) {
+ stl->g_data->light_cache = scene_eval->eevee.light_cache_data;
+ }
+ else {
+ if (!sldata->fallback_lightcache) {
#if defined(IRRADIANCE_SH_L2)
- int grid_res = 4;
+ int grid_res = 4;
#elif defined(IRRADIANCE_CUBEMAP)
- int grid_res = 8;
+ int grid_res = 8;
#elif defined(IRRADIANCE_HL2)
- int grid_res = 4;
+ int grid_res = 4;
#endif
- int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution);
- int vis_res = scene_eval->eevee.gi_visibility_resolution;
- sldata->fallback_lightcache = EEVEE_lightcache_create(
- 1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1});
+ sldata->fallback_lightcache = EEVEE_lightcache_create(
+ 1,
+ 1,
+ scene_eval->eevee.gi_cubemap_resolution,
+ scene_eval->eevee.gi_visibility_resolution,
+ (int[3]){grid_res, grid_res, 1});
+ }
+ stl->g_data->light_cache = sldata->fallback_lightcache;
}
- stl->g_data->light_cache = (use_fallback_lightcache) ? sldata->fallback_lightcache :
- scene_eval->eevee.light_cache;
-
- EEVEE_lightcache_load(stl->g_data->light_cache);
-
if (!sldata->probes) {
sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
@@ -255,7 +252,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
- DRW_shgroup_call(grp, geom, NULL);
+ DRW_shgroup_call_instances(grp, NULL, geom, 6);
}
{
@@ -508,8 +505,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
EEVEE_LightProbesInfo *pinfo = sldata->probes;
LightProbe *probe = (LightProbe *)ob->data;
- if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) ||
- (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) ||
+ if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= EEVEE_PROBE_MAX) ||
+ (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= EEVEE_PROBE_MAX) ||
(probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR)) {
printf("Too many probes in the view !!!\n");
return;
@@ -762,7 +759,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
/* For shading, save max level of the octahedron map */
- sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len - 1.0f;
+ sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len;
sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL;
sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res;
sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing);
@@ -785,15 +782,15 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
if (draw_ctx->scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) {
Scene *scene_orig = DEG_get_input_scene(draw_ctx->depsgraph);
- if (scene_orig->eevee.light_cache != NULL) {
+ if (scene_orig->eevee.light_cache_data != NULL) {
if (pinfo->do_grid_update) {
- scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID;
+ scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID;
}
- /* If we update grid we need to update the cube-maps too.
- * So always refresh cube-maps. */
- scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE;
- /* Tag the light-cache to auto update. */
- scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_AUTO;
+ /* If we update grid we need to update the cubemaps too.
+ * So always refresh cubemaps. */
+ scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE;
+ /* Tag the lightcache to auto update. */
+ scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_AUTO;
/* Use a notifier to trigger the operator after drawing. */
WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig);
}
@@ -1077,7 +1074,7 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
pinfo->texel_size = 1.0f / (float)mipsize;
pinfo->padding_size = (i == maxlevel) ? 0 : (float)(1 << (maxlevel - i - 1));
pinfo->padding_size *= pinfo->texel_size;
- pinfo->layer = probe_idx;
+ pinfo->layer = probe_idx * 6;
pinfo->roughness = i / (float)maxlevel;
pinfo->roughness *= pinfo->roughness; /* Disney Roughness */
pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index 7be6fc2d030..a725a3583f3 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -76,7 +76,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
effects->lookdev_view = NULL;
- if (LOOK_DEV_OVERLAY_ENABLED(v3d)) {
+ if (eevee_hdri_preview_overlay_enabled(v3d)) {
/* Viewport / Spheres size. */
const rcti *rect;
rcti fallback_rect;
@@ -116,7 +116,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
EEVEE_shaders_background_studiolight_sh_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution);
+ int cube_res = scene_eval->eevee.gi_cubemap_resolution;
/* If one of the component is missing we start from scratch. */
if ((stl->lookdev_grid_data == NULL) || (stl->lookdev_cube_data == NULL) ||
@@ -228,7 +228,7 @@ void EEVEE_lookdev_draw(EEVEE_Data *vedata)
const DRWContextState *draw_ctx = DRW_context_state_get();
- if (psl->lookdev_diffuse_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) {
+ if (psl->lookdev_diffuse_pass && eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) {
/* Config renderer. */
EEVEE_CommonUniformBuffer *common = &sldata->common_data;
common->la_num_light = 0;
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index a37c063adf6..230a0725493 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -89,6 +89,7 @@ extern char datatoc_common_hair_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_lit_surface_frag_glsl[];
extern char datatoc_lit_surface_vert_glsl[];
extern char datatoc_raytrace_lib_glsl[];
@@ -618,6 +619,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
datatoc_raytrace_lib_glsl,
datatoc_ssr_lib_glsl,
datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_irradiance_lib_glsl,
datatoc_lightprobe_lib_glsl,
datatoc_ltc_lib_glsl,
@@ -641,6 +643,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
datatoc_bsdf_common_lib_glsl,
datatoc_ambient_occlusion_lib_glsl,
datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_irradiance_lib_glsl,
datatoc_lightprobe_lib_glsl,
datatoc_ltc_lib_glsl,
@@ -776,6 +779,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
wo,
engine,
options,
+ false,
e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
@@ -796,6 +800,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
wo,
engine,
options,
+ false,
e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
@@ -819,6 +824,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
wo,
engine,
options,
+ true,
e_data.vert_volume_shader_str,
e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
@@ -853,6 +859,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
ma,
engine,
options,
+ false,
e_data.vert_shader_str,
NULL,
e_data.frag_shader_lib,
@@ -880,6 +887,7 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
ma,
engine,
options,
+ true,
e_data.vert_volume_shader_str,
e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
@@ -916,6 +924,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
ma,
engine,
options,
+ false,
(is_shadow) ? e_data.vert_shadow_shader_str :
e_data.vert_shader_str,
NULL,
@@ -945,6 +954,7 @@ struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
ma,
engine,
options,
+ false,
e_data.vert_shader_str,
NULL,
e_data.frag_shader_lib,
@@ -1256,7 +1266,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
- if (LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) {
+ if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) {
DRWShadingGroup *shgrp;
struct GPUBatch *sphere = DRW_cache_sphere_get();
@@ -1919,7 +1929,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
* to know if the material has a "volume nodetree".
*/
bool use_volume_material = (gpumat_array[0] &&
- GPU_material_use_domain_volume(gpumat_array[0]));
+ GPU_material_has_volume_output(gpumat_array[0]));
if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) {
/* Get per-material split surface */
@@ -1968,7 +1978,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* Do not render surface if we are rendering a volume object
* and do not have a surface closure. */
if (use_volume_material &&
- (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i]))) {
+ (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) {
continue;
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 5ffea393e1f..0f084ba306b 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -78,6 +78,8 @@ extern struct DrawEngineType draw_engine_eevee_type;
SHADER_IRRADIANCE
/* clang-format on */
+#define EEVEE_PROBE_MAX min_ii(MAX_PROBE, GPU_max_texture_layers() / 6)
+
#define SWAP_DOUBLE_BUFFERS() \
{ \
if (effects->swap_double_buffer) { \
@@ -123,9 +125,21 @@ extern struct DrawEngineType draw_engine_eevee_type;
} \
((void)0)
-#define LOOK_DEV_OVERLAY_ENABLED(v3d) \
- ((v3d) && (v3d->shading.type == OB_MATERIAL) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && \
- (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV))
+BLI_INLINE bool eevee_hdri_preview_overlay_enabled(View3D *v3d)
+{
+ /* Only show the HDRI Preview in Shading Preview in the Viewport. */
+ if (v3d == NULL || v3d->shading.type != OB_MATERIAL) {
+ return false;
+ }
+
+ /* Only show the HDRI Preview when viewing the Combined render pass */
+ if (v3d->shading.render_pass != SCE_PASS_COMBINED) {
+ return false;
+ }
+
+ return ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV);
+}
+
#define USE_SCENE_LIGHT(v3d) \
((!v3d) || \
((v3d->shading.type == OB_MATERIAL) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || \
@@ -137,19 +151,6 @@ extern struct DrawEngineType draw_engine_eevee_type;
((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0))))
#define MIN_CUBE_LOD_LEVEL 3
-
-BLI_INLINE int octahedral_size_from_cubesize(int cube_size)
-{
- int cube_pixel_count = square_i(cube_size) * 6;
- int octa_size = (int)ceilf(sqrtf(cube_pixel_count));
- int lod_count = log2_floor_u(octa_size) - MIN_CUBE_LOD_LEVEL;
- /* Find lowest lod size and grow back to avoid having non matching mipsizes that would
- * break trilinear interpolation. */
- octa_size /= 1 << lod_count;
- octa_size *= 1 << lod_count;
- return octa_size;
-}
-
#define MAX_PLANAR_LOD_LEVEL 9
/* All the renderpasses that use the GPUMaterial for accumulation */
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index d231edf1383..e875187bdbf 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -54,6 +54,7 @@ extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_effect_ssr_frag_glsl[];
extern char datatoc_lightprobe_lib_glsl[];
extern char datatoc_raytrace_lib_glsl[];
@@ -67,6 +68,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
datatoc_bsdf_sampling_lib_glsl,
datatoc_ambient_occlusion_lib_glsl,
datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_lightprobe_lib_glsl,
datatoc_raytrace_lib_glsl,
datatoc_effect_ssr_frag_glsl);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 2d91e4bb4bd..50b7c5c5f97 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -88,6 +88,7 @@ extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lightprobe_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_cubemap_lib_glsl[];
/* Velocity Resolve */
extern char datatoc_effect_velocity_resolve_frag_glsl[];
@@ -196,6 +197,7 @@ GPUShader *EEVEE_shaders_background_studiolight_sh_get(void)
{
if (e_data.probe_background_studiolight_sh == NULL) {
char *frag_str = BLI_string_joinN(datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_lightprobe_lib_glsl,
@@ -217,6 +219,7 @@ GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void)
{
if (e_data.probe_cube_display_sh == NULL) {
char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
@@ -238,6 +241,7 @@ GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void)
{
if (e_data.probe_grid_display_sh == NULL) {
char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 98e799acb5e..bab89a8a87b 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -41,6 +41,7 @@ extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_lights_lib_glsl[];
extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
@@ -59,6 +60,7 @@ static void eevee_create_shader_subsurface(void)
datatoc_bsdf_sampling_lib_glsl,
datatoc_raytrace_lib_glsl,
datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_lights_lib_glsl,
datatoc_effect_translucency_frag_glsl);
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index d11e93bbc3f..8c1c72a3c20 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -72,6 +72,7 @@ extern char datatoc_bsdf_common_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_cubemap_lib_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lights_lib_glsl[];
extern char datatoc_volumetric_accum_frag_glsl[];
@@ -99,6 +100,7 @@ static void eevee_create_shader_volumes(void)
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
datatoc_irradiance_lib_glsl,
datatoc_lights_lib_glsl,
datatoc_volumetric_lib_glsl);
@@ -141,10 +143,10 @@ static void eevee_create_shader_volumes(void)
e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl,
NULL);
- float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, color);
+ const float density[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, density);
- float flame = 0.0f;
+ const float flame = 0.0f;
e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame);
}
@@ -351,7 +353,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
!LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) {
struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo);
- if (GPU_material_use_domain_volume(mat)) {
+ if (GPU_material_has_volume_output(mat)) {
grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps);
}
@@ -367,9 +369,11 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
/* Fix principle volumetric not working with world materials. */
- DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density);
- DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame);
- DRW_shgroup_uniform_vec2_copy(grp, "unftemperature", (float[2]){0.0f, 1.0f});
+ ListBase gpu_grids = GPU_material_volume_grids(mat);
+ for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid;
+ gpu_grid = gpu_grid->next) {
+ DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density);
+ }
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
@@ -445,6 +449,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1);
DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1);
+ ListBase gpu_grids = GPU_material_volume_grids(mat);
/* Smoke Simulation */
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
(md = modifiers_findByType(ob, eModifierType_Fluid)) &&
@@ -476,10 +481,25 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd));
}
- DRW_shgroup_uniform_texture_ref(
- grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density);
- DRW_shgroup_uniform_texture_ref(
- grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame);
+ for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) {
+ if (STREQ(gpu_grid->name, "density")) {
+ DRW_shgroup_uniform_texture_ref(grp,
+ gpu_grid->sampler_name,
+ mds->tex_density ? &mds->tex_density :
+ &e_data.dummy_density);
+ }
+ else if (STREQ(gpu_grid->name, "color")) {
+ DRW_shgroup_uniform_texture_ref(
+ grp, gpu_grid->sampler_name, mds->tex_color ? &mds->tex_color : &e_data.dummy_density);
+ }
+ else if (STREQ(gpu_grid->name, "flame") || STREQ(gpu_grid->name, "temperature")) {
+ DRW_shgroup_uniform_texture_ref(
+ grp, gpu_grid->sampler_name, mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame);
+ }
+ else {
+ DRW_shgroup_uniform_texture_ref(grp, gpu_grid->sampler_name, &e_data.dummy_density);
+ }
+ }
/* Constant Volume color. */
bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
@@ -489,13 +509,13 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1);
/* Output is such that 0..1 maps to 0..1000K */
- DRW_shgroup_uniform_vec2(grp, "unftemperature", &mds->flame_ignition, 1);
+ DRW_shgroup_uniform_vec2(grp, "volumeTemperature", &mds->flame_ignition, 1);
}
else {
- DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density);
- DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame);
+ for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) {
+ DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density);
+ }
DRW_shgroup_uniform_vec3(grp, "volumeColor", white, 1);
- DRW_shgroup_uniform_vec2(grp, "unftemperature", (float[2]){0.0f, 1.0f}, 1);
}
/* TODO Reduce to number of slices intersecting. */
diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl
new file mode 100644
index 00000000000..90272400915
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl
@@ -0,0 +1,130 @@
+
+#ifdef GPU_ARB_texture_cube_map_array
+
+# define textureLod_cubemapArray(tex, co, lod) textureLod(tex, co, lod)
+
+#else
+
+/* Fallback implementation for hardware not supporting cubemap arrays. */
+# define samplerCubeArray sampler2DArray
+
+float cubemap_face_index(vec3 P)
+{
+ vec3 aP = abs(P);
+ if (all(greaterThan(aP.xx, aP.yz))) {
+ return (P.x > 0.0) ? 0.0 : 1.0;
+ }
+ else if (all(greaterThan(aP.yy, aP.xz))) {
+ return (P.y > 0.0) ? 2.0 : 3.0;
+ }
+ else {
+ return (P.z > 0.0) ? 4.0 : 5.0;
+ }
+}
+
+vec2 cubemap_face_coord(vec3 P, float face)
+{
+ if (face < 2.0) {
+ return (P.zy / P.x) * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
+ }
+ else if (face < 4.0) {
+ return (P.xz / P.y) * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
+ }
+ else {
+ return (P.xy / P.z) * vec2(0.5, -sign(P.z) * 0.5) + 0.5;
+ }
+}
+
+vec3 cubemap_adj_x(float face)
+{
+ bool y_axis = (face == 2.0 || face == 3.0);
+ return y_axis ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+}
+
+vec3 cubemap_adj_y(float face)
+{
+ bool x_axis = (face < 2.0);
+ return x_axis ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+}
+
+vec3 cubemap_adj_xy(float face)
+{
+ if (face < 2.0) {
+ return vec3(0.0, 1.0, 1.0);
+ }
+ else if (face < 4.0) {
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return vec3(1.0, 1.0, 0.0);
+ }
+}
+
+vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod)
+{
+ /* Manual Cube map Layer indexing. */
+ float face = cubemap_face_index(cubevec.xyz);
+ vec2 uv = cubemap_face_coord(cubevec.xyz, face);
+ vec3 coord = vec3(uv, cubevec.w * 6.0 + face);
+
+ vec4 col = textureLod(tex, coord, lod);
+
+ float cube_size = float(textureSize(tex, int(lod)).x);
+
+ vec2 uv_border = (abs(uv - 0.5) + (0.5 / cube_size - 0.5)) * 2.0 * cube_size;
+ bvec2 border = greaterThan(uv_border, vec2(0.0));
+ if (all(border)) {
+ /* Corners case. */
+ vec3 cubevec_adj;
+ float face_adj;
+ /* Get the other face coords. */
+ cubevec_adj = cubevec.xyz * cubemap_adj_x(face);
+ face_adj = cubemap_face_index(cubevec_adj);
+ /* Still use the original cubevec to get the outer texels or the face. */
+ uv = cubemap_face_coord(cubevec.xyz, face_adj);
+ coord = vec3(uv, cubevec.w * 6.0 + face_adj);
+ vec4 col1 = textureLod(tex, coord, lod);
+
+ /* Get the 3rd face coords. */
+ cubevec_adj = cubevec.xyz * cubemap_adj_y(face);
+ face_adj = cubemap_face_index(cubevec_adj);
+ /* Still use the original cubevec to get the outer texels or the face. */
+ uv = cubemap_face_coord(cubevec.xyz, face_adj);
+ coord = vec3(uv, cubevec.w * 6.0 + face_adj);
+ vec4 col2 = textureLod(tex, coord, lod);
+
+ /* Mix all colors to get the corner color. */
+ vec4 col3 = (col + col1 + col2) / 3.0;
+
+ vec2 mix_fac = uv_border * 0.5;
+ return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y);
+ }
+ else if (any(border)) {
+ /* Edges case. */
+ /* Get the other face coords. */
+ vec3 cubevec_adj = cubevec.xyz * cubemap_adj_xy(face);
+ face = cubemap_face_index(cubevec_adj);
+ /* Still use the original cubevec to get the outer texels or the face. */
+ uv = cubemap_face_coord(cubevec.xyz, face);
+ coord = vec3(uv, cubevec.w * 6.0 + face);
+
+ float mix_fac = max(uv_border.x, uv_border.y) * 0.5;
+ return mix(col, textureLod(tex, coord, lod), mix_fac);
+ }
+ else {
+ return col;
+ }
+}
+
+vec4 textureLod_cubemapArray(sampler2DArray tex, vec4 cubevec, float lod)
+{
+ float lod1 = floor(lod);
+ float lod2 = ceil(lod);
+
+ vec4 col_lod1 = cubemap_seamless(tex, cubevec, lod1);
+ vec4 col_lod2 = cubemap_seamless(tex, cubevec, lod2);
+
+ return mix(col_lod1, col_lod2, lod - lod1);
+}
+
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
index a852dd47872..96fe94fc41e 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
@@ -15,6 +15,5 @@ void main()
vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr)));
vec3 world_ref = mat3(ViewMatrixInverse) * reflect(vec3(0.0, 0.0, -1.0), view_nor);
- FragColor = vec4(textureLod_octahedron(probeCubes, vec4(world_ref, pid), 0.0, prbLodCubeMax).rgb,
- 1.0);
+ FragColor = vec4(textureLod_cubemapArray(probeCubes, vec4(world_ref, pid), 0.0).rgb, 1.0);
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
index 06c31272ecd..00eb3c7e200 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
@@ -33,29 +33,9 @@ vec3 octahedral_to_cubemap_proj(vec2 co)
void main()
{
- vec2 uvs = gl_FragCoord.xy * texelSize;
-
- /* Add a N pixel border to ensure filtering is correct
- * for N mipmap levels. */
- uvs = (uvs - paddingSize) / (1.0 - 2.0 * paddingSize);
-
- /* edge mirroring : only mirror if directly adjacent
- * (not diagonally adjacent) */
- vec2 m = abs(uvs - 0.5) + 0.5;
- vec2 f = floor(m);
- if (f.x - f.y != 0.0) {
- uvs = 1.0 - uvs;
- }
-
- /* clamp to [0-1] */
- uvs = fract(uvs);
-
- /* get cubemap vector */
- vec3 cubevec = octahedral_to_cubemap_proj(uvs);
-
vec3 N, T, B, V;
- vec3 R = normalize(cubevec);
+ vec3 R = normalize(worldPosition);
/* Isotropic assumption */
N = V = R;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index ab205b78274..6c6db88139b 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -1,7 +1,7 @@
/* ----------- Uniforms --------- */
uniform sampler2DArray probePlanars;
-uniform sampler2DArray probeCubes;
+uniform samplerCubeArray probeCubes;
/* ----------- Structures --------- */
@@ -172,15 +172,12 @@ vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness)
float fac = saturate(original_roughness * 2.0 - 1.0);
R = mix(intersection, R, fac * fac);
- return textureLod_octahedron(
- probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax, prbLodCubeMax)
- .rgb;
+ return textureLod_cubemapArray(probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax).rgb;
}
vec3 probe_evaluate_world_spec(vec3 R, float roughness)
{
- return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax)
- .rgb;
+ return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb;
}
vec3 probe_evaluate_planar(
diff --git a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl
index bfb6bc890ec..e05cc2719fa 100644
--- a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl
@@ -18,21 +18,3 @@ vec2 mapping_octahedron(vec3 cubevec, vec2 texel_size)
return uvs;
}
-
-vec4 textureLod_octahedron(sampler2DArray tex, vec4 cubevec, float lod, float lod_max)
-{
- vec2 texelSize = 1.0 / vec2(textureSize(tex, int(lod_max)));
-
- vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize);
-
- return textureLod(tex, vec3(uvs, cubevec.w), lod);
-}
-
-vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec)
-{
- vec2 texelSize = 1.0 / vec2(textureSize(tex, 0));
-
- vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize);
-
- return texture(tex, vec3(uvs, cubevec.w));
-}
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 743171b09fb..3459685f504 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -61,7 +61,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob)
/* TODO: This does not work quite well if you use
* strokes not aligned with the object axes. Maybe we could try to
* compute the minimum axis of all strokes. But this would be more
- * computationaly heavy and should go into the GPData evaluation. */
+ * computationally heavy and should go into the GPData evaluation. */
BoundBox *bbox = BKE_object_boundbox_get(ob);
/* Convert bbox to matrix */
float mat[4][4], size[3], center[3];
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 77baadfc83a..625af8cec6f 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -108,7 +108,7 @@ static void gpencil_object_random_color_get(const Object *ob, float r_color[3])
static void gpencil_shade_color(float color[3])
{
- /* This is scene refered color, not gamma corrected and not per perceptual.
+ /* This is scene refereed color, not gamma corrected and not per perceptual.
* So we lower the threshold a bit. (1.0 / 3.0) */
if (color[0] + color[1] + color[2] > 1.1) {
add_v3_fl(color, -0.25f);
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index d47d6f8a836..37aef5a633a 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -710,7 +710,7 @@ void GPENCIL_cache_finish(void *ved)
if (pd->use_mask_fb) {
/* We need an extra depth to not disturb the normal drawing.
- * The color_tx is needed for framebuffer cmpleteness. */
+ * The color_tx is needed for frame-buffer completeness. */
GPUTexture *color_tx, *depth_tx;
depth_tx = DRW_texture_pool_query_2d(
size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index cfa0fa9eb1a..740ca42800e 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -382,9 +382,6 @@ static void OVERLAY_cache_finish(void *vedata)
DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
GPU_framebuffer_ensure_config(
- &dfbl->default_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
- GPU_framebuffer_ensure_config(
&dfbl->in_front_fb,
{GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
}
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index e77a0a143a9..0395f6890bd 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -33,7 +33,7 @@
#include "overlay_private.h"
-/* Returns the normal plane in ndc space. */
+/* Returns the normal plane in NDC space. */
static void gpencil_depth_plane(Object *ob, float r_plane[4])
{
/* TODO put that into private data. */
@@ -42,11 +42,11 @@ static void gpencil_depth_plane(Object *ob, float r_plane[4])
float *camera_z_axis = viewinv[2];
float *camera_pos = viewinv[3];
- /* Find the normal most likely to represent the gpObject. */
+ /* Find the normal most likely to represent the grease pencil object. */
/* TODO: This does not work quite well if you use
* strokes not aligned with the object axes. Maybe we could try to
* compute the minimum axis of all strokes. But this would be more
- * computationaly heavy and should go into the GPData evaluation. */
+ * computationally heavy and should go into the GPData evaluation. */
BoundBox *bbox = BKE_object_boundbox_get(ob);
/* Convert bbox to matrix */
float mat[4][4], size[3], center[3];
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index 722055c36f0..6b0e5e0b72e 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -68,22 +68,17 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
OVERLAY_shader_wireframe();
for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) {
- /* Only do stencil test if stencil buffer is written by the render engine. */
- DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL;
DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
DRWPass *pass;
- uint stencil_mask;
if (xray == 0) {
- DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state);
+ DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state);
pass = psl->wireframe_ps;
- stencil_mask = 0xFF;
}
else {
DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state);
pass = psl->wireframe_xray_ps;
- stencil_mask = 0x00;
}
for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
@@ -94,17 +89,14 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
- DRW_shgroup_stencil_mask(grp, stencil_mask);
pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
- DRW_shgroup_stencil_mask(grp, stencil_mask);
}
pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
- DRW_shgroup_stencil_mask(grp, stencil_mask);
}
if (is_material_shmode) {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
deleted file mode 100644
index a0e04f252e2..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
+++ /dev/null
@@ -1,81 +0,0 @@
-out vec4 fragColor;
-
-uniform sampler2D depthBuffer;
-uniform sampler2D colorBuffer;
-uniform sampler2D normalBuffer;
-uniform usampler2D objectId;
-
-uniform vec2 invertedViewportSize;
-uniform mat4 WinMatrix; /* inverse WinMatrix */
-
-uniform vec4 viewvecs[3];
-uniform vec4 ssao_params;
-uniform vec4 ssao_settings;
-uniform vec2 curvature_settings;
-uniform sampler2D ssao_jitter;
-
-layout(std140) uniform samples_block
-{
- vec4 ssao_samples[500];
-};
-
-#define ssao_samples_num ssao_params.x
-#define jitter_tilling ssao_params.yz
-#define ssao_iteration ssao_params.w
-
-#define ssao_distance ssao_settings.x
-#define ssao_factor_cavity ssao_settings.y
-#define ssao_factor_edge ssao_settings.z
-#define ssao_attenuation ssao_settings.w
-
-vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
-{
- if (WinMatrix[3][3] == 0.0) {
- /* Perspective */
- float d = 2.0 * depth - 1.0;
-
- float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
-
- return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
- }
- else {
- /* Orthographic */
- vec3 offset = vec3(uvcoords, depth);
-
- return viewvecs[0].xyz + offset * viewvecs[1].xyz;
- }
-}
-
-/* forward declaration */
-void ssao_factors(in float depth,
- in vec3 normal,
- in vec3 position,
- in vec2 screenco,
- out float cavities,
- out float edges);
-
-void main()
-{
- vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize;
- ivec2 texel = ivec2(gl_FragCoord.xy);
-
- float cavity = 0.0, edges = 0.0, curvature = 0.0;
-
-#ifdef USE_CAVITY
- float depth = texelFetch(depthBuffer, texel, 0).x;
- vec3 position = get_view_space_from_depth(screenco, depth);
- vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg);
-
- ssao_factors(depth, normal_viewport, position, screenco, cavity, edges);
-#endif
-
-#ifdef USE_CURVATURE
- curvature = calculate_curvature(
- objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y);
-#endif
-
- float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
-
- /* Using UNORM render target so compress the range. */
- fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE);
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
index 376b19cdd1b..87d04144cde 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -1,77 +1,87 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
-/* from The Alchemy screen-space ambient obscurance algorithm
+layout(std140) uniform samples_block
+{
+ vec4 samples_coords[512];
+};
+
+uniform sampler2D cavityJitter;
+
+/* From The Alchemy screen-space ambient obscurance algorithm
* http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
-void ssao_factors(in float depth,
- in vec3 normal,
- in vec3 position,
- in vec2 screenco,
- out float cavities,
- out float edges)
+void cavity_compute(vec2 screenco,
+ sampler2D depthBuffer,
+ sampler2D normalBuffer,
+ 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) {
+
+ float depth = texture(depthBuffer, screenco).x;
+
+ /* Early out if background and infront. */
+ if (depth == 1.0 || depth == 0.0) {
return;
}
- /* take the normalized ray direction here */
- vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
+ vec3 position = view_position_from_depth(screenco, depth, world_data.viewvecs, ProjectionMatrix);
+ vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco));
+
+ vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale;
+ vec3 noise = texture(cavityJitter, jitter_co).rgb;
/* find the offset in screen space by multiplying a point
* in camera space at the depth of the point by the projection matrix. */
vec2 offset;
- float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
- offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
- offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
+ float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
+ offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord;
+ offset.y = ProjectionMatrix[1][1] * world_data.cavity_distance / homcoord;
/* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
offset *= 0.5;
- int num_samples = int(ssao_samples_num);
-
/* Note. Putting noise usage here to put some ALU after texture fetch. */
vec2 rotX = noise.rg;
vec2 rotY = vec2(-rotX.y, rotX.x);
- for (int x = 0; x < num_samples; x++) {
- int sample_index = x + (int(ssao_iteration) * num_samples);
- if (sample_index > 500) {
- continue;
- }
- /* ssao_samples[x].xy is sample direction (normalized).
- * ssao_samples[x].z is sample distance from disk center. */
-
+ int sample_start = world_data.cavity_sample_start;
+ int sample_end = world_data.cavity_sample_end;
+ for (int i = sample_start; i < sample_end && i < 512; i++) {
+ /* sample_coord.xy is sample direction (normalized).
+ * sample_coord.z is sample distance from disk center. */
+ vec3 sample_coord = samples_coords[i].xyz;
/* Rotate with random direction to get jittered result. */
- vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX),
- dot(ssao_samples[sample_index].xy, rotY));
- dir_jittered.xy *= ssao_samples[sample_index].z + noise.b;
+ vec2 dir_jittered = vec2(dot(sample_coord.xy, rotX), dot(sample_coord.xy, rotY));
+ dir_jittered.xy *= sample_coord.z + noise.b;
- vec2 uvcoords = screenco.xy + dir_jittered * offset;
-
- if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) {
+ vec2 uvcoords = screenco + dir_jittered * offset;
+ /* Out of screen case. */
+ if (any(greaterThan(abs(uvcoords - 0.5), vec2(0.5)))) {
continue;
}
-
- float depth_new = texture(depthBuffer, uvcoords).r;
-
+ /* Sample depth. */
+ float s_depth = texture(depthBuffer, uvcoords).r;
/* Handle Background case */
- bool is_background = (depth_new == 1.0);
-
+ bool is_background = (s_depth == 1.0);
/* This trick provide good edge effect even if no neighbor is found. */
- vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
+ s_depth = (is_background) ? depth : s_depth;
+ vec3 s_pos = view_position_from_depth(
+ uvcoords, s_depth, world_data.viewvecs, ProjectionMatrix);
if (is_background) {
- pos_new.z -= ssao_distance;
+ s_pos.z -= world_data.cavity_distance;
}
- vec3 dir = pos_new - position;
+ vec3 dir = s_pos - position;
float len = length(dir);
float f_cavities = dot(dir, normal);
float f_edge = -f_cavities;
float f_bias = 0.05 * len + 0.0001;
- float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
+ float attenuation = 1.0 / (len * (1.0 + len * len * world_data.cavity_attenuation));
/* use minor bias here to avoid self shadowing */
if (f_cavities > -f_bias) {
@@ -82,11 +92,10 @@ void ssao_factors(in float depth,
edges += f_edge * attenuation;
}
}
-
- cavities /= ssao_samples_num;
- edges /= ssao_samples_num;
+ cavities *= world_data.cavity_sample_count_inv;
+ edges *= world_data.cavity_sample_count_inv;
/* don't let cavity wash out the surface appearance */
- cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
- edges = edges * ssao_factor_edge;
+ cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0);
+ edges = edges * world_data.cavity_ridge_factor;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
index c0d7719180b..25eaf003e07 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -1,30 +1,16 @@
-#define NO_OBJECT_ID uint(0)
+
#define EPSILON 0.00001
#define M_PI 3.14159265358979323846
#define CAVITY_BUFFER_RANGE 4.0
-/* 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 vec4 dither_mat4x4[4] = vec4[4](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)));
-
-float bayer_dither_noise()
-{
- ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4;
- ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2;
- return dither_mat4x4[tx1.x][tx1.y];
-}
-
#ifdef WORKBENCH_ENCODE_NORMALS
# define WB_Normal vec2
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
-vec3 workbench_normal_decode(WB_Normal enc)
+vec3 workbench_normal_decode(vec4 enc)
{
vec2 fenc = enc.xy * 4.0 - 2.0;
float f = dot(fenc, fenc);
@@ -37,8 +23,9 @@ vec3 workbench_normal_decode(WB_Normal enc)
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
-WB_Normal workbench_normal_encode(vec3 n)
+WB_Normal workbench_normal_encode(bool front_face, vec3 n)
{
+ n = normalize(front_face ? n : -n);
float p = sqrt(n.z * 8.0 + 8.0);
n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0);
return n.xy;
@@ -47,161 +34,64 @@ WB_Normal workbench_normal_encode(vec3 n)
#else
# define WB_Normal vec3
/* Well just do nothing... */
-# define workbench_normal_encode(a) (a)
-# define workbench_normal_decode(a) (a)
+# define workbench_normal_encode(f, a) (a)
+# define workbench_normal_decode(a) (a.xyz)
#endif /* WORKBENCH_ENCODE_NORMALS */
-/* Encoding into the alpha of a RGBA8 UNORM texture. */
+/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */
#define TARGET_BITCOUNT 8u
#define METALLIC_BITS 3u /* Metallic channel is less important. */
#define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS)
-#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS)
/* Encode 2 float into 1 with the desired precision. */
float workbench_float_pair_encode(float v1, float v2)
{
- // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS);
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
/* Same as above because some compiler are dumb af. and think we use mediump int. */
- const int total_mask = 0xFF;
const int v1_mask = 0x1F;
const int v2_mask = 0x7;
int iv1 = int(v1 * float(v1_mask));
int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS);
- return float(iv1 | iv2) * (1.0 / float(total_mask));
+ return float(iv1 | iv2);
}
void workbench_float_pair_decode(float data, out float v1, out float v2)
{
- // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS);
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
/* Same as above because some compiler are dumb af. and think we use mediump int. */
- const int total_mask = 0xFF;
const int v1_mask = 0x1F;
const int v2_mask = 0x7;
- int idata = int(data * float(total_mask));
+ int idata = int(data);
v1 = float(idata & v1_mask) * (1.0 / float(v1_mask));
v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask));
}
-float calculate_transparent_weight(float z, float alpha)
-{
-#if 0
- /* Eq 10 : Good for surfaces with varying opacity (like particles) */
- float a = min(1.0, alpha * 10.0) + 0.01;
- float b = -gl_FragCoord.z * 0.95 + 1.0;
- float w = a * a * a * 3e2 * b * b * b;
-#else
- /* Eq 7 put more emphasis on surfaces closer to the view. */
- // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
- // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
- // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
- /* Same as eq 7, but optimized. */
- float a = abs(z) / 5.0;
- float b = abs(z) / 200.0;
- b *= b;
- float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
-#endif
- return alpha * clamp(w, 1e-2, 3e2);
-}
-
-/* Special function only to be used with calculate_transparent_weight(). */
-float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
+vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat)
{
if (proj_mat[3][3] == 0.0) {
- float d = 2.0 * depth - 1.0;
- return -proj_mat[3][2] / (d + proj_mat[2][2]);
+ return normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz);
}
else {
- /* Return depth from near plane. */
- return depth * viewvecs[1].z;
- }
-}
-
-vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat)
-{
- return (proj_mat[3][3] == 0.0) ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz) :
- vec3(0.0, 0.0, 1.0);
-}
-
-vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
-{
- /* Quick creation of an orthonormal basis */
- float a = 1.0 / (1.0 + I.z);
- float b = -I.x * I.y * a;
- vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
- vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
- vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
- if (flipped) {
- matcap_uv.x = -matcap_uv.x;
+ return vec3(0.0, 0.0, 1.0);
}
- return matcap_uv * 0.496 + 0.5;
}
-bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
+vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat)
{
- vec2 tile_pos = floor(co.xy);
-
- if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
- return false;
-
- float tile = 10.0 * tile_pos.y + tile_pos.x;
- if (tile >= textureSize(map, 0).x)
- return false;
-
- /* Fetch tile information. */
- float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
- if (tile_layer < 0.0)
- return false;
-
- vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
-
- co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
- return true;
-}
+ if (proj_mat[3][3] == 0.0) {
+ /* Perspective */
+ float d = 2.0 * depth - 1.0;
-vec4 workbench_sample_texture(sampler2D image,
- vec2 coord,
- bool nearest_sampling,
- bool premultiplied)
-{
- vec2 tex_size = vec2(textureSize(image, 0).xy);
- /* TODO(fclem) We could do the same with sampler objects.
- * But this is a quick workaround instead of messing with the GPUTexture itself. */
- vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
- vec4 color = texture(image, uv);
+ float zview = -proj_mat[3][2] / (d + proj_mat[2][2]);
- /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
- if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
- color.rgb = color.rgb / color.a;
+ return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
}
+ else {
+ /* Orthographic */
+ vec3 offset = vec3(uvcoords, depth);
- return color;
-}
-
-vec4 workbench_sample_texture_array(sampler2DArray tile_array,
- sampler1DArray tile_data,
- vec2 coord,
- bool nearest_sampling,
- bool premultiplied)
-{
- vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
-
- vec3 uv = vec3(coord, 0);
- if (!node_tex_tile_lookup(uv, tile_array, tile_data))
- return vec4(1.0, 0.0, 1.0, 1.0);
-
- /* TODO(fclem) We could do the same with sampler objects.
- * But this is a quick workaround instead of messing with the GPUTexture itself. */
- uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
- vec4 color = texture(tile_array, uv);
-
- /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
- if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
- color.rgb = color.rgb / color.a;
+ return viewvecs[0].xyz + offset * viewvecs[1].xyz;
}
-
- return color;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
new file mode 100644
index 00000000000..cdb9823096c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
@@ -0,0 +1,44 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
+
+uniform sampler2D materialBuffer;
+uniform sampler2D normalBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
+ vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix);
+ vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st));
+ vec4 mat_data = texture(materialBuffer, uvcoordsvar.st);
+
+ vec3 base_color = mat_data.rgb;
+
+ float roughness, metallic;
+ workbench_float_pair_decode(mat_data.a, roughness, metallic);
+
+#ifdef V3D_LIGHTING_MATCAP
+ /* When using matcaps, mat_data.a is the backface sign. */
+ N = (mat_data.a > 0.0) ? N : -N;
+
+ fragColor.rgb = get_matcap_lighting(base_color, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_STUDIO
+ fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_FLAT
+ fragColor.rgb = base_color;
+#endif
+
+ fragColor.rgb *= get_shadow(N);
+
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
index 22dc906be83..e6bc4c7bbc6 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
@@ -1,6 +1,5 @@
-#ifndef CURVATURE_OFFSET
-# define CURVATURE_OFFSET 1
-#endif
+
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
float curvature_soft_clamp(float curvature, float control)
{
@@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control)
return 0.25 / control;
}
-float calculate_curvature(
- usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley)
+void curvature_compute(vec2 uv,
+ usampler2D objectIdBuffer,
+ sampler2D normalBuffer,
+ out float curvature)
{
- uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r;
- uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r;
- uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r;
- uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r;
+ curvature = 0.0;
+
+ vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
+ uint object_up = texture(objectIdBuffer, uv + offset.zy).r;
+ uint object_down = texture(objectIdBuffer, uv - offset.zy).r;
+ uint object_right = texture(objectIdBuffer, uv + offset.xz).r;
+ uint object_left = texture(objectIdBuffer, uv - offset.xz).r;
+ /* Remove object outlines. */
if ((object_up != object_down) || (object_right != object_left)) {
- return 0.0;
+ return;
}
- vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg;
- vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg;
- vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg;
- vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg;
-
- normal_up = workbench_normal_decode(normal_up).rg;
- normal_down = workbench_normal_decode(normal_down).rg;
- normal_left = workbench_normal_decode(normal_left).rg;
- normal_right = workbench_normal_decode(normal_right).rg;
+ float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g;
+ float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g;
+ float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r;
+ float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r;
- float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r));
+ float normal_diff = (normal_up - normal_down) + (normal_right - normal_left);
if (normal_diff < 0) {
- return -2.0 * curvature_soft_clamp(-normal_diff, valley);
+ curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley);
+ }
+ else {
+ curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge);
}
-
- return 2.0 * curvature_soft_clamp(normal_diff, ridge);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
index 0c984b094d3..5f3283e1643 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
@@ -5,12 +5,42 @@ struct LightData {
};
struct WorldData {
+ vec4 viewvecs[3];
+ vec4 viewport_size;
vec4 object_outline_color;
vec4 shadow_direction_vs;
+ float shadow_focus;
+ float shadow_shift;
+ float shadow_mul;
+ float shadow_add;
+ /* - 16 bytes alignment- */
LightData lights[4];
vec4 ambient_color;
- int num_lights;
- int matcap_orientation;
+
+ int cavity_sample_start;
+ int cavity_sample_end;
+ float cavity_sample_count_inv;
+ float cavity_jitter_scale;
+
+ float cavity_valley_factor;
+ float cavity_ridge_factor;
+ float cavity_attenuation;
+ float cavity_distance;
+
float curvature_ridge;
float curvature_valley;
+ float ui_scale;
+ float _pad0;
+
+ int matcap_orientation;
+ bool use_specular;
+ int _pad1;
+ int _pad2;
+};
+
+#define viewport_size_inv viewport_size.zw
+
+layout(std140) uniform world_block
+{
+ WorldData world_data;
};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl
deleted file mode 100644
index 22fa2babbbf..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-uniform usampler2D objectId;
-
-uniform vec2 invertedViewportSize;
-
-out vec4 fragColor;
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-
-void main()
-{
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
-
-#ifndef V3D_SHADING_OBJECT_OUTLINE
-
- fragColor = vec4(0.0);
-
-#else /* !V3D_SHADING_OBJECT_OUTLINE */
-
- ivec2 texel = ivec2(gl_FragCoord.xy);
- uint object_id = texelFetch(objectId, texel, 0).r;
- float object_outline = calculate_object_outline(objectId, texel, object_id);
-
- fragColor = vec4(world_data.object_outline_color.rgb, 1.0) * (1.0 - object_outline);
-
-#endif /* !V3D_SHADING_OBJECT_OUTLINE */
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
deleted file mode 100644
index fd4cea4279a..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
+++ /dev/null
@@ -1,103 +0,0 @@
-out vec4 fragColor;
-
-uniform usampler2D objectId;
-uniform sampler2D materialBuffer;
-uniform sampler2D normalBuffer;
-/* normalBuffer contains viewport normals */
-uniform sampler2D cavityBuffer;
-uniform sampler2D matcapDiffuseImage;
-uniform sampler2D matcapSpecularImage;
-
-uniform vec2 invertedViewportSize;
-uniform vec4 viewvecs[3];
-uniform float shadowMultiplier;
-uniform float lightMultiplier;
-uniform float shadowShift = 0.1;
-uniform float shadowFocus = 1.0;
-
-uniform vec3 materialSingleColor;
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
-
- float roughness, metallic;
- vec3 base_color;
-
-#ifndef MATDATA_PASS_ENABLED
- base_color = materialSingleColor;
- metallic = 0.0;
- roughness = 0.5;
-#else
- vec4 material_data = texelFetch(materialBuffer, texel, 0);
- base_color = material_data.rgb;
- workbench_float_pair_decode(material_data.a, roughness, metallic);
-#endif
-
-/* Do we need normals */
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg);
-#endif
-
- vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
-
- /* -------- SHADING --------- */
-#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = base_color;
-
-#elif defined(V3D_LIGHTING_MATCAP)
- /* When using matcaps, the metallic is the backface sign. */
- normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport;
- bool flipped = world_data.matcap_orientation != 0;
- vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped);
- vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
-
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
-# else
- vec3 matcap_specular = vec3(0.0);
-# endif
-
- vec3 shaded_color = matcap_diffuse * base_color + matcap_specular;
-
-#elif defined(V3D_LIGHTING_STUDIO)
-
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- vec3 specular_color = mix(vec3(0.05), base_color, metallic);
- vec3 diffuse_color = mix(base_color, vec3(0.0), metallic);
-# else
- roughness = 0.0;
- vec3 specular_color = vec3(0.0);
- vec3 diffuse_color = base_color;
-# endif
-
- vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color, specular_color, roughness, normal_viewport, I_vs);
-#endif
-
- /* -------- POST EFFECTS --------- */
-#ifdef WB_CAVITY
- /* Using UNORM texture so decompress the range */
- shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE;
-#endif
-
-#ifdef V3D_SHADING_SHADOW
- float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz);
- float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor);
- shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
-#endif
-
-#ifdef V3D_SHADING_OBJECT_OUTLINE
- uint object_id = texelFetch(objectId, texel, 0).r;
- float object_outline = calculate_object_outline(objectId, texel, object_id);
- shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline);
-#endif
-
- fragColor = vec4(shaded_color, 1.0);
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
new file mode 100644
index 00000000000..328d50e69e0
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
@@ -0,0 +1,31 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl)
+
+uniform sampler2D depthBuffer;
+uniform sampler2D normalBuffer;
+uniform usampler2D objectIdBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ float cavity = 0.0, edges = 0.0, curvature = 0.0;
+
+#ifdef USE_CAVITY
+ cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges);
+#endif
+
+#ifdef USE_CURVATURE
+ curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature);
+#endif
+
+ float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
+
+ fragColor.rgb = vec3(final_cavity_factor);
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
deleted file mode 100644
index 95ca2c0c297..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
+++ /dev/null
@@ -1,14 +0,0 @@
-
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D colorBuffer;
-uniform vec2 invertedViewportSize;
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- FragColor = FxaaPixelShader(
- uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833);
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
new file mode 100644
index 00000000000..fb6fdb93462
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
@@ -0,0 +1,24 @@
+
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+
+uniform usampler2D objectIdBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
+ vec2 uv = uvcoordsvar.st;
+
+ uint center_id = texture(objectIdBuffer, uv).r;
+ uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r,
+ texture(objectIdBuffer, uv - offset.zy).r,
+ texture(objectIdBuffer, uv + offset.xz).r,
+ texture(objectIdBuffer, uv - offset.xz).r);
+
+ float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25));
+
+ fragColor = world_data.object_outline_color * outline_opacity;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
new file mode 100644
index 00000000000..2dea2fc4883
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
@@ -0,0 +1,44 @@
+
+uniform sampler2D edgesTex;
+uniform sampler2D areaTex;
+uniform sampler2D searchTex;
+uniform sampler2D blendTex;
+uniform sampler2D colorTex;
+uniform float mixFactor;
+uniform float taaSampleCountInv;
+
+in vec2 uvs;
+in vec2 pixcoord;
+in vec4 offset[3];
+
+#if SMAA_STAGE == 0
+out vec2 fragColor;
+#else
+out vec4 fragColor;
+#endif
+
+void main()
+{
+#if SMAA_STAGE == 0
+ /* Detect edges in color and revealage buffer. */
+ fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ /* Discard if there is no edge. */
+ if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ discard;
+ }
+
+#elif SMAA_STAGE == 1
+ fragColor = SMAABlendingWeightCalculationPS(
+ uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
+
+#elif SMAA_STAGE == 2
+ fragColor = vec4(0.0);
+ if (mixFactor > 0.0) {
+ fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
+ }
+ if (mixFactor < 1.0) {
+ fragColor += texture(colorTex, uvs) * (1.0 - mixFactor);
+ }
+ fragColor *= taaSampleCountInv;
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
new file mode 100644
index 00000000000..07734d19972
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
@@ -0,0 +1,21 @@
+
+out vec2 uvs;
+out vec2 pixcoord;
+out vec4 offset[3];
+
+void main()
+{
+ int v = gl_VertexID % 3;
+ float x = -1.0 + float((v & 1) << 2);
+ float y = -1.0 + float((v & 2) << 1);
+ gl_Position = vec4(x, y, 1.0, 1.0);
+ uvs = (gl_Position.xy + 1.0) * 0.5;
+
+#if SMAA_STAGE == 0
+ SMAAEdgeDetectionVS(uvs, offset);
+#elif SMAA_STAGE == 1
+ SMAABlendingWeightCalculationVS(uvs, pixcoord, offset);
+#elif SMAA_STAGE == 2
+ SMAANeighborhoodBlendingVS(uvs, offset[0]);
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
index 5795268f794..b877c2c3f76 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
@@ -1,14 +1,11 @@
-uniform sampler2D historyBuffer;
+
uniform sampler2D colorBuffer;
-out vec4 colorOutput;
+in vec4 uvcoordsvar;
-uniform float mixFactor;
+out vec4 fragColor;
void main()
{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- vec4 color_buffer = texelFetch(colorBuffer, texel, 0);
- vec4 history_buffer = texelFetch(historyBuffer, texel, 0);
- colorOutput = mix(history_buffer, color_buffer, mixFactor);
+ fragColor = texture(colorBuffer, uvcoordsvar.st);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl
deleted file mode 100644
index 0a4d64b37ad..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-out vec4 fragColor;
-
-uniform usampler2D objectId;
-uniform sampler2D transparentAccum;
-uniform sampler2D transparentRevealage;
-uniform vec2 invertedViewportSize;
-
-#ifndef ALPHA_COMPOSITE
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-#endif
-
-/* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
-
- /* Listing 4 */
- vec4 trans_accum = texelFetch(transparentAccum, texel, 0);
- float trans_revealage = trans_accum.a;
- trans_accum.a = texelFetch(transparentRevealage, texel, 0).r;
-
- vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4);
-
- fragColor.a = 1.0 - trans_revealage;
- fragColor.rgb = trans_color * fragColor.a;
-
-#ifdef V3D_SHADING_OBJECT_OUTLINE
- uint object_id = texelFetch(objectId, texel, 0).r;
- float outline = calculate_object_outline(objectId, texel, object_id);
- fragColor = mix(vec4(world_data.object_outline_color.rgb, 1.0), fragColor, outline);
-#endif
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
deleted file mode 100644
index abd8c1f6579..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
+++ /dev/null
@@ -1,20 +0,0 @@
-
-layout(location = 0) out uint objectId;
-
-uniform float ImageTransparencyCutoff = 0.1;
-#ifdef V3D_SHADING_TEXTURE_COLOR
-uniform sampler2D image;
-
-in vec2 uv_interp;
-#endif
-
-void main()
-{
-#ifdef V3D_SHADING_TEXTURE_COLOR
- if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
- discard;
- }
-#endif
-
- objectId = uint(resource_id + 1) & 0xFFu;
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
deleted file mode 100644
index 559dc07c107..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ /dev/null
@@ -1,118 +0,0 @@
-
-uniform float ImageTransparencyCutoff = 0.1;
-#ifdef TEXTURE_IMAGE_ARRAY
-uniform sampler2DArray image_tile_array;
-uniform sampler1DArray image_tile_data;
-#else
-uniform sampler2D image;
-#endif
-uniform bool imageNearest;
-uniform bool imagePremultiplied;
-
-uniform float alpha = 0.5;
-uniform vec2 invertedViewportSize;
-uniform vec4 viewvecs[3];
-
-uniform vec4 materialColorAndMetal;
-uniform float materialRoughness;
-
-uniform float shadowMultiplier = 0.5;
-uniform float lightMultiplier = 1.0;
-uniform float shadowShift = 0.1;
-uniform float shadowFocus = 1.0;
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-in vec3 normal_viewport;
-#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
-#ifdef V3D_SHADING_TEXTURE_COLOR
-in vec2 uv_interp;
-#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-in vec3 vertexColor;
-#endif
-#ifdef V3D_LIGHTING_MATCAP
-uniform sampler2D matcapDiffuseImage;
-uniform sampler2D matcapSpecularImage;
-#endif
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-
-layout(location = 0) out vec4 transparentAccum;
-layout(location = 1) out
- float revealageAccum; /* revealage actually stored in transparentAccum.a */
-
-void main()
-{
- vec4 base_color;
-
-#if defined(V3D_SHADING_TEXTURE_COLOR)
-# ifdef TEXTURE_IMAGE_ARRAY
- base_color = workbench_sample_texture_array(
- image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
-# else
- base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
-# endif
- if (base_color.a < ImageTransparencyCutoff) {
- discard;
- }
-#elif defined(V3D_SHADING_VERTEX_COLOR)
- base_color.rgb = vertexColor;
-#else
- base_color.rgb = materialColorAndMetal.rgb;
-#endif /* V3D_SHADING_TEXTURE_COLOR */
-
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
- vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 nor = normalize(normal_viewport);
-#endif
-
- /* -------- SHADING --------- */
-#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = base_color.rgb;
-
-#elif defined(V3D_LIGHTING_MATCAP)
- bool flipped = world_data.matcap_orientation != 0;
- vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped);
- vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
-# else
- vec3 matcap_specular = vec3(0.0);
-# endif
- vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
-
-#elif defined(V3D_LIGHTING_STUDIO)
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- float metallic = materialColorAndMetal.a;
- vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
- vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
-# else
- vec3 specular_color = vec3(0.0);
- vec3 diffuse_color = base_color.rgb;
-# endif
-
- vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
-#endif
-
-#ifdef V3D_SHADING_SHADOW
- float light_factor = -dot(nor, world_data.shadow_direction_vs.xyz);
- float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor);
- shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
-#endif
-
- /* Based on :
- * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
- * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
- */
- /* Listing 4 */
- float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix);
- float weight = calculate_transparent_weight(z, alpha);
- transparentAccum = vec4(shaded_color * weight, alpha);
- revealageAccum = weight;
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl
deleted file mode 100644
index d223a7650c5..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-uniform sampler2D depthBuffer;
-
-void main(void)
-{
- float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
-
- /* background, discard */
- if (depth >= 1.0) {
- discard;
- }
-
- gl_FragDepth = depth;
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
new file mode 100644
index 00000000000..6f99739f259
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
@@ -0,0 +1,83 @@
+
+/* TODO(fclem) deduplicate code. */
+bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
+{
+ vec2 tile_pos = floor(co.xy);
+
+ if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
+ return false;
+
+ float tile = 10.0 * tile_pos.y + tile_pos.x;
+ if (tile >= textureSize(map, 0).x)
+ return false;
+
+ /* Fetch tile information. */
+ float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
+ if (tile_layer < 0.0)
+ return false;
+
+ vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
+
+ co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
+ return true;
+}
+
+vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
+{
+ vec2 tex_size = vec2(textureSize(image, 0).xy);
+ /* TODO(fclem) We could do the same with sampler objects.
+ * But this is a quick workaround instead of messing with the GPUTexture itself. */
+ vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
+ return texture(image, uv);
+}
+
+vec4 workbench_sample_texture_array(sampler2DArray tile_array,
+ sampler1DArray tile_data,
+ vec2 coord,
+ bool nearest_sampling)
+{
+ vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
+
+ vec3 uv = vec3(coord, 0);
+ if (!node_tex_tile_lookup(uv, tile_array, tile_data))
+ return vec4(1.0, 0.0, 1.0, 1.0);
+
+ /* TODO(fclem) We could do the same with sampler objects.
+ * But this is a quick workaround instead of messing with the GPUTexture itself. */
+ uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
+ return texture(tile_array, uv);
+}
+
+uniform sampler2DArray imageTileArray;
+uniform sampler1DArray imageTileData;
+uniform sampler2D imageTexture;
+
+uniform float imageTransparencyCutoff = 0.1;
+uniform bool imageNearest;
+uniform bool imagePremult;
+
+vec3 workbench_image_color(vec2 uvs)
+{
+#ifdef V3D_SHADING_TEXTURE_COLOR
+# ifdef TEXTURE_IMAGE_ARRAY
+ vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest);
+# else
+ vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest);
+# endif
+
+ /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
+ if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) {
+ color.rgb /= color.a;
+ }
+
+# ifdef GPU_FRAGMENT_SHADER
+ if (color.a < imageTransparencyCutoff) {
+ discard;
+ }
+# endif
+
+ return color.rgb;
+#else
+ return vec3(1.0);
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
new file mode 100644
index 00000000000..2d18cc1b014
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
@@ -0,0 +1,30 @@
+
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+
+vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
+{
+ /* Quick creation of an orthonormal basis */
+ float a = 1.0 / (1.0 + I.z);
+ float b = -I.x * I.y * a;
+ vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
+ vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
+ vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
+ if (flipped) {
+ matcap_uv.x = -matcap_uv.x;
+ }
+ return matcap_uv * 0.496 + 0.5;
+}
+
+uniform sampler2D matcapDiffuseImage;
+uniform sampler2D matcapSpecularImage;
+
+vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I)
+{
+ bool flipped = world_data.matcap_orientation != 0;
+ vec2 uv = matcap_uv_compute(I, N, flipped);
+
+ vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb;
+ vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb;
+
+ return diffuse * base_color + specular * float(world_data.use_specular);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
new file mode 100644
index 00000000000..1d8950e34b3
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
@@ -0,0 +1,21 @@
+
+layout(std140) uniform material_block
+{
+ vec4 mat_data[4096];
+};
+
+/* If set to -1, the resource handle is used instead. */
+uniform int materialIndex;
+
+void workbench_material_data_get(
+ int handle, out vec3 color, out float alpha, out float roughness, out float metallic)
+{
+ handle = (materialIndex != -1) ? materialIndex : handle;
+ vec4 data = mat_data[uint(handle) & 0xFFFu];
+ color = data.rgb;
+
+ uint encoded_data = floatBitsToUint(data.w);
+ alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0);
+ roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0);
+ metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
new file mode 100644
index 00000000000..58becb03290
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -0,0 +1,18 @@
+
+uniform sampler2D depthBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ float depth = texture(depthBuffer, uvcoordsvar.st).r;
+ /* Discard background pixels. */
+ if (depth == 1.0) {
+ discard;
+ }
+ /* Make this fragment occlude any fragment that will try to
+ * render over it in the normal passes. */
+ gl_FragDepth = 0.0;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl
deleted file mode 100644
index a4a5d9c31a3..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl
+++ /dev/null
@@ -1,12 +0,0 @@
-#define OBJECT_OUTLINE_OFFSET 1
-
-float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id)
-{
- uvec4 oid_offset = uvec4(
- texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r,
- texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r,
- texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r,
- texelFetchOffset(objectId, texel, 0, ivec2(OBJECT_OUTLINE_OFFSET, 0)).r);
-
- return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25));
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index 94e41b4bcd4..6d24b001d4d 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,92 +1,29 @@
-uniform vec4 materialColorAndMetal;
-uniform float materialRoughness;
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-#ifdef TEXTURE_IMAGE_ARRAY
-uniform sampler2DArray image_tile_array;
-uniform sampler1DArray image_tile_data;
-#else
-uniform sampler2D image;
-#endif
-uniform float ImageTransparencyCutoff = 0.1;
-uniform bool imageNearest;
-uniform bool imagePremultiplied;
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-in vec3 normal_viewport;
-#endif
-
-#ifdef V3D_SHADING_TEXTURE_COLOR
-in vec2 uv_interp;
-#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-in vec3 vertexColor;
-#endif
-
-#ifdef HAIR_SHADER
-flat in float hair_rand;
-#endif
-
-#ifdef MATDATA_PASS_ENABLED
layout(location = 0) out vec4 materialData;
-#endif
-#ifdef OBJECT_ID_PASS_ENABLED
-layout(location = 1) out uint objectId;
-#endif
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-layout(location = 2) out WB_Normal normalViewport;
-#endif
+layout(location = 1) out WB_Normal normalData;
+layout(location = 2) out uint objectId;
+
+uniform bool useMatcap = false;
void main()
{
-#ifdef MATDATA_PASS_ENABLED
- float metallic, roughness;
- vec4 color;
-
-# if defined(V3D_SHADING_TEXTURE_COLOR)
-# ifdef TEXTURE_IMAGE_ARRAY
- color = workbench_sample_texture_array(
- image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
-# else
- color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
-# endif
- if (color.a < ImageTransparencyCutoff) {
- discard;
- }
-# elif defined(V3D_SHADING_VERTEX_COLOR)
- color.rgb = vertexColor;
-# else
- color.rgb = materialColorAndMetal.rgb;
-# endif
-
-# ifdef V3D_LIGHTING_MATCAP
- /* Encode front facing in metallic channel. */
- metallic = float(gl_FrontFacing);
- roughness = 0.0;
-# else
- metallic = materialColorAndMetal.a;
- roughness = materialRoughness;
-# endif
+ normalData = workbench_normal_encode(gl_FrontFacing, normal_interp);
-# ifdef HAIR_SHADER
- /* Add some variation to the hairs to avoid uniform look. */
- float hair_variation = hair_rand * 0.1;
- color = clamp(color - hair_variation, 0.0, 1.0);
- metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
- roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
-# endif
+ materialData = vec4(color_interp, packed_rough_metal);
- materialData.rgb = color.rgb;
- materialData.a = workbench_float_pair_encode(roughness, metallic);
-#endif /* MATDATA_PASS_ENABLED */
+ objectId = uint(object_id);
-#ifdef OBJECT_ID_PASS_ENABLED
- objectId = uint(resource_id + 1) & 0xFFu;
-#endif
+ if (useMatcap) {
+ /* For matcaps, save front facing in alpha channel. */
+ materialData.a = float(gl_FrontFacing);
+ }
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
- n = normalize(n);
- normalViewport = workbench_normal_encode(n);
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ materialData.rgb = workbench_image_color(uv_interp);
#endif
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
new file mode 100644
index 00000000000..6a7bc185fe9
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
@@ -0,0 +1,94 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
+
+uniform samplerBuffer ac; /* active color layer */
+uniform samplerBuffer au; /* active texture layer */
+
+/* From http://libnoise.sourceforge.net/noisegen/index.html */
+float integer_noise(int n)
+{
+ n = (n >> 13) ^ n;
+ int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return (float(nn) / 1073741824.0);
+}
+
+vec3 workbench_hair_random_normal(vec3 tan, vec3 binor, float rand)
+{
+ /* To "simulate" anisotropic shading, randomize hair normal per strand. */
+ vec3 nor = cross(tan, binor);
+ nor = normalize(mix(nor, -tan, rand * 0.1));
+ float cos_theta = (rand * 2.0 - 1.0) * 0.2;
+ float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
+ nor = nor * sin_theta + binor * cos_theta;
+ return nor;
+}
+
+void workbench_hair_random_material(float rand,
+ inout vec3 color,
+ inout float roughness,
+ inout float metallic)
+{
+ /* Center noise around 0. */
+ rand -= 0.5;
+ rand *= 0.1;
+ /* Add some variation to the hairs to avoid uniform look. */
+ metallic = clamp(metallic + rand, 0.0, 1.0);
+ roughness = clamp(roughness + rand, 0.0, 1.0);
+ /* Modulate by color intensity to reduce very high contrast when color is dark. */
+ color = clamp(color + rand * (color + 0.05), 0.0, 1.0);
+}
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float time, thick_time, thickness;
+ vec3 world_pos, tan, binor;
+ hair_get_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz,
+ ViewMatrixInverse[2].xyz,
+ world_pos,
+ tan,
+ binor,
+ time,
+ thickness,
+ thick_time);
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ float hair_rand = integer_noise(hair_get_strand_id());
+ vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+
+ uv_interp = hair_get_customdata_vec2(au);
+
+ normal_interp = normalize(normal_world_to_view(nor));
+
+#ifdef OPAQUE_MATERIAL
+ float metallic, roughness;
+#endif
+ workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
+
+ if (materialIndex == 0) {
+ color_interp = hair_get_customdata_vec3(ac);
+ }
+
+ /* Hairs have lots of layer and can rapidly become the most prominent surface.
+ * So we lower their alpha artificially. */
+ alpha_interp *= 0.3;
+
+ workbench_hair_random_material(hair_rand, color_interp, roughness, metallic);
+
+#ifdef OPAQUE_MATERIAL
+ packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
+#endif
+
+ object_id = int((uint(resource_id) + 1u) & 0xFFu);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 0a3252f0b9b..31e298d1540 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -1,110 +1,40 @@
-#ifndef HAIR_SHADER
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
+
in vec3 pos;
in vec3 nor;
-in vec2 au; /* active texture layer */
-# ifdef V3D_SHADING_VERTEX_COLOR
in vec4 ac; /* active color */
-# endif
-# define uv au
-#else /* HAIR_SHADER */
-
-# ifdef V3D_SHADING_TEXTURE_COLOR
-uniform samplerBuffer au; /* active texture layer */
-# endif
-# ifdef V3D_SHADING_VERTEX_COLOR
-uniform samplerBuffer ac; /* active color layer */
-# endif
-
-flat out float hair_rand;
-#endif /* HAIR_SHADER */
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-out vec3 normal_viewport;
-#endif
-
-#ifdef V3D_SHADING_TEXTURE_COLOR
-out vec2 uv_interp;
-#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-out vec3 vertexColor;
-#endif
-
-#ifdef OBJECT_ID_PASS_ENABLED
-RESOURCE_ID_VARYING
-#endif
-
-/* From http://libnoise.sourceforge.net/noisegen/index.html */
-float integer_noise(int n)
-{
- n = (n >> 13) ^ n;
- int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
- return (float(nn) / 1073741824.0);
-}
-
-vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand)
-{
- /* To "simulate" anisotropic shading, randomize hair normal per strand. */
- vec3 nor = cross(tan, binor);
- nor = normalize(mix(nor, -tan, rand * 0.1));
- float cos_theta = (rand * 2.0 - 1.0) * 0.2;
- float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
- nor = nor * sin_theta + binor * cos_theta;
- return nor;
-}
+in vec2 au; /* active texture layer */
void main()
{
-#ifdef HAIR_SHADER
-# ifdef V3D_SHADING_TEXTURE_COLOR
- vec2 uv = hair_get_customdata_vec2(au);
-# endif
- float time, thick_time, thickness;
- vec3 world_pos, tan, binor;
- hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
- ModelMatrixInverse,
- ViewMatrixInverse[3].xyz,
- ViewMatrixInverse[2].xyz,
- world_pos,
- tan,
- binor,
- time,
- thickness,
- thick_time);
-
- hair_rand = integer_noise(hair_get_strand_id());
- vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand);
-#else
vec3 world_pos = point_object_to_world(pos);
-#endif
gl_Position = point_world_to_ndc(world_pos);
-#ifdef V3D_SHADING_TEXTURE_COLOR
- uv_interp = uv;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-# ifndef HAIR_SHADER
- vertexColor = ac.rgb;
-# else
- vertexColor = hair_get_customdata_vec4(ac).rgb;
-# endif
-#endif
+ uv_interp = au;
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-# ifndef HAIR_SHADER
- normal_viewport = normal_object_to_view(nor);
- normal_viewport = normalize(normal_viewport);
-# else
- normal_viewport = normal_world_to_view(nor);
-# endif
-#endif
+ normal_interp = normalize(normal_object_to_view(nor));
-#ifdef OBJECT_ID_PASS_ENABLED
- PASS_RESOURCE_ID
+#ifdef OPAQUE_MATERIAL
+ float metallic, roughness;
#endif
+ workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
+ if (materialIndex == 0) {
+ color_interp = ac.rgb;
+ }
+
+#ifdef OPAQUE_MATERIAL
+ packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
#endif
+
+ object_id = int((uint(resource_id) + 1u) & 0xFFu);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
new file mode 100644
index 00000000000..8e2f7ba4735
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
@@ -0,0 +1,21 @@
+
+#ifdef GPU_VERTEX_SHADER
+# define IN_OUT out
+#else
+# define IN_OUT in
+#endif
+
+IN_OUT ShaderStageInterface
+{
+ vec3 normal_interp;
+ vec3 color_interp;
+ float alpha_interp;
+ vec2 uv_interp;
+#ifdef TRANSPARENT_MATERIAL
+ flat float roughness;
+ flat float metallic;
+#else
+ flat float packed_rough_metal;
+#endif
+ flat int object_id;
+};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
index 6b0741b6d1b..6fa76510e6e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
@@ -1,15 +1,19 @@
out vec4 fragColor;
+layout(location = 0) out vec4 materialData;
+layout(location = 1) out vec4 normalData;
+layout(location = 2) out uint objectId;
+
void main()
{
- const float intensity = 0.25;
+ const float a = 0.25;
#ifdef SHADOW_PASS
- fragColor = vec4(
- (gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0);
+ materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0);
#else
- fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) :
- vec3(-intensity, -intensity, intensity),
- 1.0);
+ materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a);
#endif
+ materialData.a = 0.0;
+ normalData = vec4(0.0);
+ objectId = 0u;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
new file mode 100644
index 00000000000..3c2d1a9c0c7
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
@@ -0,0 +1,89 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
+
+/* Revealage is actually stored in transparentAccum alpha channel.
+ * This is a workaround to older hardware not having separate blend equation per render target. */
+layout(location = 0) out vec4 transparentAccum;
+layout(location = 1) out vec4 revealageAccum;
+
+/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
+layout(location = 2) out uint objectId;
+
+/* Special function only to be used with calculate_transparent_weight(). */
+float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
+{
+ if (proj_mat[3][3] == 0.0) {
+ float d = 2.0 * depth - 1.0;
+ return -proj_mat[3][2] / (d + proj_mat[2][2]);
+ }
+ else {
+ /* Return depth from near plane. */
+ return depth * viewvecs[1].z;
+ }
+}
+
+/* Based on :
+ * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
+ * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
+ */
+float calculate_transparent_weight(void)
+{
+ float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix);
+#if 0
+ /* Eq 10 : Good for surfaces with varying opacity (like particles) */
+ float a = min(1.0, alpha * 10.0) + 0.01;
+ float b = -gl_FragCoord.z * 0.95 + 1.0;
+ float w = a * a * a * 3e2 * b * b * b;
+#else
+ /* Eq 7 put more emphasis on surfaces closer to the view. */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
+ /* Same as eq 7, but optimized. */
+ float a = abs(z) / 5.0;
+ float b = abs(z) / 200.0;
+ b *= b;
+ float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
+#endif
+ return clamp(w, 1e-2, 3e2);
+}
+
+void main()
+{
+ /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
+ vec2 uv_viewport = gl_FragCoord.xy * world_data.viewport_size_inv;
+ vec3 I = view_vector_from_screen_uv(uv_viewport, world_data.viewvecs, ProjectionMatrix);
+ vec3 N = normalize(normal_interp);
+
+ vec3 color = color_interp;
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ color = workbench_image_color(uv_interp);
+#endif
+
+#ifdef V3D_LIGHTING_MATCAP
+ vec3 shaded_color = get_matcap_lighting(color, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_STUDIO
+ vec3 shaded_color = get_world_lighting(color, roughness, metallic, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_FLAT
+ vec3 shaded_color = color;
+#endif
+
+ shaded_color *= get_shadow(N);
+
+ /* Listing 4 */
+ float weight = calculate_transparent_weight() * alpha_interp;
+ transparentAccum = vec4(shaded_color * weight, alpha_interp);
+ revealageAccum = vec4(weight);
+
+ objectId = uint(object_id);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
new file mode 100644
index 00000000000..d985737a35b
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
@@ -0,0 +1,26 @@
+
+uniform sampler2D transparentAccum;
+uniform sampler2D transparentRevealage;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+/* Based on :
+ * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
+ * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
+ */
+
+void main()
+{
+ /* Revealage is actually stored in transparentAccum alpha channel.
+ * This is a workaround to older hardware not having separate blend equation per render target.
+ */
+ vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st);
+ float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r;
+ float trans_reveal = trans_accum.a;
+
+ /* Listing 4 */
+ fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4);
+ fragColor.a = 1.0 - trans_reveal;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index c38d8fe06bc..e957f8bbe9c 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,4 +1,9 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
@@ -8,10 +13,9 @@ uniform sampler1D flameColorTexture;
uniform sampler1D transferTexture;
uniform int samplesLen = 256;
-uniform float noiseOfs = 0.0f;
+uniform float noiseOfs = 0.0;
uniform float stepLength; /* Step length in local space. */
uniform float densityScale; /* Simple Opacity multiplicator. */
-uniform vec4 viewvecs[3];
uniform vec3 activeColor;
uniform float slicePosition;
@@ -23,34 +27,11 @@ in vec3 localPos;
out vec4 fragColor;
-#define M_PI 3.1415926535897932 /* pi */
-
float phase_function_isotropic()
{
return 1.0 / (4.0 * M_PI);
}
-float get_view_z_from_depth(float depth)
-{
- if (ProjectionMatrix[3][3] == 0.0) {
- float d = 2.0 * depth - 1.0;
- return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
- }
- else {
- return viewvecs[0].z + depth * viewvecs[1].z;
- }
-}
-
-vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
-{
- if (ProjectionMatrix[3][3] == 0.0) {
- return vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0) * get_view_z_from_depth(depth);
- }
- else {
- return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz;
- }
-}
-
float max_v3(vec3 v)
{
return max(v.x, max(v.y, v.z));
@@ -134,8 +115,9 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction)
float shadows = sample_volume_texture(shadowTexture, co).r;
vec4 density = sample_volume_texture(densityTexture, co); /* rgb: color, a: density */
- scattering = density.rgb * (density.a * densityScale) * activeColor;
+ scattering = density.rgb * densityScale;
extinction = max(1e-4, dot(scattering, vec3(0.33333)));
+ scattering *= activeColor;
/* Scale shadows in log space and clamp them to avoid completely black shadows. */
scattering *= exp(clamp(log(shadows) * densityScale * 0.1, -2.5, 0.0)) * M_PI;
@@ -208,8 +190,10 @@ void main()
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
float depth_end = min(depth, gl_FragCoord.z);
- vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end);
- vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0);
+ vec3 vs_ray_end = view_position_from_depth(
+ screen_uv, depth_end, world_data.viewvecs, ProjectionMatrix);
+ vec3 vs_ray_ori = view_position_from_depth(
+ screen_uv, 0.0, world_data.viewvecs, ProjectionMatrix);
vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0);
vs_ray_dir /= abs(vs_ray_dir.z);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 3542a1a91fc..1a32a202290 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,4 +1,7 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
+
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
index 690ce5d527f..81f6e651be0 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+
/* [Drobot2014a] Low Level Optimizations for GCN */
vec4 fast_rcp(vec4 v)
{
@@ -41,9 +43,19 @@ vec4 wrapped_lighting(vec4 NL, vec4 w)
return clamp((NL + w) * denom, 0.0, 1.0);
}
-vec3 get_world_lighting(
- WorldData world_data, vec3 diffuse_color, vec3 specular_color, float roughness, vec3 N, vec3 I)
+vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I)
{
+ vec3 specular_color, diffuse_color;
+
+ if (world_data.use_specular) {
+ diffuse_color = mix(base_color, vec3(0.0), metallic);
+ specular_color = mix(vec3(0.05), base_color, metallic);
+ }
+ else {
+ diffuse_color = base_color;
+ specular_color = vec3(0.0);
+ }
+
vec3 specular_light = world_data.ambient_color.rgb;
vec3 diffuse_light = world_data.ambient_color.rgb;
vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a,
@@ -51,37 +63,37 @@ vec3 get_world_lighting(
world_data.lights[2].diffuse_color_wrap.a,
world_data.lights[3].diffuse_color_wrap.a);
-#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- /* Prepare Specular computation. Eval 4 lights at once. */
- vec3 R = -reflect(I, N);
- vec4 spec_angle, spec_NL, wrap_NL;
- prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
- prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
- prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
- prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
-
- vec4 gloss = vec4(1.0 - roughness);
- /* Reduce gloss for smooth light. (simulate bigger light) */
- gloss *= 1.0 - wrap;
- vec4 shininess = exp2(10.0 * gloss + 1.0);
-
- vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
-
- /* Simulate Env. light. */
- vec4 w = mix(wrap, vec4(1.0), roughness);
- vec4 spec_env = wrapped_lighting(wrap_NL, w);
-
- spec_light = mix(spec_light, spec_env, wrap * wrap);
-
- /* Multiply result by lights specular colors. */
- specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
- specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
- specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
- specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
-
- float NV = clamp(dot(N, I), 0.0, 1.0);
- specular_color = brdf_approx(specular_color, roughness, NV);
-#endif
+ if (world_data.use_specular) {
+ /* Prepare Specular computation. Eval 4 lights at once. */
+ vec3 R = -reflect(I, N);
+ vec4 spec_angle, spec_NL, wrap_NL;
+ prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
+ prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
+ prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
+ prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
+
+ vec4 gloss = vec4(1.0 - roughness);
+ /* Reduce gloss for smooth light. (simulate bigger light) */
+ gloss *= 1.0 - wrap;
+ vec4 shininess = exp2(10.0 * gloss + 1.0);
+
+ vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
+
+ /* Simulate Env. light. */
+ vec4 w = mix(wrap, vec4(1.0), roughness);
+ vec4 spec_env = wrapped_lighting(wrap_NL, w);
+
+ spec_light = mix(spec_light, spec_env, wrap * wrap);
+
+ /* Multiply result by lights specular colors. */
+ specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
+ specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
+ specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
+ specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
+
+ float NV = clamp(dot(N, I), 0.0, 1.0);
+ specular_color = brdf_approx(specular_color, roughness, NV);
+ }
specular_light *= specular_color;
/* Prepare diffuse computation. Eval 4 lights at once. */
@@ -107,3 +119,13 @@ vec3 get_world_lighting(
return diffuse_light + specular_light;
}
+
+uniform bool forceShadowing = false;
+
+float get_shadow(vec3 N)
+{
+ float light_factor = -dot(N, world_data.shadow_direction_vs.xyz);
+ float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
+ shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
+ return shadow_mix + world_data.shadow_add;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c
deleted file mode 100644
index fed7e230a86..00000000000
--- a/source/blender/draw/engines/workbench/solid_mode.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- *
- * Simple engine for drawing color and/or depth.
- * When we only need simple studio shaders.
- */
-
-#include "DRW_render.h"
-
-#include "GPU_shader.h"
-
-#include "RE_pipeline.h"
-
-#include "workbench_private.h"
-
-/* Functions */
-
-static void workbench_solid_engine_init(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_deferred_engine_init(data);
-}
-
-static void workbench_solid_cache_init(void *vedata)
-{
-
- WORKBENCH_Data *data = vedata;
- workbench_deferred_cache_init(data);
-}
-
-static void workbench_solid_cache_populate(void *vedata, Object *ob)
-{
- WORKBENCH_Data *data = vedata;
- workbench_deferred_solid_cache_populate(data, ob);
-}
-
-static void workbench_solid_cache_finish(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_deferred_cache_finish(data);
-}
-
-static void workbench_solid_draw_scene(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- const int num_samples = workbench_num_viewport_rendering_iterations(data);
-
- for (int sample = 0; sample < num_samples; sample++) {
- workbench_deferred_draw_scene(data);
- }
- workbench_deferred_draw_finish(data);
-}
-
-static void workbench_solid_engine_free(void)
-{
- workbench_deferred_engine_free();
-}
-
-static void workbench_solid_view_update(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_taa_view_updated(data);
-}
-
-static void workbench_solid_id_update(void *UNUSED(vedata), struct ID *id)
-{
- if (GS(id->name) == ID_OB) {
- WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(
- id, &draw_engine_workbench_solid);
- if (oed != NULL && oed->dd.recalc != 0) {
- oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0;
- oed->dd.recalc = 0;
- }
- }
-}
-
-static void workbench_render_to_image(void *vedata,
- RenderEngine *engine,
- RenderLayer *render_layer,
- const rcti *rect)
-{
- workbench_render(vedata, engine, render_layer, rect);
-}
-
-static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
-
-DrawEngineType draw_engine_workbench_solid = {
- NULL,
- NULL,
- N_("Workbench"),
- &workbench_data_size,
- &workbench_solid_engine_init,
- &workbench_solid_engine_free,
- &workbench_solid_cache_init,
- &workbench_solid_cache_populate,
- &workbench_solid_cache_finish,
- &workbench_solid_draw_scene,
- &workbench_solid_view_update,
- &workbench_solid_id_update,
- &workbench_render_to_image,
-};
diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c
deleted file mode 100644
index fef1ffded8d..00000000000
--- a/source/blender/draw/engines/workbench/transparent_mode.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- *
- * Simple engine for drawing color and/or depth.
- * When we only need simple studio shaders.
- */
-
-#include "DRW_render.h"
-
-#include "GPU_shader.h"
-
-#include "workbench_private.h"
-
-/* Functions */
-
-static void workbench_transparent_engine_init(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_forward_engine_init(data);
-}
-
-static void workbench_transparent_cache_init(void *vedata)
-{
-
- WORKBENCH_Data *data = vedata;
- workbench_forward_cache_init(data);
-}
-
-static void workbench_transparent_cache_populate(void *vedata, Object *ob)
-{
- WORKBENCH_Data *data = vedata;
- workbench_forward_cache_populate(data, ob);
-}
-
-static void workbench_transparent_cache_finish(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_forward_cache_finish(data);
-}
-
-static void workbench_transparent_draw_scene(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- const int num_samples = workbench_num_viewport_rendering_iterations(data);
-
- for (int sample = 0; sample < num_samples; sample++) {
- workbench_forward_draw_scene(data);
- }
- workbench_forward_draw_finish(data);
-}
-
-static void workbench_transparent_engine_free(void)
-{
- workbench_forward_engine_free();
-}
-
-static void workbench_transparent_view_update(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_taa_view_updated(data);
-}
-
-static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
-
-DrawEngineType draw_engine_workbench_transparent = {
- NULL,
- NULL,
- N_("Workbench"),
- &workbench_data_size,
- &workbench_transparent_engine_init,
- &workbench_transparent_engine_free,
- &workbench_transparent_cache_init,
- &workbench_transparent_cache_populate,
- &workbench_transparent_cache_finish,
- &workbench_transparent_draw_scene,
- &workbench_transparent_view_update,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 623a3c0cb15..0ab67d620ee 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -22,133 +22,231 @@
#include "workbench_private.h"
+#include "BLI_memblock.h"
+
#include "DNA_userdef_types.h"
#include "ED_view3d.h"
+#include "ED_screen.h"
#include "UI_resources.h"
-#include "GPU_batch.h"
+#include "GPU_uniformbuffer.h"
/* -------------------------------------------------------------------- */
/** \name World Data
* \{ */
-static void workbench_world_data_free(DrawData *dd)
+GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd)
{
- WORKBENCH_WorldData *data = (WORKBENCH_WorldData *)dd;
- DRW_UBO_FREE_SAFE(data->world_ubo);
+ struct GPUUniformBuffer **ubo = BLI_memblock_alloc(wpd->material_ubo);
+ if (*ubo == NULL) {
+ *ubo = GPU_uniformbuffer_create(sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL, NULL, NULL);
+ }
+ return *ubo;
}
-/* Ensure the availability of the world_ubo in the given WORKBENCH_PrivateData
- *
- * See T70167: Some platforms create threads to upload ubo's.
- *
- * Reuses the last previous created `world_ubo`. Due to limitations of
- * DrawData it will only be reused when there is a world attached to the Scene.
- * Future development: The best location would be to store it in the View3D.
- *
- * We don't cache the data itself as there was no indication that that lead to
- * an improvement.
- *
- * This functions also sets the `WORKBENCH_PrivateData.is_world_ubo_owner` that must
- * be respected.
- */
-static void workbench_world_data_ubo_ensure(const Scene *scene, WORKBENCH_PrivateData *wpd)
+static void workbench_ubo_free(void *elem)
{
- World *world = scene->world;
- if (world) {
- WORKBENCH_WorldData *engine_world_data = (WORKBENCH_WorldData *)DRW_drawdata_ensure(
- &world->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_WorldData),
- NULL,
- &workbench_world_data_free);
-
- if (engine_world_data->world_ubo == NULL) {
- engine_world_data->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World),
- &wpd->world_data);
- }
- else {
- DRW_uniformbuffer_update(engine_world_data->world_ubo, &wpd->world_data);
- }
-
- /* Borrow world data ubo */
- wpd->is_world_ubo_owner = false;
- wpd->world_ubo = engine_world_data->world_ubo;
- }
- else {
- /* there is no world so we cannot cache the UBO. */
- BLI_assert(!wpd->world_ubo || wpd->is_world_ubo_owner);
- if (!wpd->world_ubo) {
- wpd->is_world_ubo_owner = true;
- wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
- }
- }
+ GPUUniformBuffer **ubo = elem;
+ DRW_UBO_FREE_SAFE(*ubo);
}
-static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd)
+static void workbench_view_layer_data_free(void *storage)
{
- WORKBENCH_UBO_World *wd = &wpd->world_data;
- float light_direction[3];
- float view_matrix[4][4];
- DRW_view_viewmat_get(NULL, view_matrix, false);
+ WORKBENCH_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage;
+
+ DRW_UBO_FREE_SAFE(vldata->dof_sample_ubo);
+ DRW_UBO_FREE_SAFE(vldata->world_ubo);
+ DRW_UBO_FREE_SAFE(vldata->cavity_sample_ubo);
+ DRW_TEXTURE_FREE_SAFE(vldata->cavity_jitter_tx);
+
+ BLI_memblock_destroy(vldata->material_ubo_data, NULL);
+ BLI_memblock_destroy(vldata->material_ubo, workbench_ubo_free);
+}
- workbench_private_data_get_light_direction(light_direction);
+static WORKBENCH_ViewLayerData *workbench_view_layer_data_ensure_ex(struct ViewLayer *view_layer)
+{
+ WORKBENCH_ViewLayerData **vldata = (WORKBENCH_ViewLayerData **)
+ DRW_view_layer_engine_data_ensure_ex(view_layer,
+ (DrawEngineType *)&workbench_view_layer_data_ensure_ex,
+ &workbench_view_layer_data_free);
+
+ if (*vldata == NULL) {
+ *vldata = MEM_callocN(sizeof(**vldata), "WORKBENCH_ViewLayerData");
+ size_t matbuf_size = sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL;
+ (*vldata)->material_ubo_data = BLI_memblock_create_ex(matbuf_size, matbuf_size * 2);
+ (*vldata)->material_ubo = BLI_memblock_create_ex(sizeof(void *), sizeof(void *) * 8);
+ (*vldata)->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL);
+ }
- /* Shadow direction. */
- mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction);
+ return *vldata;
}
/* \} */
-void workbench_clear_color_get(float color[4])
+static void workbench_viewvecs_update(float r_viewvecs[3][4])
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
+ float invproj[4][4];
+ const bool is_persp = DRW_view_is_persp_get(NULL);
+ DRW_view_winmat_get(NULL, invproj, true);
+
+ /* view vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ copy_v4_fl4(r_viewvecs[0], -1.0f, -1.0f, -1.0f, 1.0f);
+ copy_v4_fl4(r_viewvecs[1], 1.0f, -1.0f, -1.0f, 1.0f);
+ copy_v4_fl4(r_viewvecs[2], -1.0f, 1.0f, -1.0f, 1.0f);
+
+ /* convert the view vectors to view space */
+ for (int i = 0; i < 3; i++) {
+ mul_m4_v4(invproj, r_viewvecs[i]);
+ /* normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][3]);
+ if (is_persp) {
+ mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][2]);
+ }
+ r_viewvecs[i][3] = 1.0;
+ }
+
+ /* we need to store the differences */
+ r_viewvecs[1][0] -= r_viewvecs[0][0];
+ r_viewvecs[1][1] = r_viewvecs[2][1] - r_viewvecs[0][1];
- if (!DRW_state_is_scene_render() || !DRW_state_draw_background()) {
- zero_v4(color);
+ /* 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]);
+ r_viewvecs[1][2] = vec_far[2] - r_viewvecs[0][2];
}
- else if (scene->world) {
- copy_v3_v3(color, &scene->world->horr);
- color[3] = 1.0f;
+}
+
+static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
+{
+ StudioLight *studiolight = wpd->studio_light;
+ float view_matrix[4][4], rot_matrix[4][4];
+ DRW_view_viewmat_get(NULL, view_matrix, false);
+
+ if (USE_WORLD_ORIENTATION(wpd)) {
+ axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
+ mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
+ swap_v3_v3(rot_matrix[2], rot_matrix[1]);
+ negate_v3(rot_matrix[2]);
}
else {
- zero_v3(color);
- color[3] = 1.0f;
+ unit_m4(rot_matrix);
}
-}
-void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info)
-{
- effect_info->jitter_index = 0;
- effect_info->view_updated = true;
+ if (U.edit_studio_light) {
+ studiolight = BKE_studiolight_studio_edit_get();
+ }
+
+ /* Studio Lights. */
+ for (int i = 0; i < 4; i++) {
+ WORKBENCH_UBO_Light *light = &wd->lights[i];
+
+ SolidLight *sl = (studiolight) ? &studiolight->light[i] : NULL;
+ if (sl && sl->flag) {
+ copy_v3_v3(light->light_direction, sl->vec);
+ mul_mat3_m4_v3(rot_matrix, light->light_direction);
+ /* We should predivide the power by PI but that makes the lights really dim. */
+ copy_v3_v3(light->specular_color, sl->spec);
+ copy_v3_v3(light->diffuse_color, sl->col);
+ light->wrapped = sl->smooth;
+ }
+ else {
+ copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
+ copy_v3_fl(light->specular_color, 0.0f);
+ copy_v3_fl(light->diffuse_color, 0.0f);
+ }
+ }
+
+ if (studiolight) {
+ copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
+ }
+ else {
+ copy_v3_fl(wd->ambient_color, 1.0f);
+ }
+
+ wd->use_specular = workbench_is_specular_highlight_enabled(wpd);
}
void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
- wpd->material_hash = BLI_ghash_ptr_new(__func__);
- wpd->material_transp_hash = BLI_ghash_ptr_new(__func__);
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
+
+ wpd->is_playback = DRW_state_is_playback();
+ wpd->is_navigating = rv3d && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
+
+ wpd->ctx_mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+
wpd->preferences = &U;
+ wpd->scene = scene;
+ wpd->sh_cfg = draw_ctx->sh_cfg;
+ wpd->clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
+ wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
+ wpd->vldata = vldata;
+ wpd->world_ubo = vldata->world_ubo;
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
+ wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd);
+
+ wpd->volumes_do = false;
+ BLI_listbase_clear(&wpd->smoke_domains);
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
+ /* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
+ * But this is a workaround for a missing update tagging from operators. */
+ if (scene->display.shading.type != wpd->shading.type ||
+ XRAY_ENABLED(v3d) != XRAY_ENABLED((&scene->display))) {
+ wpd->view_updated = true;
+ }
+
wpd->shading = scene->display.shading;
- wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
- wpd->use_color_render_settings = true;
+ if (XRAY_FLAG_ENABLED((&scene->display))) {
+ wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
+ }
+ else {
+ wpd->shading.xray_alpha = 1.0f;
+ }
+
+ if (scene->r.alphamode == R_ALPHAPREMUL) {
+ copy_v4_fl(wpd->background_color, 0.0f);
+ }
+ else if (scene->world) {
+ World *wo = scene->world;
+ copy_v4_fl4(wpd->background_color, wo->horr, wo->horg, wo->horb, 1.0f);
+ }
+ else {
+ copy_v4_fl4(wpd->background_color, 0.0f, 0.0f, 0.0f, 1.0f);
+ }
}
else {
+ /* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
+ * But this is a workaround for a missing update tagging from operators. */
+ if (v3d->shading.type != wpd->shading.type || XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd)) {
+ wpd->view_updated = true;
+ }
+
wpd->shading = v3d->shading;
- wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
- wpd->use_color_render_settings = false;
- }
+ if (wpd->shading.type < OB_SOLID) {
+ wpd->shading.xray_alpha = 0.0f;
+ }
+ else if (XRAY_ENABLED(v3d)) {
+ wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
+ }
+ else {
+ wpd->shading.xray_alpha = 1.0f;
+ }
- wpd->use_color_management = BKE_scene_check_color_management_enabled(scene);
+ /* No background. The overlays will draw the correct one. */
+ copy_v4_fl(wpd->background_color, 0.0f);
+ }
if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP);
@@ -162,119 +260,56 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO);
}
- float shadow_focus = scene->display.shadow_focus;
- /* Clamp to avoid overshadowing and shading errors. */
- CLAMP(shadow_focus, 0.0001f, 0.99999f);
- wpd->shadow_shift = scene->display.shadow_shift;
- wpd->shadow_focus = 1.0f - shadow_focus * (1.0f - wpd->shadow_shift);
- wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity;
-
- WORKBENCH_UBO_World *wd = &wpd->world_data;
- wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0;
-
- studiolight_update_world(wpd, wpd->studio_light, wd);
-
- copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color);
- wd->object_outline_color[3] = 1.0f;
-
- wd->curvature_ridge = 0.5f / max_ff(square_f(wpd->shading.curvature_ridge_factor), 1e-4f);
- wd->curvature_valley = 0.7f / max_ff(square_f(wpd->shading.curvature_valley_factor), 1e-4f);
-
- /* Will be NULL when rendering. */
- if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
- wpd->world_clip_planes = rv3d->clip;
- }
- else {
- wpd->world_clip_planes = NULL;
- }
-
- workbench_world_data_update_shadow_direction_vs(wpd);
- workbench_world_data_ubo_ensure(scene, wpd);
-
- /* Cavity settings */
{
- const int ssao_samples = scene->display.matcap_ssao_samples;
-
- float invproj[4][4];
- const bool is_persp = DRW_view_is_persp_get(NULL);
- /* view vectors for the corners of the view frustum.
- * Can be used to recreate the world space position easily */
- float viewvecs[3][4] = {
- {-1.0f, -1.0f, -1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f, 1.0f},
- };
- int i;
- const float *size = DRW_viewport_size_get();
-
- wpd->ssao_params[0] = ssao_samples;
- wpd->ssao_params[1] = size[0] / 64.0;
- wpd->ssao_params[2] = size[1] / 64.0;
- wpd->ssao_params[3] = 0;
-
- /* distance, factor, factor, attenuation */
- copy_v4_fl4(wpd->ssao_settings,
- scene->display.matcap_ssao_distance,
- wpd->shading.cavity_valley_factor,
- wpd->shading.cavity_ridge_factor,
- scene->display.matcap_ssao_attenuation);
-
- DRW_view_winmat_get(NULL, wpd->winmat, false);
- DRW_view_winmat_get(NULL, invproj, true);
-
- /* convert the view vectors to view space */
- for (i = 0; i < 3; i++) {
- mul_m4_v4(invproj, viewvecs[i]);
- /* normalized trick see:
- * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
- if (is_persp) {
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
- }
- viewvecs[i][3] = 1.0;
-
- copy_v4_v4(wpd->viewvecs[i], viewvecs[i]);
- }
-
- /* we need to store the differences */
- wpd->viewvecs[1][0] -= wpd->viewvecs[0][0];
- wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->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]);
- wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2];
- }
+ /* Material UBOs. */
+ wpd->material_ubo_data = vldata->material_ubo_data;
+ wpd->material_ubo = vldata->material_ubo;
+ wpd->material_chunk_count = 1;
+ wpd->material_chunk_curr = 0;
+ wpd->material_index = 1;
+ /* Create default material ubo. */
+ wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data);
+ wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd);
+ /* Init default material used by vertex color & texture. */
+ workbench_material_ubo_data(
+ wpd, NULL, NULL, &wpd->material_ubo_data_curr[0], V3D_SHADING_MATERIAL_COLOR);
}
-
- wpd->volumes_do = false;
- BLI_listbase_clear(&wpd->smoke_domains);
}
-void workbench_private_data_get_light_direction(float r_light_direction[3])
+void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
+ WORKBENCH_UBO_World wd;
- copy_v3_v3(r_light_direction, scene->display.light_direction);
- SWAP(float, r_light_direction[2], r_light_direction[1]);
- r_light_direction[2] = -r_light_direction[2];
- r_light_direction[0] = -r_light_direction[0];
+ copy_v2_v2(wd.viewport_size, DRW_viewport_size_get());
+ copy_v2_v2(wd.viewport_size_inv, DRW_viewport_invert_size_get());
+ copy_v3_v3(wd.object_outline_color, wpd->shading.object_outline_color);
+ wd.object_outline_color[3] = 1.0f;
+ wd.ui_scale = G_draw.block.sizePixel;
+ wd.matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0;
+
+ workbench_studiolight_data_update(wpd, &wd);
+ workbench_shadow_data_update(wpd, &wd);
+ workbench_cavity_data_update(wpd, &wd);
+ workbench_viewvecs_update(wd.viewvecs);
+
+ DRW_uniformbuffer_update(wpd->world_ubo, &wd);
}
-void workbench_private_data_free(WORKBENCH_PrivateData *wpd)
+void workbench_update_material_ubos(WORKBENCH_PrivateData *UNUSED(wpd))
{
- BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
- BLI_ghash_free(wpd->material_transp_hash, NULL, MEM_freeN);
-
- if (wpd->is_world_ubo_owner) {
- DRW_UBO_FREE_SAFE(wpd->world_ubo);
- }
- else {
- wpd->world_ubo = NULL;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
+
+ BLI_memblock_iter iter, iter_data;
+ BLI_memblock_iternew(vldata->material_ubo, &iter);
+ BLI_memblock_iternew(vldata->material_ubo_data, &iter_data);
+ WORKBENCH_UBO_Material *matchunk;
+ while ((matchunk = BLI_memblock_iterstep(&iter_data))) {
+ GPUUniformBuffer **ubo = BLI_memblock_iterstep(&iter);
+ BLI_assert(*ubo != NULL);
+ GPU_uniformbuffer_update(*ubo, matchunk);
}
- DRW_UBO_FREE_SAFE(wpd->dof_ubo);
+ BLI_memblock_clear(vldata->material_ubo, workbench_ubo_free);
+ BLI_memblock_clear(vldata->material_ubo_data, NULL);
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
deleted file mode 100644
index df9a597faf9..00000000000
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ /dev/null
@@ -1,1415 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "workbench_private.h"
-
-#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
-#include "BLI_utildefines.h"
-#include "BLI_rand.h"
-#include "BLI_string_utils.h"
-
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-
-#include "DNA_image_types.h"
-#include "DNA_fluid_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_node_types.h"
-
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-#include "GPU_extensions.h"
-
-#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
-
-/* *********** STATIC *********** */
-
-/* #define DEBUG_SHADOW_VOLUME */
-
-#ifdef DEBUG_SHADOW_VOLUME
-# include "draw_debug.h"
-#endif
-
-typedef struct WORKBENCH_DEFERRED_Shaders {
- struct GPUShader *prepass_sh_cache[MAX_PREPASS_SHADERS];
-} WORKBENCH_DEFERRED_Shaders;
-
-static struct {
- WORKBENCH_DEFERRED_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
- struct GPUShader *composite_sh_cache[MAX_COMPOSITE_SHADERS];
- struct GPUShader *cavity_sh[MAX_CAVITY_SHADERS];
- struct GPUShader *background_sh[2];
- struct GPUShader *ghost_resolve_sh;
- struct GPUShader *shadow_fail_sh;
- struct GPUShader *shadow_fail_manifold_sh;
- struct GPUShader *shadow_pass_sh;
- struct GPUShader *shadow_pass_manifold_sh;
- struct GPUShader *shadow_caps_sh;
- struct GPUShader *shadow_caps_manifold_sh;
- struct GPUShader *oit_resolve_sh;
-
- /* TODO(fclem) move everything below to wpd and custom viewlayer data. */
- struct GPUTexture *oit_accum_tx; /* ref only, not alloced */
- struct GPUTexture *oit_revealage_tx; /* ref only, not alloced */
- struct GPUTexture *object_id_tx; /* ref only, not alloced */
- struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-
- SceneDisplay display; /* world light direction for shadows */
-
- struct GPUUniformBuffer *sampling_ubo;
- struct GPUTexture *jitter_tx;
- int cached_sample_num;
-} e_data = {{{{NULL}}}};
-
-/* Shaders */
-extern char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_workbench_prepass_vert_glsl[];
-extern char datatoc_workbench_prepass_frag_glsl[];
-extern char datatoc_workbench_cavity_frag_glsl[];
-extern char datatoc_workbench_forward_composite_frag_glsl[];
-extern char datatoc_workbench_deferred_composite_frag_glsl[];
-extern char datatoc_workbench_deferred_background_frag_glsl[];
-extern char datatoc_workbench_ghost_resolve_frag_glsl[];
-
-extern char datatoc_workbench_shadow_vert_glsl[];
-extern char datatoc_workbench_shadow_geom_glsl[];
-extern char datatoc_workbench_shadow_caps_geom_glsl[];
-extern char datatoc_workbench_shadow_debug_frag_glsl[];
-
-extern char datatoc_workbench_cavity_lib_glsl[];
-extern char datatoc_workbench_common_lib_glsl[];
-extern char datatoc_workbench_data_lib_glsl[];
-extern char datatoc_workbench_object_outline_lib_glsl[];
-extern char datatoc_workbench_curvature_lib_glsl[];
-extern char datatoc_workbench_world_light_lib_glsl[];
-
-extern char datatoc_gpu_shader_depth_only_frag_glsl[];
-
-static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
-
- if (!FLAT_ENABLED(wpd)) {
- BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
- }
- if (OBJECT_OUTLINE_ENABLED(wpd)) {
- BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
- }
- if (CURVATURE_ENABLED(wpd)) {
- BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
- }
-
- BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_prepass_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_prepass_vert(bool is_hair)
-{
- DynStr *ds = BLI_dynstr_new();
- if (is_hair) {
- BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
- }
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_dpi)
-{
- DynStr *ds = BLI_dynstr_new();
-
- if (cavity) {
- BLI_dynstr_append(ds, "#define USE_CAVITY\n");
- }
- if (curvature) {
- BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
- }
- if (high_dpi) {
- BLI_dynstr_append(ds, "#define CURVATURE_OFFSET 2\n");
- }
- if (NORMAL_ENCODING_ENABLED()) {
- BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
- }
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature)
-{
- const bool high_dpi = (U.pixelsize > 1.5f);
- int index = 0;
- SET_FLAG_FROM_TEST(index, cavity, 1 << 0);
- SET_FLAG_FROM_TEST(index, curvature, 1 << 1);
- SET_FLAG_FROM_TEST(index, high_dpi, 1 << 2);
-
- GPUShader **sh = &e_data.cavity_sh[index];
- if (*sh == NULL) {
- char *cavity_frag = workbench_build_cavity_frag(cavity, curvature, high_dpi);
- *sh = DRW_shader_create_fullscreen(cavity_frag, NULL);
- MEM_freeN(cavity_frag);
- }
- return *sh;
-}
-
-static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override,
- eGPUShaderConfig sh_cfg)
-{
- WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg];
- int index = workbench_material_get_prepass_shader_index(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- if (sh_data->prepass_sh_cache[index] == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- char *prepass_vert = workbench_build_prepass_vert(is_hair);
- char *prepass_frag = workbench_build_prepass_frag();
- sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, prepass_vert, NULL},
- .frag = (const char *[]){prepass_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
- });
- MEM_freeN(prepass_vert);
- MEM_freeN(prepass_frag);
- MEM_freeN(defines);
- }
- return sh_data->prepass_sh_cache[index];
-}
-
-static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd)
-{
- int index = workbench_material_get_composite_shader_index(wpd);
- if (e_data.composite_sh_cache[index] == NULL) {
- char *defines = workbench_material_build_defines(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *composite_frag = workbench_build_composite_frag(wpd);
- e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
- MEM_freeN(composite_frag);
- MEM_freeN(defines);
- }
- return e_data.composite_sh_cache[index];
-}
-
-static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd)
-{
- const int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
- if (e_data.background_sh[index] == NULL) {
- const char *defines = (index) ? "#define V3D_SHADING_OBJECT_OUTLINE\n" : NULL;
- char *frag = BLI_string_joinN(datatoc_workbench_data_lib_glsl,
- datatoc_workbench_common_lib_glsl,
- datatoc_workbench_object_outline_lib_glsl,
- datatoc_workbench_deferred_background_frag_glsl);
- e_data.background_sh[index] = DRW_shader_create_fullscreen(frag, defines);
- MEM_freeN(frag);
- }
- return e_data.background_sh[index];
-}
-
-static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
-{
- wpd->prepass_sh = ensure_deferred_prepass_shader(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_hair_sh = ensure_deferred_prepass_shader(
- wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(
- wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(
- wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_textured_sh = ensure_deferred_prepass_shader(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->prepass_textured_array_sh = ensure_deferred_prepass_shader(
- wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->prepass_vertex_sh = ensure_deferred_prepass_shader(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
- wpd->composite_sh = ensure_deferred_composite_shader(wpd);
- wpd->background_sh = ensure_background_shader(wpd);
-}
-
-/* Using Hammersley distribution */
-static float *create_disk_samples(int num_samples, int num_iterations)
-{
- /* vec4 to ensure memory alignment. */
- const int total_samples = num_samples * num_iterations;
- float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * total_samples, __func__);
- const float num_samples_inv = 1.0f / num_samples;
-
- for (int i = 0; i < total_samples; i++) {
- float it_add = (i / num_samples) * 0.499f;
- float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
- double dphi;
- BLI_hammersley_1d(i, &dphi);
-
- float phi = (float)dphi * 2.0f * M_PI + it_add;
- texels[i][0] = cosf(phi);
- texels[i][1] = sinf(phi);
- /* This deliberately distribute more samples
- * at the center of the disk (and thus the shadow). */
- texels[i][2] = r;
- }
-
- return (float *)texels;
-}
-
-static struct GPUTexture *create_jitter_texture(int num_samples)
-{
- float jitter[64 * 64][4];
- const float num_samples_inv = 1.0f / num_samples;
-
- for (int i = 0; i < 64 * 64; i++) {
- float phi = blue_noise[i][0] * 2.0f * M_PI;
- /* This rotate the sample per pixels */
- jitter[i][0] = cosf(phi);
- jitter[i][1] = sinf(phi);
- /* This offset the sample along it's direction axis (reduce banding) */
- float bn = blue_noise[i][1] - 0.5f;
- CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
- jitter[i][2] = bn * num_samples_inv;
- jitter[i][3] = blue_noise[i][1];
- }
-
- UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
-
- return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
-}
-/* Functions */
-
-static void workbench_init_object_data(DrawData *dd)
-{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->shadow_bbox_dirty = true;
-}
-
-static void workbench_init_oit_framebuffer(WORKBENCH_FramebufferList *fbl,
- DefaultTextureList *dtxl)
-{
- const float *size = DRW_viewport_size_get();
- e_data.oit_accum_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
- e_data.oit_revealage_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16F, &draw_engine_workbench_solid);
-
- GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.oit_accum_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.oit_revealage_tx),
- });
-}
-
-void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
- View3D *v3d = draw_ctx->v3d;
- Scene *scene = draw_ctx->scene;
- Object *camera;
-
- if (v3d && rv3d) {
- camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
- }
- else {
- camera = scene->camera;
- }
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
- if (!stl->effects) {
- stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
- workbench_effect_info_init(stl->effects);
- }
-
- if (!e_data.shadow_pass_sh) {
- WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache));
- memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache));
-#ifdef DEBUG_SHADOW_VOLUME
- const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
-#else
- const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl;
-#endif
- /* TODO only compile on demand */
- e_data.shadow_pass_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_PASS\n"
- "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- e_data.shadow_pass_manifold_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_PASS\n", NULL},
- });
- e_data.shadow_fail_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n"
- "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- e_data.shadow_fail_manifold_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL},
- });
- e_data.shadow_caps_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n"
- "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- e_data.shadow_caps_manifold_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL},
- });
-
- e_data.ghost_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_ghost_resolve_frag_glsl, NULL);
- }
- workbench_volume_engine_init();
- workbench_fxaa_engine_init();
- workbench_taa_engine_init(vedata);
-
- WORKBENCH_PrivateData *wpd = stl->g_data;
- workbench_private_data_init(wpd);
-
- wpd->shading.xray_alpha = 1.0f;
-
- workbench_dof_engine_init(vedata, camera);
-
- if (OIT_ENABLED(wpd)) {
- if (e_data.oit_resolve_sh == NULL) {
- e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_forward_composite_frag_glsl, "#define ALPHA_COMPOSITE\n");
- }
-
- workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg);
- workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
- }
-
- {
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16 : GPU_RGBA32F;
- const eGPUTextureFormat comp_tex_format = GPU_RGBA16F;
- const eGPUTextureFormat col_tex_format = workbench_color_texture_format(wpd);
- const eGPUTextureFormat id_tex_format = OBJECT_ID_PASS_ENABLED(wpd) ? GPU_R32UI : GPU_R8;
-
- e_data.object_id_tx = NULL;
- e_data.color_buffer_tx = NULL;
- e_data.composite_buffer_tx = NULL;
- e_data.normal_buffer_tx = NULL;
- e_data.cavity_buffer_tx = NULL;
-
- e_data.composite_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], comp_tex_format, &draw_engine_workbench_solid);
-
- if (workbench_is_matdata_pass_enabled(wpd) || GPU_unused_fb_slot_workaround()) {
- e_data.color_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], col_tex_format, &draw_engine_workbench_solid);
- }
- if (OBJECT_ID_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) {
- e_data.object_id_tx = DRW_texture_pool_query_2d(
- size[0], size[1], id_tex_format, &draw_engine_workbench_solid);
- }
- if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
- e_data.normal_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], nor_tex_format, &draw_engine_workbench_solid);
- }
- if (CAVITY_ENABLED(wpd)) {
- e_data.cavity_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16, &draw_engine_workbench_solid);
- }
-
- GPU_framebuffer_ensure_config(&fbl->prepass_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->cavity_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->composite_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->color_only_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
- });
-
- if (!workbench_is_matdata_pass_enabled(wpd) && !GPU_unused_fb_slot_workaround()) {
- e_data.color_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], col_tex_format, &draw_engine_workbench_solid);
- }
-
- GPU_framebuffer_ensure_config(&fbl->effect_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- });
-
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- GPU_framebuffer_ensure_config(&fbl->id_clear_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- });
- }
- }
-
- {
- /* AO Samples Tex */
- int num_iterations = workbench_taa_calculate_num_iterations(vedata);
-
- const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples;
- const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500);
-
- if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) {
- DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
- DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
- }
-
- if (e_data.sampling_ubo == NULL) {
- float *samples = create_disk_samples(ssao_samples_single_iteration, num_iterations);
- e_data.jitter_tx = create_jitter_texture(ssao_samples);
- e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples);
- e_data.cached_sample_num = ssao_samples;
- MEM_freeN(samples);
- }
- }
-
- /* Prepass */
- {
- DRWShadingGroup *grp;
- DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
- DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
-
- psl->prepass_pass = DRW_pass_create("Prepass", state | cull_state | clip_state);
- psl->prepass_hair_pass = DRW_pass_create("Prepass", state | clip_state);
-
- psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost", state | cull_state | clip_state);
- psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state | clip_state);
-
- psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
- grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- {
- workbench_aa_create_pass(vedata, &e_data.color_buffer_tx);
- }
-
- {
- workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx, e_data.jitter_tx);
- }
-
- if (CAVITY_ENABLED(wpd)) {
- int state = DRW_STATE_WRITE_COLOR;
- GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
- psl->cavity_pass = DRW_pass_create("Cavity", state);
- DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass);
- DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
- DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo);
-
- if (SSAO_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1);
- DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1);
- DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat);
- DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx);
- }
-
- if (CURVATURE_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1);
- }
-
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-}
-
-void workbench_deferred_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- for (int index = 0; index < MAX_PREPASS_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(sh_data->prepass_sh_cache[index]);
- }
- }
- for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
- }
- for (int index = 0; index < MAX_CAVITY_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]);
- }
- DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh);
- DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
- DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
- DRW_SHADER_FREE_SAFE(e_data.background_sh[0]);
- DRW_SHADER_FREE_SAFE(e_data.background_sh[1]);
-
- DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
-
- DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh);
-
- workbench_volume_engine_free();
- workbench_fxaa_engine_free();
- workbench_taa_engine_free();
- workbench_dof_engine_free();
-}
-
-static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
-{
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- if (workbench_is_matdata_pass_enabled(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx);
- }
- else {
- DRW_shgroup_uniform_vec3(grp, "materialSingleColor", wpd->shading.single_color, 1);
- }
- if (OBJECT_OUTLINE_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- }
- if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
- }
- if (CAVITY_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
- }
- if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- }
- if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- }
- if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light,
- STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
- STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
- DRW_shgroup_uniform_texture(
- grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- DRW_shgroup_uniform_texture(
- grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
- }
- }
-}
-
-void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- DRWShadingGroup *grp;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- Scene *scene = draw_ctx->scene;
-
- workbench_volume_cache_init(vedata);
- select_deferred_shaders(wpd, draw_ctx->sh_cfg);
-
- /* Background Pass */
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
- if (DRW_state_is_scene_render()) {
- /* Composite the scene over cleared background. */
- state |= DRW_STATE_BLEND_ALPHA_PREMUL;
- }
- psl->background_pass = DRW_pass_create("Background", state);
- grp = DRW_shgroup_create(wpd->background_sh, psl->background_pass);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- if (OBJECT_OUTLINE_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- }
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- /* Deferred Mix Pass */
- {
- workbench_private_data_get_light_direction(e_data.display.light_direction);
- studiolight_update_light(wpd, e_data.display.light_direction);
-
- if (SHADOW_ENABLED(wpd)) {
- psl->composite_pass = DRW_pass_create(
- "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_DEPTH_GREATER);
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
- workbench_composite_uniforms(wpd, grp);
- DRW_shgroup_stencil_mask(grp, 0x00);
- DRW_shgroup_uniform_float_copy(grp, "lightMultiplier", 1.0f);
- DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1);
- DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift);
- DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-
- /* Stencil Shadow passes. */
-#ifdef DEBUG_SHADOW_VOLUME
- DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR |
- DRW_STATE_BLEND_ADD;
- DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR |
- DRW_STATE_BLEND_ADD;
-#else
- DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS |
- DRW_STATE_STENCIL_ALWAYS;
- DRWState depth_fail_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL |
- DRW_STATE_STENCIL_ALWAYS;
-#endif
- psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Pass", depth_pass_state);
- psl->shadow_depth_pass_mani_pass = DRW_pass_create("Shadow Pass Mani", depth_pass_state);
- psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Fail", depth_fail_state);
- psl->shadow_depth_fail_mani_pass = DRW_pass_create("Shadow Fail Mani", depth_fail_state);
- psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Fail Caps", depth_fail_state);
- psl->shadow_depth_fail_caps_mani_pass = DRW_pass_create("Shadow Fail Caps Mani",
- depth_fail_state);
-
-#ifndef DEBUG_SHADOW_VOLUME
- grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh,
- psl->shadow_depth_fail_caps_mani_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
-
- psl->composite_shadow_pass = DRW_pass_create(
- "Composite Shadow",
- DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_DEPTH_GREATER);
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_shadow_pass);
- DRW_shgroup_stencil_mask(grp, 0x00);
- workbench_composite_uniforms(wpd, grp);
- DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1);
- DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1);
- DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift);
- DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-#endif
- }
- else {
- psl->composite_pass = DRW_pass_create("Composite",
- DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER);
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
- workbench_composite_uniforms(wpd, grp);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
- }
-
- /**
- * Order Independent Transparency.
- * Similar to workbench forward. Duplicated code to avoid
- * spaghetti with workbench forward. It would be great if we unify
- * this in a clean way.
- */
- if (OIT_ENABLED(wpd)) {
- DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
- DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
- /* Transparency Accum */
- {
- /* Same as forward but here we use depth test to
- * not bleed through other solid objects. */
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND_OIT | cull_state |
- clip_state;
- psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
- }
- /* Depth */
- {
- int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | clip_state;
- psl->object_outline_pass = DRW_pass_create("Transparent Depth", state);
- }
- /* OIT Composite */
- {
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
- psl->oit_composite_pass = DRW_pass_create("OIT Composite", state);
-
- grp = DRW_shgroup_create(e_data.oit_resolve_sh, psl->oit_composite_pass);
- DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.oit_accum_tx);
- DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.oit_revealage_tx);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
- }
-}
-
-static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata,
- Object *ob,
- Material *mat,
- Image *ima,
- ImageUser *iuser,
- eV3DShadingColorType color_type,
- int interp)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_MaterialData *material;
- WORKBENCH_MaterialData material_template;
- const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
-
- /* Solid */
- workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.color_type = color_type;
- material_template.ima = ima;
- material_template.iuser = iuser;
- material_template.interp = interp;
- uint hash = workbench_material_get_hash(&material_template, is_ghost);
-
- material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash));
- if (material == NULL) {
- material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
- /* select the correct prepass shader */
- GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh :
- wpd->prepass_uniform_sh;
- const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
- if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- shader = is_tiled ? wpd->prepass_textured_array_sh : wpd->prepass_textured_sh;
- }
- if (color_type == V3D_SHADING_VERTEX_COLOR) {
- shader = wpd->prepass_vertex_sh;
- }
- material->shgrp = DRW_shgroup_create(
- shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
- workbench_material_copy(material, &material_template);
- DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, is_tiled, interp);
- BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
- }
- return material;
-}
-
-static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
- if (md->type != eModifierType_ParticleSystem) {
- continue;
- }
- ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
- if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
- continue;
- }
- ParticleSettings *part = psys->part;
- const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
-
- if (draw_as == PART_DRAW_PATH) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, false);
- WORKBENCH_MaterialData *material = get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
-
- struct GPUShader *shader = (wpd->shading.color_type == color_type) ?
- wpd->prepass_hair_sh :
- wpd->prepass_uniform_hair_sh;
- DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
- ob,
- psys,
- md,
- (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
- shader);
- DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, false, interp);
- }
- }
-}
-
-static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- /* Force workbench to render active object textured when in texture paint mode */
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* Single Image mode */
- if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- Image *image = imapaint->canvas;
- int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
- SHD_INTERP_CLOSEST;
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
- material = get_or_create_material_data(vedata, ob, NULL, image, NULL, color_type, interp);
-
- DRW_shgroup_call(material->shgrp, geom, ob);
- }
- else {
- /* IMAGEPAINT_MODE_MATERIAL */
- const int materials_len = DRW_cache_object_material_count_get(ob);
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- if (geom_array != NULL && geom_array[i] != NULL) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- material = get_or_create_material_data(vedata, ob, mat, image, iuser, color_type, interp);
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- }
- }
- }
-}
-
-static void workbench_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, false);
- DRW_shgroup_call(material->shgrp, geom, ob);
-}
-
-void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
-
- if (!DRW_object_is_renderable(ob)) {
- return;
- }
-
- if (ob->type == OB_MESH) {
- workbench_cache_populate_particles(vedata, ob);
- }
-
- ModifierData *md;
- if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((FluidModifierData *)md)->domain != NULL) &&
- (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
- workbench_volume_cache_populate(vedata, scene, ob, md);
- return; /* Do not draw solid in this case. */
- }
-
- if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
- return;
- }
- if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
- return;
- }
-
- WORKBENCH_MaterialData *material;
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool is_active = (ob == draw_ctx->obact);
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
- const int materials_len = DRW_cache_object_material_count_get(ob);
- const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- bool has_transp_mat = false;
- const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
- const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
- me && me->mloopuv;
- const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
- me && me->mloopcol;
-
- if (use_texture_paint_drawing) {
- workbench_cache_populate_texture_paint_mode(vedata, ob);
- }
- else if (use_vertex_paint_drawing) {
- workbench_cache_populate_vertex_paint_mode(vedata, ob);
- }
- else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
- /* Draw textured */
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- if (geom_array != NULL && geom_array[i] != NULL) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- if (color_type == V3D_SHADING_MATERIAL_COLOR && mat && mat->a < 1.0) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, 0);
- has_transp_mat = true;
- }
- else {
- material = get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
- }
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- }
- }
- }
- else if (ELEM(wpd->shading.color_type,
- V3D_SHADING_SINGLE_COLOR,
- V3D_SHADING_OBJECT_COLOR,
- V3D_SHADING_RANDOM_COLOR,
- V3D_SHADING_VERTEX_COLOR)) {
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
-
- if ((ob->color[3] < 1.0f) && (color_type == V3D_SHADING_OBJECT_COLOR)) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, 0);
- has_transp_mat = true;
- }
- else {
- /* Draw solid color */
- material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0);
- }
-
- if (use_sculpt_pbvh) {
- bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
- DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol);
- }
- else {
- struct GPUBatch *geom;
- if (color_type == V3D_SHADING_VERTEX_COLOR) {
- geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- }
- else {
- geom = DRW_cache_object_surface_get(ob);
- }
-
- if (geom) {
- DRW_shgroup_call(material->shgrp, geom, ob);
- }
- }
- }
- else {
- /* Draw material color */
- if (use_sculpt_pbvh) {
- struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
-
- for (int i = 0; i < materials_len; i++) {
- struct Material *mat = BKE_object_material_get(ob, i + 1);
- if (mat != NULL && mat->a < 1.0f) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- has_transp_mat = true;
- }
- else {
- material = get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- }
- shgrps[i] = material->shgrp;
- }
- DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
- }
- else {
- struct GPUBatch **geoms;
- struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
- memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
-
- geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
- for (int i = 0; i < materials_len; i++) {
- if (geoms != NULL && geoms[i] != NULL) {
- Material *mat = BKE_object_material_get(ob, i + 1);
- if (mat != NULL && mat->a < 1.0f) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- has_transp_mat = true;
- }
- else {
- material = get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- }
- DRW_shgroup_call(material->shgrp, geoms[i], ob);
- }
- }
- }
- }
-
- if (SHADOW_ENABLED(wpd) && !(ob->dtx & OB_DRAW_NO_SHADOW_CAST)) {
- bool is_manifold;
- struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold);
- if (geom_shadow) {
- if (use_sculpt_pbvh || use_hide) {
- /* Currently unsupported in sculpt mode. We could revert to the slow
- * method in this case but I'm not sure if it's a good idea given that
- * sculpted meshes are heavy to begin with. */
- // DRW_shgroup_call_sculpt(wpd->shadow_shgrp, ob, ob->obmat);
- }
- else {
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
-
- if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
-
- mul_v3_mat3_m4v3(
- engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction);
-
- DRWShadingGroup *grp;
- bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow(
- wpd, ob, engine_object_data);
-
- if (use_shadow_pass_technique && !has_transp_mat) {
- if (is_manifold) {
- grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh,
- psl->shadow_depth_pass_mani_pass);
- }
- else {
- grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
- }
- DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
- DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f);
- DRW_shgroup_call_no_cull(grp, geom_shadow, ob);
-#ifdef DEBUG_SHADOW_VOLUME
- DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
-#endif
- }
- else {
- float extrude_distance = studiolight_object_shadow_distance(
- wpd, ob, engine_object_data);
-
- /* TODO(fclem): only use caps if they are in the view frustum. */
- const bool need_caps = true;
- if (need_caps) {
- if (is_manifold) {
- grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh,
- psl->shadow_depth_fail_caps_mani_pass);
- }
- else {
- grp = DRW_shgroup_create(e_data.shadow_caps_sh,
- psl->shadow_depth_fail_caps_pass);
- }
- DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
- DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
- DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob);
- }
-
- if (is_manifold) {
- grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh,
- psl->shadow_depth_fail_mani_pass);
- }
- else {
- grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
- }
- DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
- DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
- DRW_shgroup_call_no_cull(grp, geom_shadow, ob);
-#ifdef DEBUG_SHADOW_VOLUME
- DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
-#endif
- }
- }
- }
- }
- }
- }
-}
-
-void workbench_deferred_cache_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
-
- if (GHOST_ENABLED(psl)) {
- /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
-
- GPU_framebuffer_ensure_config(
- &dfbl->default_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
- GPU_framebuffer_ensure_config(
- &dfbl->in_front_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
-
- GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
- });
- }
-}
-
-void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- if (workbench_is_taa_enabled(wpd)) {
- workbench_taa_draw_scene_start(vedata);
- }
-
- const float clear_depth = 1.0f;
- const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- uint clear_stencil = 0x00;
- int clear_bits = GPU_DEPTH_BIT;
- SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT);
-
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- /* From all the color buffers, only object id needs to be cleared. */
- GPU_framebuffer_bind(fbl->id_clear_fb);
- GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
- }
-
- GPU_framebuffer_bind(fbl->prepass_fb);
- GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_col, clear_depth, clear_stencil);
-
- DRW_draw_pass(psl->prepass_pass);
- DRW_draw_pass(psl->prepass_hair_pass);
-
- if (fbl->ghost_prepass_fb) {
- GPU_framebuffer_bind(fbl->ghost_prepass_fb);
- GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f);
- }
- else if (dtxl->depth_in_front) {
- /* TODO(fclem) This clear should be done in a global place. */
- GPU_framebuffer_bind(dfbl->in_front_fb);
- GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
- }
-
- if (GHOST_ENABLED(psl)) {
- DRW_draw_pass(psl->ghost_prepass_pass);
- DRW_draw_pass(psl->ghost_prepass_hair_pass);
-
- GPU_framebuffer_bind(dfbl->depth_only_fb);
- DRW_draw_pass(psl->ghost_resolve_pass);
- }
-
- if (CAVITY_ENABLED(wpd)) {
- GPU_framebuffer_bind(fbl->cavity_fb);
- DRW_draw_pass(psl->cavity_pass);
- }
-
- if (DRW_state_is_scene_render()) {
- float clear_color[4];
- workbench_clear_color_get(clear_color);
- GPU_framebuffer_bind(fbl->composite_fb);
- GPU_framebuffer_clear_color(fbl->composite_fb, clear_color);
- }
-
- if (SHADOW_ENABLED(wpd)) {
-#ifdef DEBUG_SHADOW_VOLUME
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->composite_pass);
-#else
- GPU_framebuffer_bind(dfbl->depth_only_fb);
-#endif
- DRW_draw_pass(psl->shadow_depth_pass_pass);
- DRW_draw_pass(psl->shadow_depth_pass_mani_pass);
- DRW_draw_pass(psl->shadow_depth_fail_pass);
- DRW_draw_pass(psl->shadow_depth_fail_mani_pass);
- DRW_draw_pass(psl->shadow_depth_fail_caps_pass);
- DRW_draw_pass(psl->shadow_depth_fail_caps_mani_pass);
-
- if (GHOST_ENABLED(psl)) {
- /* We need to set the stencil buffer to 0 where Ghost objects are
- * else they will get shadow and even badly shadowed. */
- DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
- DRW_pass_state_set(psl->ghost_prepass_pass, state);
- DRW_pass_state_set(psl->ghost_prepass_hair_pass, state);
-
- DRW_draw_pass(psl->ghost_prepass_pass);
- DRW_draw_pass(psl->ghost_prepass_hair_pass);
- }
-#ifndef DEBUG_SHADOW_VOLUME
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->composite_pass);
- DRW_draw_pass(psl->composite_shadow_pass);
-#endif
- }
- else {
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->composite_pass);
- }
-
- /* In order to not draw on top of ghost objects, we clear the stencil
- * to 0xFF and the ghost object to 0x00 and only draw overlays on top if
- * stencil is not 0. */
- /* TODO(fclem) Remove this hack. */
- GPU_framebuffer_bind(dfbl->depth_only_fb);
- GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
-
- /* TODO(fclem): only enable when needed (when there is overlays). */
- if (GHOST_ENABLED(psl)) {
- DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
- DRW_pass_state_set(psl->ghost_prepass_pass, state);
- DRW_pass_state_set(psl->ghost_prepass_hair_pass, state);
-
- DRW_draw_pass(psl->ghost_prepass_pass);
- DRW_draw_pass(psl->ghost_prepass_hair_pass);
- }
-
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->background_pass);
-
- if (OIT_ENABLED(wpd) && !DRW_pass_is_empty(psl->transparent_accum_pass)) {
- /* meh, late init to not request buffers we won't use. */
- workbench_init_oit_framebuffer(fbl, dtxl);
-
- const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- GPU_framebuffer_bind(fbl->transparent_accum_fb);
- GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
- DRW_draw_pass(psl->transparent_accum_pass);
-
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->oit_composite_pass);
- }
-
- if (wpd->volumes_do) {
- GPU_framebuffer_bind(fbl->color_only_fb);
- DRW_draw_pass(psl->volume_pass);
- }
-
- workbench_dof_draw_pass(vedata);
- workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
-}
-
-void workbench_deferred_draw_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- /* XXX TODO(fclem) do not discard UBOS after drawing! Store them per viewport. */
- workbench_private_data_free(wpd);
- workbench_volume_smoke_textures_free(wpd);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c
deleted file mode 100644
index c03fe5cd5c8..00000000000
--- a/source/blender/draw/engines/workbench/workbench_effect_aa.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "ED_screen.h"
-
-#include "draw_color_management.h"
-
-#include "workbench_private.h"
-
-void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if (draw_ctx->evil_C != NULL) {
- struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
- wpd->is_playback = ED_screen_animation_playing(wm) != NULL;
- }
- else {
- wpd->is_playback = false;
- }
-
- if (workbench_is_taa_enabled(wpd)) {
- psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx);
- }
- else if (workbench_is_fxaa_enabled(wpd)) {
- psl->effect_aa_pass = workbench_fxaa_create_pass(tx);
- effect_info->jitter_index = 0;
- }
- else {
- psl->effect_aa_pass = NULL;
- effect_info->jitter_index = 0;
- }
-}
-
-static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *UNUSED(wpd))
-{
- DRW_transform_none(tx);
-}
-
-void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
-
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- if (workbench_is_fxaa_enabled(wpd)) {
- GPU_framebuffer_bind(fbl->effect_fb);
- workspace_aa_draw_transform(tx, wpd);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->effect_aa_pass);
- }
- else if (workbench_is_taa_enabled(wpd)) {
- /*
- * when drawing the first TAA frame, we transform directly to the
- * color_only_fb as the TAA shader is just performing a direct copy.
- * the workbench_taa_draw_screen_end will fill the history buffer
- * for the other iterations.
- */
- if (effect_info->jitter_index == 1) {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- workspace_aa_draw_transform(tx, wpd);
- }
- else {
- GPU_framebuffer_bind(fbl->effect_fb);
- workspace_aa_draw_transform(tx, wpd);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->effect_aa_pass);
- }
- workbench_taa_draw_scene_end(vedata);
- }
- else {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- workspace_aa_draw_transform(tx, wpd);
- }
-}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
new file mode 100644
index 00000000000..3cd21dfeace
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Anti-aliasing:
+ *
+ * We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution.
+ *
+ * If the viewport stays static, the engine ask for multiple redraw and will progressively
+ * converge to a much more accurate image without aliasing.
+ * We call this one TAA (Temporal Anti-Aliasing).
+ *
+ * This is done using an accumulation buffer and a final pass that will output the final color
+ * to the scene buffer. We softly blend between SMAA and TAA to avoid really harsh transitions.
+ */
+
+#include "ED_screen.h"
+
+#include "BLI_jitter_2d.h"
+
+#include "smaa_textures.h"
+
+#include "workbench_private.h"
+
+static struct {
+ bool init;
+ float jitter_5[5][2];
+ float jitter_8[8][2];
+ float jitter_11[11][2];
+ float jitter_16[16][2];
+ float jitter_32[32][2];
+} e_data = {false};
+
+static void workbench_taa_jitter_init_order(float (*table)[2], int num)
+{
+ BLI_jitter_init(table, num);
+
+ /* find closest element to center */
+ int closest_index = 0;
+ float closest_squared_distance = 1.0f;
+
+ for (int index = 0; index < num; index++) {
+ const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]);
+ if (squared_dist < closest_squared_distance) {
+ closest_squared_distance = squared_dist;
+ closest_index = index;
+ }
+ }
+
+ /* move jitter table so that closest sample is in center */
+ for (int index = 0; index < num; index++) {
+ sub_v2_v2(table[index], table[closest_index]);
+ mul_v2_fl(table[index], 2.0f);
+ }
+
+ /* swap center sample to the start of the table */
+ if (closest_index != 0) {
+ swap_v2_v2(table[0], table[closest_index]);
+ }
+
+ /* sort list based on furtest distance with previous */
+ for (int i = 0; i < num - 2; i++) {
+ float f_squared_dist = 0.0;
+ int f_index = i;
+ for (int j = i + 1; j < num; j++) {
+ const float squared_dist = square_f(table[i][0] - table[j][0]) +
+ square_f(table[i][1] - table[j][1]);
+ if (squared_dist > f_squared_dist) {
+ f_squared_dist = squared_dist;
+ f_index = j;
+ }
+ }
+ swap_v2_v2(table[i + 1], table[f_index]);
+ }
+}
+
+static void workbench_taa_jitter_init(void)
+{
+ if (e_data.init == false) {
+ e_data.init = true;
+ workbench_taa_jitter_init_order(e_data.jitter_5, 5);
+ workbench_taa_jitter_init_order(e_data.jitter_8, 8);
+ workbench_taa_jitter_init_order(e_data.jitter_11, 11);
+ workbench_taa_jitter_init_order(e_data.jitter_16, 16);
+ workbench_taa_jitter_init_order(e_data.jitter_32, 32);
+ }
+}
+
+int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+
+ if (wpd->is_navigating || wpd->is_playback) {
+ /* Only draw using SMAA or no AA when navigating. */
+ return min_ii(wpd->preferences->viewport_aa, 1);
+ }
+ else if (DRW_state_is_image_render()) {
+ if (draw_ctx->v3d) {
+ return scene->display.viewport_aa;
+ }
+ else {
+ return scene->display.render_aa;
+ }
+ }
+ else {
+ return wpd->preferences->viewport_aa;
+ }
+}
+
+void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ if (stl && stl->wpd) {
+ stl->wpd->view_updated = true;
+ }
+}
+
+void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ DrawEngineType *owner = (DrawEngineType *)&workbench_antialiasing_engine_init;
+
+ wpd->view = NULL;
+
+ /* reset complete drawing when navigating. */
+ if (wpd->taa_sample != 0) {
+ if (wpd->is_navigating) {
+ wpd->taa_sample = 0;
+ }
+ }
+
+ if (wpd->view_updated) {
+ wpd->taa_sample = 0;
+ wpd->view_updated = false;
+ }
+
+ {
+ float persmat[4][4];
+ DRW_view_persmat_get(NULL, persmat, false);
+ if (!equals_m4m4(persmat, wpd->last_mat)) {
+ copy_m4_m4(wpd->last_mat, persmat);
+ wpd->taa_sample = 0;
+ }
+ }
+
+ if (wpd->taa_sample_len > 0) {
+ workbench_taa_jitter_init();
+
+ DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, DRW_TEX_FILTER);
+ DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
+
+ wpd->smaa_edge_tx = DRW_texture_pool_query_fullscreen(GPU_RG8, owner);
+ wpd->smaa_weight_tx = DRW_texture_pool_query_fullscreen(GPU_RGBA8, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->antialiasing_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->smaa_edge_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->smaa_weight_tx),
+ });
+
+ /* TODO could be shared for all viewports. */
+ if (txl->smaa_search_tx == NULL) {
+ txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH,
+ SEARCHTEX_HEIGHT,
+ 0,
+ 2,
+ searchTexBytes,
+ GPU_R8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH,
+ AREATEX_HEIGHT,
+ 0,
+ 2,
+ areaTexBytes,
+ GPU_RG8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ GPU_texture_bind(txl->smaa_search_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_search_tx, true);
+ GPU_texture_unbind(txl->smaa_search_tx);
+
+ GPU_texture_bind(txl->smaa_area_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_area_tx, true);
+ GPU_texture_unbind(txl->smaa_area_tx);
+ }
+ }
+ else {
+ /* Cleanup */
+ DRW_TEXTURE_FREE_SAFE(txl->history_buffer_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->depth_buffer_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->smaa_search_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->smaa_area_tx);
+ }
+}
+
+void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ if (wpd->taa_sample_len == 0) {
+ return;
+ }
+
+ {
+ DRW_PASS_CREATE(psl->aa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
+
+ GPUShader *shader = workbench_shader_antialiasing_accumulation_get();
+ grp = DRW_shgroup_create(shader, psl->aa_accum_ps);
+ DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ const float *size = DRW_viewport_size_get();
+ const float *sizeinv = DRW_viewport_invert_size_get();
+ float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
+
+ {
+ /* Stage 1: Edge detection. */
+ DRW_PASS_CREATE(psl->aa_edge_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(0);
+ grp = DRW_shgroup_create(sh, psl->aa_edge_ps);
+ DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 2: Blend Weight/Coord. */
+ DRW_PASS_CREATE(psl->aa_weight_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(1);
+ grp = DRW_shgroup_create(sh, psl->aa_weight_ps);
+ DRW_shgroup_uniform_texture(grp, "edgesTex", wpd->smaa_edge_tx);
+ DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx);
+ DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 3: Resolve. */
+ DRW_PASS_CREATE(psl->aa_resolve_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(2);
+ grp = DRW_shgroup_create(sh, psl->aa_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+ DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1);
+ DRW_shgroup_uniform_float(grp, "taaSampleCountInv", &wpd->taa_sample_inv, 1);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+/* Return true if render is not cached. */
+bool workbench_antialiasing_setup(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+
+ if (wpd->taa_sample_len == 0) {
+ /* AA disabled. */
+ return true;
+ }
+
+ if (wpd->taa_sample >= wpd->taa_sample_len) {
+ /* TAA accumulation has finish. Just copy the result back */
+ return false;
+ }
+ else {
+ const float *viewport_size = DRW_viewport_size_get();
+ const DRWView *default_view = DRW_view_default_get();
+ float *transform_offset;
+
+ switch (wpd->taa_sample_len) {
+ default:
+ case 5:
+ transform_offset = e_data.jitter_5[min_ii(wpd->taa_sample, 5)];
+ break;
+ case 8:
+ transform_offset = e_data.jitter_8[min_ii(wpd->taa_sample, 8)];
+ break;
+ case 11:
+ transform_offset = e_data.jitter_11[min_ii(wpd->taa_sample, 11)];
+ break;
+ case 16:
+ transform_offset = e_data.jitter_16[min_ii(wpd->taa_sample, 16)];
+ break;
+ case 32:
+ transform_offset = e_data.jitter_32[min_ii(wpd->taa_sample, 32)];
+ break;
+ }
+
+ /* construct new matrices from transform delta */
+ float winmat[4][4], viewmat[4][4], persmat[4][4];
+ DRW_view_winmat_get(default_view, winmat, false);
+ DRW_view_viewmat_get(default_view, viewmat, false);
+ DRW_view_persmat_get(default_view, persmat, false);
+
+ window_translate_m4(winmat,
+ persmat,
+ transform_offset[0] / viewport_size[0],
+ transform_offset[1] / viewport_size[1]);
+
+ if (wpd->view) {
+ /* When rendering just update the view. This avoids recomputing the culling. */
+ DRW_view_update_sub(wpd->view, viewmat, winmat);
+ }
+ else {
+ /* TAA is not making a big change to the matrices.
+ * Reuse the main view culling by creating a sub-view. */
+ wpd->view = DRW_view_create_sub(default_view, viewmat, winmat);
+ }
+ DRW_view_set_active(wpd->view);
+ return true;
+ }
+}
+
+void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (wpd->taa_sample_len == 0) {
+ /* AA disabled. */
+ /* Just set sample to 1 to avoid rendering indefinitely. */
+ wpd->taa_sample = 1;
+ return;
+ }
+
+ /**
+ * We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already
+ * high. This ensure a smoother transition.
+ * If TAA accumulation is finished, we only blit the result.
+ */
+
+ if (wpd->taa_sample == 0) {
+ /* In playback mode, we are sure the next redraw will not use the same viewmatrix.
+ * In this case no need to save the depth buffer. */
+ eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0);
+ GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits);
+ }
+ else {
+ /* Accumulate result to the TAA buffer. */
+ GPU_framebuffer_bind(fbl->antialiasing_fb);
+ DRW_draw_pass(psl->aa_accum_ps);
+ /* Copy back the saved depth buffer for correct overlays. */
+ GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
+ }
+
+ if (!DRW_state_is_image_render() || wpd->taa_sample + 1 == wpd->taa_sample_len) {
+ /* After a certain point SMAA is no longer necessary. */
+ wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f);
+ wpd->taa_sample_inv = 1.0f / (wpd->taa_sample + 1);
+
+ if (wpd->smaa_mix_factor > 0.0f) {
+ GPU_framebuffer_bind(fbl->smaa_edge_fb);
+ DRW_draw_pass(psl->aa_edge_ps);
+
+ GPU_framebuffer_bind(fbl->smaa_weight_fb);
+ DRW_draw_pass(psl->aa_weight_ps);
+ }
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->aa_resolve_ps);
+ }
+
+ wpd->taa_sample++;
+
+ if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) {
+ DRW_viewport_request_redraw();
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
new file mode 100644
index 00000000000..cdf8a93fc57
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Cavity Effect:
+ *
+ * We use Screen Space Ambient Occlusion (SSAO) to enhance geometric details of the surfaces.
+ * We also use a Curvature effect computed only using the surface normals.
+ *
+ * This is done after the opaque pass. It only affects the opaque surfaces.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_rand.h"
+
+#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+#define JITTER_TEX_SIZE 64
+#define CAVITY_MAX_SAMPLES 512
+
+/* Using Hammersley distribution */
+static float *create_disk_samples(int num_samples, int num_iterations)
+{
+ const int total_samples = num_samples * num_iterations;
+ const float num_samples_inv = 1.0f / num_samples;
+ /* vec4 to ensure memory alignment. */
+ float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__);
+
+ for (int i = 0; i < total_samples; i++) {
+ float it_add = (i / num_samples) * 0.499f;
+ float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
+ double dphi;
+ BLI_hammersley_1d(i, &dphi);
+
+ float phi = (float)dphi * 2.0f * M_PI + it_add;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ /* This deliberately distribute more samples
+ * at the center of the disk (and thus the shadow). */
+ texels[i][2] = r;
+ }
+
+ return (float *)texels;
+}
+
+static struct GPUTexture *create_jitter_texture(int num_samples)
+{
+ float jitter[64 * 64][4];
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < 64 * 64; i++) {
+ float phi = blue_noise[i][0] * 2.0f * M_PI;
+ /* This rotate the sample per pixels */
+ jitter[i][0] = cosf(phi);
+ jitter[i][1] = sinf(phi);
+ /* This offset the sample along it's direction axis (reduce banding) */
+ float bn = blue_noise[i][1] - 0.5f;
+ CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
+ jitter[i][2] = bn * num_samples_inv;
+ jitter[i][3] = blue_noise[i][1];
+ }
+
+ UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
+
+ return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]);
+}
+
+BLI_INLINE int workbench_cavity_total_sample_count(const WORKBENCH_PrivateData *wpd,
+ const Scene *scene)
+{
+ return min_ii(max_ii(1, wpd->taa_sample_len) * scene->display.matcap_ssao_samples,
+ CAVITY_MAX_SAMPLES);
+}
+
+void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
+{
+ View3DShading *shading = &wpd->shading;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ if (CAVITY_ENABLED(wpd)) {
+ int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
+ int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene);
+ int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration;
+
+ int sample = wpd->taa_sample % max_iter_count;
+ wd->cavity_sample_start = cavity_sample_count_single_iteration * sample;
+ wd->cavity_sample_end = cavity_sample_count_single_iteration * (sample + 1);
+
+ wd->cavity_sample_count_inv = 1.0f / (wd->cavity_sample_end - wd->cavity_sample_start);
+ wd->cavity_jitter_scale = 1.0f / 64.0f;
+
+ wd->cavity_valley_factor = shading->cavity_valley_factor;
+ wd->cavity_ridge_factor = shading->cavity_ridge_factor;
+ wd->cavity_attenuation = scene->display.matcap_ssao_attenuation;
+ wd->cavity_distance = scene->display.matcap_ssao_distance;
+
+ wd->curvature_ridge = 0.5f / max_ff(square_f(shading->curvature_ridge_factor), 1e-4f);
+ wd->curvature_valley = 0.7f / max_ff(square_f(shading->curvature_valley_factor), 1e-4f);
+ }
+}
+
+void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
+ int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene);
+
+ if (wpd->vldata->cavity_sample_count != cavity_sample_count) {
+ DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo);
+ DRW_TEXTURE_FREE_SAFE(wpd->vldata->cavity_jitter_tx);
+ }
+
+ if (wpd->vldata->cavity_sample_ubo == NULL) {
+ float *samples = create_disk_samples(cavity_sample_count_single_iteration,
+ max_ii(1, wpd->taa_sample_len));
+ wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count);
+ /* NOTE: Uniform buffer needs to always be filled to be valid. */
+ wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create(
+ sizeof(float[4]) * CAVITY_MAX_SAMPLES, samples);
+ wpd->vldata->cavity_sample_count = cavity_sample_count;
+ MEM_freeN(samples);
+ }
+}
+
+void workbench_cavity_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (CAVITY_ENABLED(wpd)) {
+ workbench_cavity_samples_ubo_ensure(wpd);
+
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
+ DRW_PASS_CREATE(psl->cavity_ps, state);
+
+ sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
+
+ grp = DRW_shgroup_create(sh, psl->cavity_ps);
+ DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
+ DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+
+ if (SSAO_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
+ DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx);
+ }
+ if (CURVATURE_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
+ }
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else {
+ psl->cavity_ps = NULL;
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index ae3e2218463..9716ccd4b44 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_dof.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -18,6 +18,17 @@
/** \file
* \ingroup draw_engine
+ *
+ * Depth of Field Effect:
+ *
+ * We use a gather approach by sampling a lowres version of the color buffer.
+ * The process can be summarized like this:
+ * - down-sample the color buffer using a COC (Circle of Confusion) aware down-sample algorithm.
+ * - do a gather pass using the COC computed in the previous pass.
+ * - do a median filter to reduce noise amount.
+ * - composite on top of main color buffer.
+ *
+ * This is done after all passes and affects every surfaces.
*/
#include "workbench_private.h"
@@ -27,24 +38,6 @@
#include "DNA_camera_types.h"
-/* *********** STATIC *********** */
-static struct {
- struct GPUShader *effect_dof_prepare_sh;
- struct GPUShader *effect_dof_downsample_sh;
- struct GPUShader *effect_dof_flatten_v_sh;
- struct GPUShader *effect_dof_flatten_h_sh;
- struct GPUShader *effect_dof_dilate_v_sh;
- struct GPUShader *effect_dof_dilate_h_sh;
- struct GPUShader *effect_dof_blur1_sh;
- struct GPUShader *effect_dof_blur2_sh;
- struct GPUShader *effect_dof_resolve_sh;
-} e_data = {NULL};
-
-/* Shaders */
-extern char datatoc_workbench_effect_dof_frag_glsl[];
-
-/* *********** Functions *********** */
-
/**
* Transform [-1..1] square to unit circle.
*/
@@ -130,52 +123,40 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo,
DRW_uniformbuffer_update(*ubo, *data);
}
-void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
+void workbench_dof_engine_init(WORKBENCH_Data *vedata)
{
WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ Object *camera;
+
+ if (v3d && rv3d) {
+ camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+ }
+ else {
+ camera = scene->camera;
+ }
+
Camera *cam = camera != NULL ? camera->data : NULL;
if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) ||
((cam->dof.flag & CAM_DOF_ENABLED) == 0)) {
wpd->dof_enabled = false;
- return;
- }
-
- if (e_data.effect_dof_prepare_sh == NULL) {
- e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define PREPARE\n");
-
- e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define DOWNSAMPLE\n");
-
- e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_VERTICAL\n");
-
- e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_HORIZONTAL\n");
-
- e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_VERTICAL\n");
-
- e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_HORIZONTAL\n");
- e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define BLUR1\n");
-
- e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define BLUR2\n");
-
- e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define RESOLVE\n");
+ /* Cleanup. */
+ DRW_TEXTURE_FREE_SAFE(txl->dof_source_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->coc_halfres_tx);
+ return;
}
const float *full_size = DRW_viewport_size_get();
int size[2] = {max_ii(1, (int)full_size[0] / 2), max_ii(1, (int)full_size[1] / 2)};
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimisation */
/* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */
int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]};
int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
@@ -186,14 +167,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
DRW_texture_ensure_2d(
&txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
wpd->dof_blur_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
-#if 0
+ size[0], size[1], GPU_RGBA16F, &draw_engine_workbench);
+#if 0 /* TODO(fclem) finish COC min_max optimisation */
wpd->coc_temp_tx = DRW_texture_pool_query_2d(
- shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench);
wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d(
- shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench);
wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2d(
- shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench);
#endif
GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb,
@@ -202,7 +183,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx),
});
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimisation */
GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb,
{
GPU_ATTACHMENT_NONE,
@@ -231,11 +212,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
});
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
-
/* Parameters */
- /* TODO UI Options */
float fstop = cam->dof.aperture_fstop;
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
float focus_dist = BKE_camera_object_dof_distance(camera);
@@ -263,128 +240,125 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
float rotation = cam->dof.aperture_rotation;
float ratio = 1.0f / cam->dof.aperture_ratio;
- if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation ||
- ratio != wpd->dof_ratio) {
+ if (wpd->vldata->dof_sample_ubo == NULL || blades != wpd->dof_blades ||
+ rotation != wpd->dof_rotation || ratio != wpd->dof_ratio) {
wpd->dof_blades = blades;
wpd->dof_rotation = rotation;
wpd->dof_ratio = ratio;
- workbench_dof_setup_samples(&wpd->dof_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
+ workbench_dof_setup_samples(
+ &wpd->vldata->dof_sample_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
}
}
wpd->dof_enabled = true;
}
-void workbench_dof_create_pass(WORKBENCH_Data *vedata,
- GPUTexture **dof_input,
- GPUTexture *noise_tex)
+void workbench_dof_cache_init(WORKBENCH_Data *vedata)
{
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ WORKBENCH_PrivateData *wpd = stl->wpd;
if (!wpd->dof_enabled) {
return;
}
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ GPUShader *prepare_sh, *downsample_sh, *blur1_sh, *blur2_sh, *resolve_sh;
+ workbench_shader_depth_of_field_get(
+ &prepare_sh, &downsample_sh, &blur1_sh, &blur2_sh, &resolve_sh);
- psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
- psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
- psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
- psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
- psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
- psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
- psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
- psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
- psl->dof_resolve_ps = DRW_pass_create("DoF Resolve",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps);
- DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input);
+ psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(prepare_sh, psl->dof_down_ps);
+ DRW_shgroup_uniform_texture(grp, "sceneColorTex", dtxl->color);
DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps);
+ psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(downsample_sh, psl->dof_down2_ps);
DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimization */
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh,
- psl->dof_flatten_h_ps);
+ psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(flatten_h_sh, psl->dof_flatten_h_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh,
- psl->dof_flatten_v_ps);
+ psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(flatten_v_sh, psl->dof_flatten_v_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps);
+ psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(dilate_v_sh, psl->dof_dilate_v_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps);
+ psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(dilate_h_sh, psl->dof_dilate_h_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
#endif
{
- float offset = stl->effects->jitter_index /
- (float)workbench_taa_calculate_num_iterations(vedata);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
- DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo);
- DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex);
+ psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
+
+ /* We reuse the same noise texture. Ensure it is up to date. */
+ workbench_cavity_samples_ubo_ensure(wpd);
+
+ float offset = wpd->taa_sample / wpd->taa_sample_len;
+ DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps);
+ DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo);
+ DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps);
+ psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(blur2_sh, psl->dof_blur2_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps);
+ psl->dof_resolve_ps = DRW_pass_create("DoF Resolve",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(resolve_sh, psl->dof_resolve_ps);
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
-void workbench_dof_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
-}
-
static void workbench_dof_downsample_level(void *userData, int UNUSED(level))
{
WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData;
@@ -396,7 +370,8 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
WORKBENCH_FramebufferList *fbl = vedata->fbl;
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
if (!wpd->dof_enabled) {
return;
@@ -410,7 +385,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
GPU_framebuffer_recursive_downsample(
fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl);
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimization */
GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
DRW_draw_pass(psl->dof_flatten_h_ps);
@@ -430,7 +405,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
GPU_framebuffer_bind(fbl->dof_blur2_fb);
DRW_draw_pass(psl->dof_blur2_ps);
- GPU_framebuffer_bind(fbl->color_only_fb);
+ GPU_framebuffer_bind(dfbl->color_only_fb);
DRW_draw_pass(psl->dof_resolve_ps);
DRW_stats_group_end();
diff --git a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c
deleted file mode 100644
index 6e3bf1658ab..00000000000
--- a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-#include "workbench_private.h"
-
-/* *********** STATIC *********** */
-static struct {
- struct GPUShader *effect_fxaa_sh;
-} e_data = {NULL};
-
-/* Shaders */
-extern char datatoc_common_fxaa_lib_glsl[];
-extern char datatoc_common_fullscreen_vert_glsl[];
-extern char datatoc_workbench_effect_fxaa_frag_glsl[];
-
-/* *********** Functions *********** */
-void workbench_fxaa_engine_init(void)
-{
- if (e_data.effect_fxaa_sh == NULL) {
- e_data.effect_fxaa_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
- NULL,
- datatoc_workbench_effect_fxaa_frag_glsl,
- datatoc_common_fxaa_lib_glsl,
- NULL);
- }
-}
-
-DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx)
-{
- DRWPass *pass = DRW_pass_create("Effect FXAA", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass);
- DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- return pass;
-}
-
-void workbench_fxaa_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.effect_fxaa_sh);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_outline.c b/source/blender/draw/engines/workbench/workbench_effect_outline.c
new file mode 100644
index 00000000000..d1bc6b6c435
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_outline.c
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Outline Effect:
+ *
+ * Simple effect that just samples an object id buffer to detect objects outlines.
+ */
+
+#include "DRW_render.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+void workbench_outline_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (OBJECT_OUTLINE_ENABLED(wpd)) {
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
+ DRW_PASS_CREATE(psl->outline_ps, state);
+
+ sh = workbench_shader_outline_get();
+
+ grp = DRW_shgroup_create(sh, psl->outline_ps);
+ DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
+ DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else {
+ psl->outline_ps = NULL;
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c
deleted file mode 100644
index e2864f8c832..00000000000
--- a/source/blender/draw/engines/workbench/workbench_effect_taa.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "workbench_private.h"
-#include "BLI_jitter_2d.h"
-
-static struct {
- struct GPUShader *effect_taa_sh;
- float jitter_5[5][2];
- float jitter_8[8][2];
- float jitter_11[11][2];
- float jitter_16[16][2];
- float jitter_32[32][2];
-} e_data = {NULL};
-
-extern char datatoc_workbench_effect_taa_frag_glsl[];
-
-static void workbench_taa_jitter_init_order(float (*table)[2], int num)
-{
- BLI_jitter_init(table, num);
-
- /* find closest element to center */
- int closest_index = 0;
- float closest_squared_distance = 1.0f;
-
- for (int index = 0; index < num; index++) {
- const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]);
- if (squared_dist < closest_squared_distance) {
- closest_squared_distance = squared_dist;
- closest_index = index;
- }
- }
-
- /* move jitter table so that closest sample is in center */
- for (int index = 0; index < num; index++) {
- sub_v2_v2(table[index], table[closest_index]);
- mul_v2_fl(table[index], 2.0f);
- }
-
- /* swap center sample to the start of the table */
- if (closest_index != 0) {
- swap_v2_v2(table[0], table[closest_index]);
- }
-
- /* sort list based on furtest distance with previous */
- for (int i = 0; i < num - 2; i++) {
- float f_squared_dist = 0.0;
- int f_index = i;
- for (int j = i + 1; j < num; j++) {
- const float squared_dist = square_f(table[i][0] - table[j][0]) +
- square_f(table[i][1] - table[j][1]);
- if (squared_dist > f_squared_dist) {
- f_squared_dist = squared_dist;
- f_index = j;
- }
- }
- swap_v2_v2(table[i + 1], table[f_index]);
- }
-}
-
-static void workbench_taa_jitter_init(void)
-{
- workbench_taa_jitter_init_order(e_data.jitter_5, 5);
- workbench_taa_jitter_init_order(e_data.jitter_8, 8);
- workbench_taa_jitter_init_order(e_data.jitter_11, 11);
- workbench_taa_jitter_init_order(e_data.jitter_16, 16);
- workbench_taa_jitter_init_order(e_data.jitter_32, 32);
-}
-
-int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const Scene *scene = DRW_context_state_get()->scene;
- int result;
- if (workbench_is_taa_enabled(wpd)) {
- if (DRW_state_is_image_render()) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (draw_ctx->v3d) {
- result = scene->display.viewport_aa;
- }
- else {
- result = scene->display.render_aa;
- }
- }
- else {
- result = wpd->preferences->viewport_aa;
- }
- }
- else {
- /* when no TAA is disabled return 1 to render a single sample
- * see `workbench_render.c` */
- result = 1;
- }
- return result;
-}
-
-int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *UNUSED(vedata))
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
- int result = DRW_state_is_image_render() ? scene->display.viewport_aa : 1;
- result = MAX2(result, 1);
- return result;
-}
-
-void workbench_taa_engine_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
-
- if (e_data.effect_taa_sh == NULL) {
- e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl,
- NULL);
- workbench_taa_jitter_init();
- }
-
- effect_info->view = NULL;
-
- /* reset complete drawing when navigating. */
- if (effect_info->jitter_index != 0) {
- if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) {
- effect_info->jitter_index = 0;
- }
- }
-
- if (effect_info->view_updated) {
- effect_info->jitter_index = 0;
- effect_info->view_updated = false;
- }
-
- {
- float persmat[4][4];
- DRW_view_persmat_get(NULL, persmat, false);
- if (!equals_m4m4(persmat, effect_info->last_mat)) {
- copy_m4_m4(effect_info->last_mat, persmat);
- effect_info->jitter_index = 0;
- }
- }
-}
-
-void workbench_taa_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh);
-}
-
-DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_TextureList *txl = vedata->txl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- const WORKBENCH_PrivateData *wpd = stl->g_data;
-
- {
- const eGPUTextureFormat hist_buffer_format = workbench_color_texture_format(wpd);
- DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, hist_buffer_format, 0);
- DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
- }
-
- {
- GPU_framebuffer_ensure_config(&fbl->effect_taa_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb,
- {
- GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
- });
- }
-
- DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass);
- DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
- DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx);
- DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-
- return pass;
-}
-
-void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- const float *viewport_size = DRW_viewport_size_get();
- const DRWView *default_view = DRW_view_default_get();
- int num_samples = 8;
- float(*samples)[2];
-
- num_samples = workbench_taa_calculate_num_iterations(vedata);
- switch (num_samples) {
- default:
- case 5:
- samples = e_data.jitter_5;
- break;
- case 8:
- samples = e_data.jitter_8;
- break;
- case 11:
- samples = e_data.jitter_11;
- break;
- case 16:
- samples = e_data.jitter_16;
- break;
- case 32:
- samples = e_data.jitter_32;
- break;
- }
-
- const int jitter_index = effect_info->jitter_index;
- const float *transform_offset = samples[jitter_index];
- effect_info->taa_mix_factor = 1.0f / (jitter_index + 1);
- effect_info->jitter_index = (jitter_index + 1) % num_samples;
- /* Copy jitter index to Cavity iteration */
- wpd->ssao_params[3] = effect_info->jitter_index;
-
- /* construct new matrices from transform delta */
- float winmat[4][4], viewmat[4][4], persmat[4][4];
- DRW_view_winmat_get(default_view, winmat, false);
- DRW_view_viewmat_get(default_view, viewmat, false);
- DRW_view_persmat_get(default_view, persmat, false);
-
- window_translate_m4(winmat,
- persmat,
- transform_offset[0] / viewport_size[0],
- transform_offset[1] / viewport_size[1]);
-
- if (effect_info->view) {
- /* When rendering just update the view. This avoids recomputing the culling. */
- DRW_view_update_sub(effect_info->view, viewmat, winmat);
- }
- else {
- /* TAA is not making a big change to the matrices.
- * Reuse the main view culling by creating a subview. */
- effect_info->view = DRW_view_create_sub(default_view, viewmat, winmat);
- }
- DRW_view_set_active(effect_info->view);
-}
-
-void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata)
-{
- /*
- * If first frame then the offset is 0.0 and its depth is the depth buffer to use
- * for the rest of the draw engines. We store it in a persistent buffer.
- *
- * If it is not the first frame we copy the persistent buffer back to the
- * default depth buffer
- */
- const WORKBENCH_StorageList *stl = vedata->stl;
- const WORKBENCH_FramebufferList *fbl = vedata->fbl;
- const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- WORKBENCH_EffectInfo *effect_info = stl->effects;
-
- if (effect_info->jitter_index == 1) {
- GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT);
- }
- else {
- GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
- }
-
- GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT);
-
- if (!DRW_state_is_image_render()) {
- DRW_view_set_active(NULL);
- }
-
- if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) {
- DRW_viewport_request_redraw();
- }
-}
-
-void workbench_taa_view_updated(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- if (stl) {
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- if (effect_info) {
- effect_info->view_updated = true;
- }
- }
-}
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 62a192bbb25..b91ca7cf070 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -19,18 +19,557 @@
/** \file
* \ingroup draw_engine
*
- * Simple engine for drawing color and/or depth.
- * When we only need simple flat shaders.
+ * Workbench Engine:
+ *
+ * Optimized engine to draw the working viewport with solid and transparent geometry.
*/
#include "DRW_render.h"
+#include "BLI_alloca.h"
+
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+
+#include "DNA_image_types.h"
+#include "DNA_fluid_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
#include "workbench_engine.h"
#include "workbench_private.h"
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
-/* Note: currently unused, we may want to register so we can see this when debugging the view. */
+void workbench_engine_init(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_TextureList *txl = vedata->txl;
+
+ workbench_shader_library_ensure();
+
+ if (!stl->wpd) {
+ stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__);
+ stl->wpd->view_updated = true;
+ }
+
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+ workbench_private_data_init(wpd);
+ workbench_update_world_ubo(wpd);
+
+ if (txl->dummy_image_tx == NULL) {
+ float fpixel[4] = {1.0f, 0.0f, 1.0f, 1.0f};
+ txl->dummy_image_tx = DRW_texture_create_2d(1, 1, GPU_RGBA8, 0, fpixel);
+ }
+ wpd->dummy_image_tx = txl->dummy_image_tx;
+
+ if (OBJECT_ID_PASS_ENABLED(wpd)) {
+ wpd->object_id_tx = DRW_texture_pool_query_fullscreen(GPU_R16UI, &draw_engine_workbench);
+ }
+ else {
+ /* Dont free because it's a pool texture. */
+ wpd->object_id_tx = NULL;
+ }
+
+ workbench_opaque_engine_init(vedata);
+ workbench_transparent_engine_init(vedata);
+ workbench_dof_engine_init(vedata);
+ workbench_antialiasing_engine_init(vedata);
+ workbench_volume_engine_init(vedata);
+}
+
+void workbench_cache_init(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+
+ workbench_opaque_cache_init(vedata);
+ workbench_transparent_cache_init(vedata);
+ workbench_shadow_cache_init(vedata);
+ workbench_cavity_cache_init(vedata);
+ workbench_outline_cache_init(vedata);
+ workbench_dof_cache_init(vedata);
+ workbench_antialiasing_cache_init(vedata);
+ workbench_volume_cache_init(vedata);
+}
+
+/* TODO(fclem) DRW_cache_object_surface_material_get needs a refactor to allow passing NULL
+ * instead of gpumat_array. Avoiding all this boilerplate code. */
+static struct GPUBatch **workbench_object_surface_material_get(Object *ob)
+{
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
+
+ return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
+}
+
+static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ eV3DShadingColorType color_type)
+{
+ const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR);
+ const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
+ BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR);
+
+ if (use_single_drawcall) {
+ DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
+ DRW_shgroup_call_sculpt(grp, ob, false, false, use_vcol);
+ }
+ else {
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
+ for (int i = 0; i < materials_len; i++) {
+ shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL);
+ }
+ DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
+ }
+}
+
+static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ const bool use_single_drawcall = imapaint->mode == IMAGEPAINT_MODE_IMAGE;
+
+ if (use_single_drawcall) {
+ struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+ if (geom) {
+ Image *ima = imapaint->canvas;
+ int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
+ SHD_INTERP_CLOSEST;
+
+ DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp);
+ DRW_shgroup_call(grp, geom, ob);
+ }
+ }
+ else {
+ struct GPUBatch **geoms = DRW_cache_mesh_surface_texpaint_get(ob);
+ if (geoms) {
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ for (int i = 0; i < materials_len; i++) {
+ DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0);
+ DRW_shgroup_call(grp, geoms[i], ob);
+ }
+ }
+ }
+}
+
+static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ eV3DShadingColorType color_type,
+ bool *r_transp)
+{
+ const bool use_tex = ELEM(color_type, V3D_SHADING_TEXTURE_COLOR);
+ const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR);
+ const bool use_single_drawcall = !ELEM(
+ color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR);
+
+ if (use_single_drawcall) {
+ struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) :
+ DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp);
+ DRW_shgroup_call(grp, geom, ob);
+ }
+ }
+ else {
+ struct GPUBatch **geoms = (use_tex) ? DRW_cache_mesh_surface_texpaint_get(ob) :
+ workbench_object_surface_material_get(ob);
+ if (geoms) {
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ for (int i = 0; i < materials_len; i++) {
+ DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp);
+ DRW_shgroup_call(grp, geoms[i], ob);
+ }
+ }
+ }
+}
+
+static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ ModifierData *md,
+ eV3DShadingColorType color_type,
+ bool use_texpaint_mode)
+{
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ ParticleSettings *part = psys->part;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+
+ const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL;
+ Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL;
+ int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
+ SHD_INTERP_CLOSEST;
+ DRWShadingGroup *grp = (use_texpaint_mode) ?
+ workbench_image_hair_setup(wpd, ob, part->omat, ima, NULL, interp) :
+ workbench_material_hair_setup(wpd, ob, part->omat, color_type);
+
+ DRW_shgroup_hair_create_sub(ob, psys, md, grp);
+}
+
+/* Decide what colortype to draw the object with.
+ * In some cases it can be overwritten by workbench_material_setup(). */
+static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ bool *r_sculpt_pbvh,
+ bool *r_texpaint_mode,
+ bool *r_draw_shadow)
+{
+ eV3DShadingColorType color_type = wpd->shading.color_type;
+ const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
+ const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL);
+ const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE);
+ const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX);
+
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) {
+ color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ /* Disable color mode if data layer is unavailable. */
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) {
+ color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) {
+ color_type = V3D_SHADING_OBJECT_COLOR;
+ }
+
+ *r_sculpt_pbvh = is_sculpt_pbvh;
+ *r_texpaint_mode = false;
+
+ if (!is_sculpt_pbvh && !is_render) {
+ /* Force texture or vertex mode if object is in paint mode. */
+ if (is_texpaint_mode && me && me->mloopuv) {
+ color_type = V3D_SHADING_TEXTURE_COLOR;
+ *r_texpaint_mode = true;
+ }
+ else if (is_vertpaint_mode && me && me->mloopcol) {
+ color_type = V3D_SHADING_VERTEX_COLOR;
+ }
+ }
+
+ if (r_draw_shadow) {
+ *r_draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && SHADOW_ENABLED(wpd);
+ /* Currently unsupported in sculpt mode. We could revert to the slow
+ * method in this case but I'm not sure if it's a good idea given that
+ * sculpted meshes are heavy to begin with. */
+ if (is_sculpt_pbvh) {
+ *r_draw_shadow = false;
+ }
+
+ if (is_active && DRW_object_use_hide_faces(ob)) {
+ *r_draw_shadow = false;
+ }
+ }
+
+ return color_type;
+}
+
+void workbench_cache_populate(void *ved, Object *ob)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+
+ if (!DRW_object_is_renderable(ob)) {
+ return;
+ }
+
+ if (ob->type == OB_MESH && ob->modifiers.first != NULL) {
+ bool use_sculpt_pbvh, use_texpaint_mode;
+ int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, NULL);
+
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH) {
+ workbench_cache_hair_populate(wpd, ob, md, color_type, use_texpaint_mode);
+ }
+ }
+ }
+
+ if (!(ob->base_flag & BASE_FROM_DUPLI)) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ if (md && modifier_isEnabled(wpd->scene, md, eModifierMode_Realtime)) {
+ FluidModifierData *fmd = (FluidModifierData *)md;
+ if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
+ workbench_volume_cache_populate(vedata, wpd->scene, ob, md);
+ return; /* Do not draw solid in this case. */
+ }
+ }
+ }
+
+ if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
+ return;
+ }
+
+ if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
+ return;
+ }
+
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false;
+ eV3DShadingColorType color_type = workbench_color_type_get(
+ wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow);
+
+ if (use_sculpt_pbvh) {
+ workbench_cache_sculpt_populate(wpd, ob, color_type);
+ }
+ else if (use_texpaint_mode) {
+ workbench_cache_texpaint_populate(wpd, ob);
+ }
+ else {
+ workbench_cache_common_populate(wpd, ob, color_type, &has_transp_mat);
+ }
+
+ if (draw_shadow) {
+ workbench_shadow_cache_populate(vedata, ob, has_transp_mat);
+ }
+ }
+}
+
+void workbench_cache_finish(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+
+ /* TODO(fclem) Only do this when really needed. */
+ {
+ /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(&dfbl->in_front_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->opaque_infront_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->transp_accum_infront_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx),
+ });
+ }
+
+ if (wpd->object_id_tx) {
+ GPU_framebuffer_ensure_config(&fbl->id_clear_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
+ });
+ }
+ else {
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->id_clear_fb);
+ }
+
+ workbench_update_material_ubos(wpd);
+
+ /* TODO don't free reuse next redraw. */
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ if (wpd->prepass[i][j][k].material_hash) {
+ BLI_ghash_free(wpd->prepass[i][j][k].material_hash, NULL, NULL);
+ wpd->prepass[i][j][k].material_hash = NULL;
+ }
+ }
+ }
+ }
+}
+
+/* Used by viewport rendering & final rendering.
+ * Do one render loop iteration (i.e: One TAA sample). */
+void workbench_draw_sample(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float clear_col_with_alpha[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ const bool do_render = workbench_antialiasing_setup(vedata);
+ const bool xray_is_visible = wpd->shading.xray_alpha > 0.0f;
+ const bool do_transparent_infront_pass = !DRW_pass_is_empty(psl->transp_accum_infront_ps);
+ const bool do_transparent_pass = !DRW_pass_is_empty(psl->transp_accum_ps);
+ const bool do_opaque_infront_pass = !DRW_pass_is_empty(psl->opaque_infront_ps);
+ const bool do_opaque_pass = !DRW_pass_is_empty(psl->opaque_ps) || do_opaque_infront_pass;
+
+ if (dfbl->in_front_fb) {
+ GPU_framebuffer_bind(dfbl->in_front_fb);
+ GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
+ }
+
+ if (do_render) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_color_depth_stencil(dfbl->default_fb, wpd->background_color, 1.0f, 0x00);
+
+ if (fbl->id_clear_fb) {
+ GPU_framebuffer_bind(fbl->id_clear_fb);
+ GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
+ }
+
+ if (do_opaque_pass) {
+ GPU_framebuffer_bind(fbl->opaque_fb);
+ DRW_draw_pass(psl->opaque_ps);
+
+ if (psl->shadow_ps[0]) {
+ DRW_draw_pass(psl->shadow_ps[0]);
+ DRW_draw_pass(psl->shadow_ps[1]);
+ }
+
+ if (do_opaque_infront_pass) {
+ GPU_framebuffer_bind(fbl->opaque_infront_fb);
+ DRW_draw_pass(psl->opaque_infront_ps);
+
+ GPU_framebuffer_bind(fbl->opaque_fb);
+ DRW_draw_pass(psl->merge_infront_ps);
+ }
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->composite_ps);
+
+ if (psl->cavity_ps) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->cavity_ps);
+ }
+ }
+
+ workbench_volume_draw_pass(vedata);
+
+ if (xray_is_visible) {
+ if (do_transparent_pass) {
+ GPU_framebuffer_bind(fbl->transp_accum_fb);
+ GPU_framebuffer_clear_color(fbl->transp_accum_fb, clear_col_with_alpha);
+
+ DRW_draw_pass(psl->transp_accum_ps);
+
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->transp_resolve_ps);
+ }
+
+ if (do_transparent_infront_pass) {
+ GPU_framebuffer_bind(fbl->transp_accum_infront_fb);
+ GPU_framebuffer_clear_color(fbl->transp_accum_infront_fb, clear_col_with_alpha);
+
+ DRW_draw_pass(psl->transp_accum_infront_ps);
+
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->transp_resolve_ps);
+ }
+ }
+
+ workbench_transparent_draw_depth_pass(vedata);
+
+ if (psl->outline_ps) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->outline_ps);
+ }
+
+ workbench_dof_draw_pass(vedata);
+ }
+
+ workbench_antialiasing_draw_pass(vedata);
+}
+
+/* Viewport rendering. */
+static void workbench_draw_scene(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+
+ if (DRW_state_is_opengl_render()) {
+ while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
+ workbench_update_world_ubo(wpd);
+
+ workbench_draw_sample(vedata);
+ }
+ }
+ else {
+ workbench_draw_sample(vedata);
+ }
+
+ workbench_draw_finish(vedata);
+}
+
+void workbench_draw_finish(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ workbench_volume_draw_finish(vedata);
+}
+
+static void workbench_engine_free(void)
+{
+ workbench_shader_free();
+}
+
+static void workbench_view_update(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_antialiasing_view_updated(data);
+}
+
+static void workbench_id_update(void *UNUSED(vedata), struct ID *id)
+{
+ if (GS(id->name) == ID_OB) {
+ WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(id,
+ &draw_engine_workbench);
+ if (oed != NULL && oed->dd.recalc != 0) {
+ oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0;
+ oed->dd.recalc = 0;
+ }
+ }
+}
+
+static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
+
+DrawEngineType draw_engine_workbench = {
+ NULL,
+ NULL,
+ N_("Workbench"),
+ &workbench_data_size,
+ &workbench_engine_init,
+ &workbench_engine_free,
+ &workbench_cache_init,
+ &workbench_cache_populate,
+ &workbench_cache_finish,
+ &workbench_draw_scene,
+ &workbench_view_update,
+ &workbench_id_update,
+ &workbench_render,
+};
+
RenderEngineType DRW_engine_viewport_workbench_type = {
NULL,
NULL,
@@ -44,7 +583,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = {
NULL,
NULL,
&workbench_render_update_passes,
- &draw_engine_workbench_solid,
+ &draw_engine_workbench,
{NULL, NULL, NULL},
};
diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h
index 78f70abdaab..eee53fcde07 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.h
+++ b/source/blender/draw/engines/workbench/workbench_engine.h
@@ -23,8 +23,6 @@
#ifndef __WORKBENCH_ENGINE_H__
#define __WORKBENCH_ENGINE_H__
-extern DrawEngineType draw_engine_workbench_solid;
-extern DrawEngineType draw_engine_workbench_transparent;
extern RenderEngineType DRW_engine_viewport_workbench_type;
#endif /* __WORKBENCH_ENGINE_H__ */
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
deleted file mode 100644
index 7e09016cf61..00000000000
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "workbench_private.h"
-
-#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
-#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-
-#include "DNA_image_types.h"
-#include "DNA_fluid_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_node_types.h"
-
-#include "ED_view3d.h"
-
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-/* *********** STATIC *********** */
-
-typedef struct WORKBENCH_FORWARD_Shaders {
- struct GPUShader *transparent_accum_sh_cache[MAX_ACCUM_SHADERS];
- struct GPUShader *object_outline_sh;
- struct GPUShader *object_outline_texture_sh;
- struct GPUShader *object_outline_hair_sh;
-} WORKBENCH_FORWARD_Shaders;
-
-static struct {
- WORKBENCH_FORWARD_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
- struct GPUShader *composite_sh_cache[2];
-
- struct GPUTexture *object_id_tx; /* ref only, not alloced */
- struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
- struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
- struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-} e_data = {{{{NULL}}}};
-
-/* Shaders */
-extern char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_workbench_forward_composite_frag_glsl[];
-extern char datatoc_workbench_forward_depth_frag_glsl[];
-extern char datatoc_workbench_forward_transparent_accum_frag_glsl[];
-extern char datatoc_workbench_data_lib_glsl[];
-extern char datatoc_workbench_object_outline_lib_glsl[];
-extern char datatoc_workbench_curvature_lib_glsl[];
-extern char datatoc_workbench_prepass_vert_glsl[];
-extern char datatoc_workbench_common_lib_glsl[];
-extern char datatoc_workbench_world_light_lib_glsl[];
-
-/* static functions */
-static char *workbench_build_forward_vert(bool is_hair)
-{
- DynStr *ds = BLI_dynstr_new();
- if (is_hair) {
- BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
- }
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_forward_outline_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_forward_transparent_accum_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_forward_composite_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(
- WORKBENCH_Data *vedata,
- Object *ob,
- Material *mat,
- Image *ima,
- ImageUser *iuser,
- eV3DShadingColorType color_type,
- int interp)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_MaterialData *material;
- WORKBENCH_MaterialData material_template;
- DRWShadingGroup *grp;
-
- /* Solid */
- workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.color_type = color_type;
- material_template.ima = ima;
- material_template.iuser = iuser;
- material_template.interp = interp;
- uint hash = workbench_material_get_hash(&material_template, false);
-
- material = BLI_ghash_lookup(wpd->material_transp_hash, POINTER_FROM_UINT(hash));
- if (material == NULL) {
- material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
-
- /* transparent accum */
- /* select the correct transparent accum shader */
- GPUShader *shader = (wpd->shading.color_type == color_type) ?
- wpd->transparent_accum_sh :
- wpd->transparent_accum_uniform_sh;
- const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
- if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- shader = is_tiled ? wpd->transparent_accum_textured_array_sh :
- wpd->transparent_accum_textured_sh;
- }
-
- grp = DRW_shgroup_create(shader, psl->transparent_accum_pass);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- workbench_material_copy(material, &material_template);
- if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light,
- STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
- STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
- DRW_shgroup_uniform_texture(
- grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- DRW_shgroup_uniform_texture(
- grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
- }
- }
- if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- }
- if (SHADOW_ENABLED(wpd)) {
- DRW_shgroup_uniform_float_copy(grp, "shadowMultiplier", wpd->shadow_multiplier);
- DRW_shgroup_uniform_float_copy(grp, "shadowShift", wpd->shadow_shift);
- DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
- }
-
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, is_tiled, interp);
- material->shgrp = grp;
-
- /* Depth */
- if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh,
- psl->object_outline_pass);
- GPUTexture *tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
- }
- else {
- material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
- psl->object_outline_pass);
- }
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
- }
- BLI_ghash_insert(wpd->material_transp_hash, POINTER_FROM_UINT(hash), material);
- }
- return material;
-}
-
-static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override,
- eGPUShaderConfig sh_cfg)
-{
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
- int index = workbench_material_get_accum_shader_index(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- if (sh_data->transparent_accum_sh_cache[index] == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- char *transparent_accum_vert = workbench_build_forward_vert(is_hair);
- char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag();
- sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, transparent_accum_vert, NULL},
- .frag = (const char *[]){transparent_accum_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
- });
- MEM_freeN(transparent_accum_vert);
- MEM_freeN(transparent_accum_frag);
- MEM_freeN(defines);
- }
- return sh_data->transparent_accum_sh_cache[index];
-}
-
-static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd)
-{
- int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
- if (e_data.composite_sh_cache[index] == NULL) {
- char *defines = workbench_material_build_defines(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *composite_frag = workbench_build_forward_composite_frag();
- e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
- MEM_freeN(composite_frag);
- MEM_freeN(defines);
- }
- return e_data.composite_sh_cache[index];
-}
-
-void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
-{
- wpd->composite_sh = ensure_forward_composite_shaders(wpd);
- wpd->transparent_accum_sh = ensure_forward_accum_shaders(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(
- wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(
- wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(
- wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->transparent_accum_textured_array_sh = ensure_forward_accum_shaders(
- wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
-}
-
-void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
-{
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
-
- if (sh_data->object_outline_sh == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *defines_texture = workbench_material_build_defines(
- wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *defines_hair = workbench_material_build_defines(
- wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *forward_vert = workbench_build_forward_vert(false);
- char *forward_frag = workbench_build_forward_outline_frag();
- char *forward_hair_vert = workbench_build_forward_vert(true);
-
- const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
-
- sh_data->object_outline_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){forward_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
- });
- sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){forward_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
- });
- sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
- .frag = (const char *[]){forward_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
- });
-
- MEM_freeN(forward_hair_vert);
- MEM_freeN(forward_vert);
- MEM_freeN(forward_frag);
- MEM_freeN(defines);
- MEM_freeN(defines_texture);
- MEM_freeN(defines_hair);
- }
-}
-
-/* public functions */
-void workbench_forward_engine_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_StorageList *stl = vedata->stl;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- DRWShadingGroup *grp;
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
- if (!stl->effects) {
- stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
- workbench_effect_info_init(stl->effects);
- }
- WORKBENCH_PrivateData *wpd = stl->g_data;
- workbench_private_data_init(wpd);
-
- workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
-
- workbench_volume_engine_init();
- workbench_fxaa_engine_init();
- workbench_taa_engine_init(vedata);
-
- workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
- workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg);
-
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- const eGPUTextureFormat comp_tex_format = GPU_RGBA16F;
-
- e_data.object_id_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R32UI, &draw_engine_workbench_transparent);
- e_data.transparent_accum_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent);
- e_data.transparent_revealage_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16F, &draw_engine_workbench_transparent);
- e_data.composite_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], comp_tex_format, &draw_engine_workbench_transparent);
-
- GPU_framebuffer_ensure_config(&fbl->object_outline_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.transparent_revealage_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->composite_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->effect_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
- });
-
- workbench_volume_cache_init(vedata);
-
- DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
- DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
-
- /* Transparency Accum */
- {
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state | clip_state;
- psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
- }
- /* Depth */
- {
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state |
- clip_state;
- psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state);
- }
- /* Composite */
- {
- int state = DRW_STATE_WRITE_COLOR;
- if (DRW_state_is_scene_render()) {
- /* Composite the scene over cleared background. */
- state |= DRW_STATE_BLEND_ALPHA_PREMUL;
- }
- psl->composite_pass = DRW_pass_create("Composite", state);
-
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- }
- DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.transparent_accum_tx);
- DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- {
- workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx);
- }
-
- if (wpd->shading.type == OB_WIRE) {
- wpd->shading.xray_alpha = 0.0f;
- wpd->shading.xray_alpha_wire = 0.0f;
- }
-}
-
-void workbench_forward_engine_free()
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- for (int index = 0; index < MAX_ACCUM_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(sh_data->transparent_accum_sh_cache[index]);
- }
- DRW_SHADER_FREE_SAFE(sh_data->object_outline_sh);
- DRW_SHADER_FREE_SAFE(sh_data->object_outline_texture_sh);
- DRW_SHADER_FREE_SAFE(sh_data->object_outline_hair_sh);
- }
-
- for (int index = 0; index < 2; index++) {
- DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
- }
-
- workbench_volume_engine_free();
- workbench_fxaa_engine_free();
- workbench_taa_engine_free();
- workbench_dof_engine_free();
-}
-
-void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata))
-{
-}
-
-static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
- if (md->type != eModifierType_ParticleSystem) {
- continue;
- }
- ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
- if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
- continue;
- }
- ParticleSettings *part = psys->part;
- const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
-
- if (draw_as == PART_DRAW_PATH) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, false);
- WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
-
- struct GPUShader *shader = (wpd->shading.color_type == color_type) ?
- wpd->transparent_accum_hair_sh :
- wpd->transparent_accum_uniform_hair_sh;
- DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
- ob, psys, md, psl->transparent_accum_pass, shader);
- DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
- DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- /* Hairs have lots of layer and can rapidly become the most prominent surface.
- * So lower their alpha artificially. */
- float hair_alpha = XRAY_ALPHA(wpd) * 0.33f;
- DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha);
- if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light,
- STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
- STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
- DRW_shgroup_uniform_texture(
- shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- DRW_shgroup_uniform_texture(
- shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
- }
- }
- if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- }
-
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- shgrp = DRW_shgroup_hair_create(
- ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
- }
- }
-}
-static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- /* Force workbench to render active object textured when in texture paint mode */
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* Single Image mode */
- if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- Image *image = imapaint->canvas;
- int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
- SHD_INTERP_CLOSEST;
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, image, NULL, color_type, interp);
-
- DRW_shgroup_call(material->shgrp, geom, ob);
- DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
- }
- else {
- /* IMAGEPAINT_MODE_MATERIAL */
- const int materials_len = DRW_cache_object_material_count_get(ob);
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- if (geom_array != NULL && geom_array[i] != NULL) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
-
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob);
- }
- }
- }
-}
-static void workbench_forward_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, false);
- DRW_shgroup_call(material->shgrp, geom, ob);
- DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
-}
-
-void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- const bool is_wire = (ob->dt == OB_WIRE);
-
- if (!DRW_object_is_renderable(ob)) {
- return;
- }
-
- if (ob->type == OB_MESH) {
- workbench_forward_cache_populate_particles(vedata, ob);
- }
-
- ModifierData *md;
- if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((FluidModifierData *)md)->domain != NULL) &&
- (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
- workbench_volume_cache_populate(vedata, scene, ob, md);
- return; /* Do not draw solid in this case. */
- }
-
- if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
- return;
- }
- if (ob->dt < OB_WIRE) {
- return;
- }
-
- WORKBENCH_MaterialData *material = NULL;
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- const int materials_len = DRW_cache_object_material_count_get(ob);
- const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
- const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
- me && me->mloopuv;
- const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
- me && me->mloopcol;
-
- if (use_texture_paint_drawing) {
- workbench_forward_cache_populate_texture_paint_mode(vedata, ob);
- }
- else if (use_vertex_paint_drawing) {
- workbench_forward_cache_populate_vertex_paint_mode(vedata, ob);
- }
- else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
- DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob);
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- }
- }
- else if (ELEM(wpd->shading.color_type,
- V3D_SHADING_SINGLE_COLOR,
- V3D_SHADING_OBJECT_COLOR,
- V3D_SHADING_RANDOM_COLOR,
- V3D_SHADING_VERTEX_COLOR)) {
- /* No material split needed */
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
-
- if (use_sculpt_pbvh) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, 0);
- bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false);
- if (!is_wire) {
- DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol);
- }
- }
- else {
- struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ?
- DRW_cache_mesh_surface_vertpaint_get(ob) :
- DRW_cache_object_surface_get(ob);
- if (geom) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, 0);
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
- if (!is_wire) {
- DRW_shgroup_call(material->shgrp, geom, ob);
- }
- }
- }
- }
- else {
- /* Draw material color */
- if (use_sculpt_pbvh) {
- struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
-
- for (int i = 0; i < materials_len; i++) {
- struct Material *mat = BKE_object_material_get(ob, i + 1);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- shgrps[i] = material->shgrp;
- }
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false);
- if (!is_wire) {
- DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
- }
- }
- else {
- struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
- memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
-
- struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
- ob, gpumat_array, materials_len);
- if (mat_geom) {
- for (int i = 0; i < materials_len; i++) {
- if (mat_geom[i] == NULL) {
- continue;
- }
-
- Material *mat = BKE_object_material_get(ob, i + 1);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob);
- if (!is_wire) {
- DRW_shgroup_call(material->shgrp, mat_geom[i], ob);
- }
- }
- }
- }
- }
- }
-}
-
-void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata))
-{
-}
-
-void workbench_forward_draw_scene(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
-
- if (dfbl->in_front_fb) {
- /* TODO(fclem) This clear should be done in a global place. */
- GPU_framebuffer_bind(dfbl->in_front_fb);
- GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
- }
-
- if (workbench_is_taa_enabled(wpd)) {
- workbench_taa_draw_scene_start(vedata);
- }
-
- /* Write Depth + Object ID */
- const float clear_outline[4] = {0.0f};
- GPU_framebuffer_bind(fbl->object_outline_fb);
- GPU_framebuffer_clear_color(fbl->object_outline_fb, clear_outline);
- DRW_draw_pass(psl->object_outline_pass);
-
- if (XRAY_ALPHA(wpd) > 0.0) {
- const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- GPU_framebuffer_bind(fbl->transparent_accum_fb);
- GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
- DRW_draw_pass(psl->transparent_accum_pass);
- }
- else {
- /* TODO(fclem): this is unnecessary and takes up perf.
- * Better change the composite frag shader to not use the tx. */
- const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- GPU_framebuffer_bind(fbl->transparent_accum_fb);
- GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
- }
-
- /* Composite */
- GPU_framebuffer_bind(fbl->composite_fb);
-
- if (DRW_state_is_scene_render()) {
- float clear_color[4];
- workbench_clear_color_get(clear_color);
- GPU_framebuffer_clear_color(fbl->composite_fb, clear_color);
- }
-
- DRW_draw_pass(psl->composite_pass);
- DRW_draw_pass(psl->volume_pass);
-
- /* Only when clipping is enabled. */
- if (psl->background_pass) {
- DRW_draw_pass(psl->background_pass);
- }
-
- /* Color correct and Anti aliasing */
- workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
-}
-
-void workbench_forward_draw_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- workbench_private_data_free(wpd);
- workbench_volume_smoke_textures_free(wpd);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 5f1e3461d9f..246f5f88045 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -22,6 +22,8 @@
#include "workbench_private.h"
+#include "BLI_memblock.h"
+
#include "BKE_image.h"
#include "BKE_node.h"
@@ -31,310 +33,78 @@
#include "DNA_node_types.h"
#include "DNA_mesh_types.h"
+#include "GPU_uniformbuffer.h"
+
#include "ED_uvedit.h"
#define HSV_SATURATION 0.5
#define HSV_VALUE 0.8
-void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
- Object *ob,
- Material *mat,
- WORKBENCH_MaterialData *data,
- int color_type)
+void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ Material *mat,
+ WORKBENCH_UBO_Material *data,
+ eV3DShadingColorType color_type)
{
- data->metallic = 0.0f;
- data->roughness = 0.632455532f; /* sqrtf(0.4f); */
- data->alpha = wpd->shading.xray_alpha;
+ float metallic = 0.0f;
+ float roughness = 0.632455532f; /* sqrtf(0.4f); */
+ float alpha = wpd->shading.xray_alpha;
- if (color_type == V3D_SHADING_SINGLE_COLOR) {
- copy_v3_v3(data->base_color, wpd->shading.single_color);
- }
- else if (color_type == V3D_SHADING_ERROR_COLOR) {
- copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
- }
- else if (color_type == V3D_SHADING_RANDOM_COLOR) {
- uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
- if (ob->id.lib) {
- hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
- }
-
- float hue = BLI_hash_int_01(hash);
- float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, data->base_color);
- }
- else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
- data->alpha *= ob->color[3];
- copy_v3_v3(data->base_color, ob->color);
- }
- else {
- /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
- if (mat) {
- data->alpha *= mat->a;
- copy_v3_v3(data->base_color, &mat->r);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- data->metallic = mat->metallic;
- data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
- }
- }
- else {
- copy_v3_fl(data->base_color, 0.8f);
- }
- }
-}
-
-char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override)
-{
- char *str = NULL;
- bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
- bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
- !is_uniform_color;
-
- switch (color_override) {
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- use_textures = true;
- use_vertex_colors = false;
- is_hair = false;
- break;
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- use_textures = false;
- use_vertex_colors = true;
- is_hair = false;
- is_tiled = false;
+ switch (color_type) {
+ case V3D_SHADING_SINGLE_COLOR:
+ copy_v3_v3(data->base_color, wpd->shading.single_color);
break;
- case WORKBENCH_COLOR_OVERRIDE_OFF:
- break;
- }
-
- DynStr *ds = BLI_dynstr_new();
-
- if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_OBJECT_OUTLINE\n");
- }
- if (wpd->shading.flag & V3D_SHADING_SHADOW) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_SHADOW\n");
- }
- if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define WB_CAVITY\n");
- }
- if (workbench_is_specular_highlight_enabled(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
- }
- if (STUDIOLIGHT_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
- }
- if (FLAT_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
- }
- if (MATCAP_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
- }
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n");
- }
- if (workbench_is_matdata_pass_enabled(wpd)) {
- BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n");
- }
- if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n");
- }
- if (use_vertex_colors) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_VERTEX_COLOR\n");
- }
- if (use_textures) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
- }
- if (NORMAL_ENCODING_ENABLED()) {
- BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
- }
- if (is_hair) {
- BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
- }
- if (use_textures && is_tiled) {
- BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
- }
-
- str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
-{
- union {
- struct {
- /* WHATCH: Keep in sync with View3DShading.color_type max value. */
- uchar color_type;
- uchar diff_r;
- uchar diff_g;
- uchar diff_b;
-
- uchar alpha;
- uchar ghost;
- uchar metal;
- uchar roughness;
-
- void *ima;
- };
- /* HACK to ensure input is 4 uint long. */
- uint a[4];
- } input = {.color_type = (uchar)(mat->color_type),
- .diff_r = (uchar)(mat->base_color[0] * 0xFF),
- .diff_g = (uchar)(mat->base_color[1] * 0xFF),
- .diff_b = (uchar)(mat->base_color[2] * 0xFF),
-
- .alpha = (uint)(mat->alpha * 0xFF),
- .ghost = (uchar)is_ghost,
- .metal = (uchar)(mat->metallic * 0xFF),
- .roughness = (uchar)(mat->roughness * 0xFF),
-
- .ima = mat->ima};
-
- BLI_assert(sizeof(input) == sizeof(uint) * 4);
-
- return BLI_ghashutil_uinthash_v4((uint *)&input);
-}
-
-int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
-{
- /* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */
- int index = 0;
- /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = wpd->shading.light;
- SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2);
- SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3);
- SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4);
- SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5);
- SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
- BLI_assert(index < MAX_COMPOSITE_SHADERS);
- return index;
-}
-
-int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override)
-{
- bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
- bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
- !is_uniform_color;
-
- switch (color_override) {
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- use_textures = true;
- use_vertex_colors = false;
- break;
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- use_textures = false;
- use_vertex_colors = true;
- is_tiled = false;
- break;
- case WORKBENCH_COLOR_OVERRIDE_OFF:
- break;
- }
-
- /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */
- int index = 0;
- SET_FLAG_FROM_TEST(index, is_hair, 1 << 0);
- SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1);
- SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2);
- SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3);
- SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4);
- SET_FLAG_FROM_TEST(index, use_textures, 1 << 5);
- SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 6);
- SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
- BLI_assert(index < MAX_PREPASS_SHADERS);
- return index;
-}
-
-int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override)
-{
- bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
- bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
- !is_uniform_color;
-
- switch (color_override) {
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- use_textures = true;
- use_vertex_colors = false;
- is_hair = false;
+ case V3D_SHADING_RANDOM_COLOR: {
+ uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
+ if (ob->id.lib) {
+ hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
+ }
+ float hue = BLI_hash_int_01(hash);
+ float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
+ hsv_to_rgb_v(hsv, data->base_color);
break;
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- use_textures = false;
- use_vertex_colors = true;
- is_hair = false;
- is_tiled = false;
+ }
+ case V3D_SHADING_OBJECT_COLOR:
+ case V3D_SHADING_VERTEX_COLOR:
+ alpha *= ob->color[3];
+ copy_v3_v3(data->base_color, ob->color);
break;
- case WORKBENCH_COLOR_OVERRIDE_OFF:
+ case V3D_SHADING_MATERIAL_COLOR:
+ case V3D_SHADING_TEXTURE_COLOR:
+ default:
+ if (mat) {
+ alpha *= mat->a;
+ copy_v3_v3(data->base_color, &mat->r);
+ metallic = mat->metallic;
+ roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
+ }
+ else {
+ copy_v3_fl(data->base_color, 0.8f);
+ }
break;
}
- /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */
- int index = 0;
- /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = wpd->shading.light;
- SET_FLAG_FROM_TEST(index, use_textures, 1 << 2);
- SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3);
- SET_FLAG_FROM_TEST(index, is_hair, 1 << 4);
- /* 1 bits SHADOWS (only facing factor) */
- SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5);
- SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
- SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
- BLI_assert(index < MAX_ACCUM_SHADERS);
- return index;
+ uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic);
+ uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness);
+ uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha);
+ data->packed_data = (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic;
}
-eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
- Image *ima,
- Object *ob,
- bool use_sculpt_pbvh)
+/* Return correct material or empty default material if slot is empty. */
+BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
{
- eV3DShadingColorType color_type = wpd->shading.color_type;
- const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
-
- if ((color_type == V3D_SHADING_TEXTURE_COLOR) &&
- (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) {
- color_type = V3D_SHADING_MATERIAL_COLOR;
+ Material *ma = BKE_object_material_get(ob, mat_nr);
+ if (ma == NULL) {
+ ma = BKE_material_default_empty();
}
- if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) {
- color_type = V3D_SHADING_OBJECT_COLOR;
- }
-
- switch (workbench_object_color_override_get(ob)) {
- /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting
- * no matter the shading color that the user has chosen, when there is no
- * texture we will render the object with the error color */
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR;
- break;
-
- /* Force V3D_SHADING_VERTEX_COLOR for active object when in vertex painting
- * no matter the shading color that the user has chosen, when there is no
- * vertex color we will render the object with the error color */
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- color_type = V3D_SHADING_VERTEX_COLOR;
- break;
-
- case WORKBENCH_COLOR_OVERRIDE_OFF:
- break;
- }
-
- return color_type;
+ return ma;
}
-void workbench_material_get_image_and_mat(
- Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat)
+BLI_INLINE void workbench_material_get_image(
+ Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp)
{
bNode *node;
- *r_mat = BKE_object_material_get(ob, mat_nr);
+
ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL);
if (node && *r_image) {
switch (node->type) {
@@ -358,53 +128,170 @@ void workbench_material_get_image_and_mat(
}
}
-void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
- DRWShadingGroup *grp,
- WORKBENCH_MaterialData *material,
- Object *ob,
- const bool deferred,
- const bool is_tiled,
- const int interp)
+/* Return true if the current material ubo has changed and needs to be rebind. */
+BLI_INLINE bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd,
+ uint32_t id,
+ uint32_t *r_mat_id)
{
- if (deferred && !workbench_is_matdata_pass_enabled(wpd)) {
- return;
+ bool resource_changed = false;
+ /* Divide in chunks of MAX_MATERIAL. */
+ uint32_t chunk = id >> 12u;
+ *r_mat_id = id & 0xFFFu;
+ /* We need to add a new chunk. */
+ while (chunk >= wpd->material_chunk_count) {
+ wpd->material_chunk_count++;
+ wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data);
+ wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd);
+ wpd->material_chunk_curr = chunk;
+ resource_changed = true;
+ }
+ /* We need to go back to a previous chunk. */
+ if (wpd->material_chunk_curr != chunk) {
+ wpd->material_ubo_data_curr = BLI_memblock_elem_get(wpd->material_ubo_data, 0, chunk);
+ wpd->material_ubo_curr = BLI_memblock_elem_get(wpd->material_ubo, 0, chunk);
+ wpd->material_chunk_curr = chunk;
+ resource_changed = true;
}
+ return resource_changed;
+}
- const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
- const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
- wpd, material->ima, ob, false));
- if (use_texture) {
- if (is_tiled) {
- GPUTexture *array_tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_2D_ARRAY);
- GPUTexture *data_tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_1D_ARRAY);
- DRW_shgroup_uniform_texture(grp, "image_tile_array", array_tex);
- DRW_shgroup_uniform_texture(grp, "image_tile_data", data_tex);
- }
- else {
- GPUTexture *tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
+DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ eV3DShadingColorType color_type,
+ bool hair,
+ bool *r_transp)
+{
+ Image *ima = NULL;
+ ImageUser *iuser = NULL;
+ int interp;
+ const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ if (color_type == V3D_SHADING_TEXTURE_COLOR) {
+ workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
+ if (ima == NULL) {
+ /* Fallback to material color. */
+ color_type = V3D_SHADING_MATERIAL_COLOR;
}
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
}
- DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
+ switch (color_type) {
+ case V3D_SHADING_TEXTURE_COLOR: {
+ return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair);
+ }
+ case V3D_SHADING_MATERIAL_COLOR: {
+ /* For now, we use the same ubo for material and object coloring but with different indices.
+ * This means they are mutually exclusive. */
+ BLI_assert(
+ ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR));
+
+ Material *ma = workbench_object_material_get(ob, mat_nr);
+
+ const bool transp = wpd->shading.xray_alpha < 1.0f || ma->a < 1.0f;
+ WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair];
+
+ if (r_transp && transp) {
+ *r_transp = true;
+ }
- if (use_highlight) {
- DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
+ DRWShadingGroup **grp_mat = NULL;
+ /* A hashmap stores material shgroups to pack all similar drawcalls together. */
+ if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) {
+ return *grp_mat;
+ }
+
+ uint32_t mat_id, id = wpd->material_index++;
+
+ workbench_material_chunk_select(wpd, id, &mat_id);
+ workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[mat_id], color_type);
+
+ DRWShadingGroup *grp = prepass->common_shgrp;
+ *grp_mat = grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id);
+ return grp;
+ }
+ case V3D_SHADING_VERTEX_COLOR: {
+ const bool transp = wpd->shading.xray_alpha < 1.0f;
+ DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].vcol_shgrp;
+ return grp;
+ }
+ default: {
+ /* For now, we use the same ubo for material and object coloring but with different indices.
+ * This means they are mutually exclusive. */
+ BLI_assert(
+ !ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR));
+
+ uint32_t mat_id, id = DRW_object_resource_id_get(ob);
+
+ bool resource_changed = workbench_material_chunk_select(wpd, id, &mat_id);
+ workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type);
+
+ const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f;
+ DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].common_shgrp;
+ if (resource_changed) {
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ }
+ if (r_transp && transp) {
+ *r_transp = true;
+ }
+ return grp;
+ }
}
}
-void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
- const WORKBENCH_MaterialData *source_material)
+/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
+DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ Image *ima,
+ ImageUser *iuser,
+ int interp,
+ bool hair)
{
- copy_v3_v3(dest_material->base_color, source_material->base_color);
- dest_material->metallic = source_material->metallic;
- dest_material->roughness = source_material->roughness;
- dest_material->ima = source_material->ima;
- dest_material->iuser = source_material->iuser;
+ GPUTexture *tex = NULL, *tex_tile_data = NULL;
+
+ if (ima == NULL) {
+ workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
+ }
+
+ if (ima) {
+ if (ima->source == IMA_SRC_TILED) {
+ tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D_ARRAY);
+ tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_1D_ARRAY);
+ }
+ else {
+ tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D);
+ }
+ }
+
+ if (tex == NULL) {
+ printf("Image not foudn\n");
+ tex = wpd->dummy_image_tx;
+ }
+
+ const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
+ const bool transp = wpd->shading.xray_alpha < 1.0f;
+ WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair];
+
+ DRWShadingGroup **grp_tex = NULL;
+ /* A hashmap stores image shgroups to pack all similar drawcalls together. */
+ if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) {
+ return *grp_tex;
+ }
+
+ DRWShadingGroup *grp = (tex_tile_data) ? prepass->image_tiled_shgrp : prepass->image_shgrp;
+
+ *grp_tex = grp = DRW_shgroup_create_sub(grp);
+ if (tex_tile_data) {
+ DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex);
+ DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data);
+ }
+ else {
+ DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex);
+ }
+ DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
+ return grp;
}
diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c
new file mode 100644
index 00000000000..08511ca092c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_opaque.c
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Opaque Pipeline:
+ *
+ * Use deferred shading to render opaque surfaces.
+ * This decouple the shading cost from scene complexity.
+ *
+ * The rendering is broken down in two passes:
+ * - the pre-pass where we render all the surfaces and output material data.
+ * - the composite pass where we compute the final aspect of the pixels.
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_extensions.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+void workbench_opaque_engine_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_FramebufferList *fbl = data->fbl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DrawEngineType *owner = (DrawEngineType *)&workbench_opaque_engine_init;
+
+ /* Reused the same textures format for transparent pipeline to share the textures. */
+ const eGPUTextureFormat col_tex_format = GPU_RGBA16F;
+ const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA16F;
+
+ wpd->material_buffer_tx = DRW_texture_pool_query_fullscreen(col_tex_format, owner);
+ wpd->normal_buffer_tx = DRW_texture_pool_query_fullscreen(nor_tex_format, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->opaque_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
+ });
+}
+
+void workbench_opaque_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ const bool use_matcap = (wpd->shading.light == V3D_LIGHTING_MATCAP);
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+
+ int opaque = 0;
+ for (int infront = 0; infront < 2; infront++) {
+ DRWPass *pass;
+ if (infront) {
+ DRW_PASS_CREATE(psl->opaque_infront_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->opaque_infront_ps;
+ }
+ else {
+ DRW_PASS_CREATE(psl->opaque_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->opaque_ps;
+ }
+
+ for (int hair = 0; hair < 2; hair++) {
+ wpd->prepass[opaque][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
+
+ sh = workbench_shader_opaque_get(wpd, hair);
+
+ wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
+
+ wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
+
+ sh = workbench_shader_opaque_image_get(wpd, hair, false);
+
+ wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
+
+ sh = workbench_shader_opaque_image_get(wpd, hair, true);
+
+ wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
+ }
+ }
+ }
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_STENCIL_EQUAL;
+
+ DRW_PASS_CREATE(psl->composite_ps, state);
+
+ sh = workbench_shader_composite_get(wpd);
+
+ grp = DRW_shgroup_create(sh, psl->composite_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx);
+ DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx);
+ DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
+ DRW_shgroup_stencil_mask(grp, 0x00);
+
+ if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
+ struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture;
+ struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
+ const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
+ spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
+ }
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (SHADOW_ENABLED(wpd)) {
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", true);
+ DRW_shgroup_state_disable(grp, DRW_STATE_STENCIL_EQUAL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_STENCIL_NEQUAL);
+ DRW_shgroup_stencil_mask(grp, 0x00);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ }
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WRITE_STENCIL |
+ DRW_STATE_STENCIL_ALWAYS;
+
+ DRW_PASS_CREATE(psl->merge_infront_ps, state);
+
+ sh = workbench_shader_merge_infront_get(wpd);
+
+ grp = DRW_shgroup_create(sh, psl->merge_infront_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front);
+ DRW_shgroup_stencil_mask(grp, 0x00);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index bb93864966e..a68b66e0f85 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -34,16 +34,14 @@
#include "workbench_engine.h"
+extern struct DrawEngineType draw_engine_workbench;
+
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
-#define MAX_COMPOSITE_SHADERS (1 << 7)
-#define MAX_PREPASS_SHADERS (1 << 8)
-#define MAX_ACCUM_SHADERS (1 << 8)
-#define MAX_CAVITY_SHADERS (1 << 3)
-
-#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR)
-#define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR)
-#define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR)
-#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT)
+
+#define MAX_MATERIAL (1 << 12)
+
+#define DEBUG_SHADOW_VOLUME 0
+
#define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO)
#define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP)
#define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0)
@@ -63,45 +61,24 @@
(wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH)))
#define CAVITY_ENABLED(wpd) (CURVATURE_ENABLED(wpd) || SSAO_ENABLED(wpd))
#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW)
-#define GHOST_ENABLED(psl) \
- (!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass))
#define CULL_BACKFACE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_BACKFACE_CULLING) != 0)
-#define OIT_ENABLED(wpd) \
- (ELEM(wpd->shading.color_type, \
- V3D_SHADING_MATERIAL_COLOR, \
- V3D_SHADING_OBJECT_COLOR, \
- V3D_SHADING_TEXTURE_COLOR, \
- V3D_SHADING_VERTEX_COLOR))
-
-#define IS_NAVIGATING(wpd) \
- ((DRW_context_state_get()->rv3d) && \
- (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)))
#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
-#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \
- (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd))
-#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \
- (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
#define NORMAL_ENCODING_ENABLED() (true)
-#define WORLD_CLIPPING_ENABLED(wpd) (wpd->world_clip_planes != NULL)
struct RenderEngine;
struct RenderLayer;
struct rcti;
typedef struct WORKBENCH_FramebufferList {
- /* Deferred render buffers */
- struct GPUFrameBuffer *prepass_fb;
- struct GPUFrameBuffer *ghost_prepass_fb;
- struct GPUFrameBuffer *cavity_fb;
- struct GPUFrameBuffer *composite_fb;
- struct GPUFrameBuffer *id_clear_fb;
+ struct GPUFrameBuffer *opaque_fb;
+ struct GPUFrameBuffer *opaque_infront_fb;
- struct GPUFrameBuffer *effect_fb;
- struct GPUFrameBuffer *effect_taa_fb;
- struct GPUFrameBuffer *depth_buffer_fb;
- struct GPUFrameBuffer *color_only_fb;
+ struct GPUFrameBuffer *transp_accum_fb;
+ struct GPUFrameBuffer *transp_accum_infront_fb;
+
+ struct GPUFrameBuffer *id_clear_fb;
struct GPUFrameBuffer *dof_downsample_fb;
struct GPUFrameBuffer *dof_coc_tile_h_fb;
@@ -110,10 +87,9 @@ typedef struct WORKBENCH_FramebufferList {
struct GPUFrameBuffer *dof_blur1_fb;
struct GPUFrameBuffer *dof_blur2_fb;
- /* Forward render buffers */
- struct GPUFrameBuffer *object_outline_fb;
- struct GPUFrameBuffer *transparent_accum_fb;
- struct GPUFrameBuffer *transparent_revealage_fb;
+ struct GPUFrameBuffer *antialiasing_fb;
+ struct GPUFrameBuffer *smaa_edge_fb;
+ struct GPUFrameBuffer *smaa_weight_fb;
} WORKBENCH_FramebufferList;
typedef struct WORKBENCH_TextureList {
@@ -121,34 +97,35 @@ typedef struct WORKBENCH_TextureList {
struct GPUTexture *coc_halfres_tx;
struct GPUTexture *history_buffer_tx;
struct GPUTexture *depth_buffer_tx;
+ struct GPUTexture *smaa_search_tx;
+ struct GPUTexture *smaa_area_tx;
+ struct GPUTexture *dummy_image_tx;
+ struct GPUTexture *dummy_volume_tx;
+ struct GPUTexture *dummy_coba_tx;
} WORKBENCH_TextureList;
typedef struct WORKBENCH_StorageList {
- struct WORKBENCH_PrivateData *g_data;
- struct WORKBENCH_EffectInfo *effects;
+ struct WORKBENCH_PrivateData *wpd;
float *dof_ubo_data;
} WORKBENCH_StorageList;
typedef struct WORKBENCH_PassList {
- /* deferred rendering */
- struct DRWPass *prepass_pass;
- struct DRWPass *prepass_hair_pass;
- struct DRWPass *ghost_prepass_pass;
- struct DRWPass *ghost_prepass_hair_pass;
- struct DRWPass *cavity_pass;
- struct DRWPass *shadow_depth_pass_pass;
- struct DRWPass *shadow_depth_pass_mani_pass;
- struct DRWPass *shadow_depth_fail_pass;
- struct DRWPass *shadow_depth_fail_mani_pass;
- struct DRWPass *shadow_depth_fail_caps_pass;
- struct DRWPass *shadow_depth_fail_caps_mani_pass;
- struct DRWPass *composite_pass;
- struct DRWPass *composite_shadow_pass;
- struct DRWPass *oit_composite_pass;
- struct DRWPass *background_pass;
- struct DRWPass *background_pass_clip;
- struct DRWPass *ghost_resolve_pass;
- struct DRWPass *effect_aa_pass;
+ struct DRWPass *opaque_ps;
+ struct DRWPass *opaque_infront_ps;
+
+ struct DRWPass *transp_resolve_ps;
+ struct DRWPass *transp_accum_ps;
+ struct DRWPass *transp_accum_infront_ps;
+
+ struct DRWPass *shadow_ps[2];
+
+ struct DRWPass *merge_infront_ps;
+
+ struct DRWPass *cavity_ps;
+ struct DRWPass *outline_ps;
+
+ struct DRWPass *composite_ps;
+
struct DRWPass *dof_down_ps;
struct DRWPass *dof_down2_ps;
struct DRWPass *dof_flatten_v_ps;
@@ -158,12 +135,13 @@ typedef struct WORKBENCH_PassList {
struct DRWPass *dof_blur1_ps;
struct DRWPass *dof_blur2_ps;
struct DRWPass *dof_resolve_ps;
- struct DRWPass *volume_pass;
- /* forward rendering */
- struct DRWPass *transparent_accum_pass;
- struct DRWPass *object_outline_pass;
- struct DRWPass *depth_pass;
+ struct DRWPass *volume_ps;
+
+ struct DRWPass *aa_accum_ps;
+ struct DRWPass *aa_edge_ps;
+ struct DRWPass *aa_weight_ps;
+ struct DRWPass *aa_resolve_ps;
} WORKBENCH_PassList;
typedef struct WORKBENCH_Data {
@@ -180,84 +158,164 @@ typedef struct WORKBENCH_UBO_Light {
float diffuse_color[3], wrapped;
} WORKBENCH_UBO_Light;
+typedef struct WORKBENCH_UBO_Material {
+ float base_color[3];
+ /* Packed data into a int. Decoded in the shader. */
+ uint32_t packed_data;
+} WORKBENCH_UBO_Material;
+
typedef struct WORKBENCH_UBO_World {
+ float viewvecs[3][4];
+ float viewport_size[2], viewport_size_inv[2];
float object_outline_color[4];
float shadow_direction_vs[4];
+ float shadow_focus, shadow_shift, shadow_mul, shadow_add;
WORKBENCH_UBO_Light lights[4];
float ambient_color[4];
- int num_lights;
- int matcap_orientation;
+
+ int cavity_sample_start;
+ int cavity_sample_end;
+ float cavity_sample_count_inv;
+ float cavity_jitter_scale;
+
+ float cavity_valley_factor;
+ float cavity_ridge_factor;
+ float cavity_attenuation;
+ float cavity_distance;
+
float curvature_ridge;
float curvature_valley;
+ float ui_scale;
+ float _pad0;
+
+ int matcap_orientation;
+ int use_specular; /* Bools are 32bit ints in GLSL. */
+ int _pad1;
+ int _pad2;
} WORKBENCH_UBO_World;
+
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16)
+BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Light, 16)
+BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Material, 16)
-typedef struct WORKBENCH_PrivateData {
+typedef struct WORKBENCH_Prepass {
+ /** Hash storing shading group for each Material or GPUTexture to reduce state changes. */
struct GHash *material_hash;
- struct GHash *material_transp_hash;
- struct GPUShader *prepass_sh;
- struct GPUShader *prepass_hair_sh;
- struct GPUShader *prepass_uniform_sh;
- struct GPUShader *prepass_uniform_hair_sh;
- struct GPUShader *prepass_textured_sh;
- struct GPUShader *prepass_textured_array_sh;
- struct GPUShader *prepass_vertex_sh;
- struct GPUShader *composite_sh;
- struct GPUShader *background_sh;
- struct GPUShader *transparent_accum_sh;
- struct GPUShader *transparent_accum_hair_sh;
- struct GPUShader *transparent_accum_uniform_sh;
- struct GPUShader *transparent_accum_uniform_hair_sh;
- struct GPUShader *transparent_accum_textured_sh;
- struct GPUShader *transparent_accum_textured_array_sh;
- struct GPUShader *transparent_accum_vertex_sh;
+ /** First common (non-vcol and non-image colored) shading group to created subgroups. */
+ struct DRWShadingGroup *common_shgrp;
+ /** First Vertex Color shading group to created subgroups. */
+ struct DRWShadingGroup *vcol_shgrp;
+ /** First Image shading group to created subgroups. */
+ struct DRWShadingGroup *image_shgrp;
+ /** First UDIM (tiled image) shading group to created subgroups. */
+ struct DRWShadingGroup *image_tiled_shgrp;
+} WORKBENCH_Prepass;
+
+typedef struct WORKBENCH_PrivateData {
+ /** ViewLayerData for faster access. */
+ struct WORKBENCH_ViewLayerData *vldata;
+ /** Copy of draw_ctx->sh_cfg for faster access. */
+ eGPUShaderConfig sh_cfg;
+ /** Global clip and cull states. */
+ DRWState clip_state, cull_state;
+ /** Copy of scene->display.shading or v3d->shading for viewport. */
View3DShading shading;
+ /** Chosen studiolight or matcap. */
StudioLight *studio_light;
+ /** Copy of ctx_draw->scene for faster access. */
+ struct Scene *scene;
+ /** Shorthand version of U global for user preferences. */
const UserDef *preferences;
- /* Does this instance owns the `world_ubo` field.
- * Normally the field is borrowed from `WORKBENCH_WorldData`. In case that
- * there is no World attached to the scene the UBO cannot be cached and should
- * be freed after using. */
- bool is_world_ubo_owner;
+ /** Copy of context mode for faster access. */
+ eContextObjectMode ctx_mode;
+ /** Shorthand for wpd->vldata->world_ubo. */
struct GPUUniformBuffer *world_ubo;
- struct DRWShadingGroup *shadow_shgrp;
- struct DRWShadingGroup *depth_shgrp;
- WORKBENCH_UBO_World world_data;
- float shadow_multiplier;
- float shadow_shift;
- float shadow_focus;
- float cached_shadow_direction[3];
+ /** Background color to clear the color buffer with. */
+ float background_color[4];
+
+ /* Shadow */
+ /** Previous shadow direction to test if shadow has changed. */
+ float shadow_cached_direction[3];
+ /** Current shadow direction in world space. */
+ float shadow_direction_ws[3];
+ /** Shadow precomputed matrices. */
float shadow_mat[4][4];
float shadow_inv[4][4];
- /* Far plane of the view frustum. */
+ /** Far plane of the view frustum. Used for shadow volume extrusion. */
float shadow_far_plane[4];
- /* Near plane corners in shadow space. */
- float shadow_near_corners[4][3];
- /* min and max of shadow_near_corners. allow fast test */
+ /** Min and max of shadow_near_corners. Speed up culling test. */
float shadow_near_min[3];
float shadow_near_max[3];
- /* This is a parallelogram, so only 2 normal and distance to the edges. */
+ /** This is a parallelogram, so only 2 normal and distance to the edges. */
float shadow_near_sides[2][4];
+ /* Shadow shading groups. First array elem is for non-manifold geom and second for manifold. */
+ struct DRWShadingGroup *shadow_pass_grp[2];
+ struct DRWShadingGroup *shadow_fail_grp[2];
+ struct DRWShadingGroup *shadow_fail_caps_grp[2];
+ /** If the shadow has changed direction and ob bboxes needs to be updated. */
bool shadow_changed;
- bool is_playback;
- float (*world_clip_planes)[4];
+ /* Temporal Antialiasing */
+ /** Total number of samples to after which TAA stops accumulating samples. */
+ int taa_sample_len;
+ /** Current TAA sample index in [0..taa_sample_len[ range. */
+ int taa_sample;
+ /** Inverse of taa_sample to divide the accumulation buffer. */
+ float taa_sample_inv;
+ /** If the view has been updated and TAA needs to be reset. */
+ bool view_updated;
+ /** View */
+ struct DRWView *view;
+ /** Last projection matrix to see if view is still valid. */
+ float last_mat[4][4];
+
+ /* Smart Morphological Anti-Aliasing */
+ /** Temp buffers to store edges and weights. */
+ struct GPUTexture *smaa_edge_tx;
+ struct GPUTexture *smaa_weight_tx;
+ /** Weight of the smaa pass. */
+ float smaa_mix_factor;
+
+ /** Opaque pipeline buffers. */
+ struct GPUTexture *material_buffer_tx;
+ struct GPUTexture *composite_buffer_tx;
+ struct GPUTexture *normal_buffer_tx;
+ /** Transparent pipeline buffers. */
+ struct GPUTexture *accum_buffer_tx;
+ struct GPUTexture *reveal_buffer_tx;
+ /** Object IDs buffer for curvature & outline. */
+ struct GPUTexture *object_id_tx;
+
+ /** Prepass infos for each draw types [transparent][infront][hair]. */
+ WORKBENCH_Prepass prepass[2][2][2];
+
+ /* Materials */
+ /** Copy of vldata->material_ubo for faster access. */
+ struct BLI_memblock *material_ubo;
+ /** Copy of vldata->material_ubo_data for faster access. */
+ struct BLI_memblock *material_ubo_data;
+ /** Current material chunk being filled by workbench_material_setup_ex(). */
+ WORKBENCH_UBO_Material *material_ubo_data_curr;
+ struct GPUUniformBuffer *material_ubo_curr;
+ /** Copy of txl->dummy_image_tx for faster access. */
+ struct GPUTexture *dummy_image_tx;
+ /** Total number of used material chunk. */
+ int material_chunk_count;
+ /** Index of current material chunk. */
+ int material_chunk_curr;
+ /** Index of current material inside the material chunk. Only for material coloring mode. */
+ int material_index;
/* Volumes */
- bool volumes_do;
+ /** List of smoke domain textures to free after drawing. */
ListBase smoke_domains;
- /* Ssao */
- float winmat[4][4];
- float viewvecs[3][4];
- float ssao_params[4];
- float ssao_settings[4];
-
- /* Dof */
+ /* Depth of Field */
+ /** Depth of field temp buffers. */
struct GPUTexture *dof_blur_tx;
struct GPUTexture *coc_temp_tx;
struct GPUTexture *coc_tiles_tx[2];
- struct GPUUniformBuffer *dof_ubo;
+ /** Depth of field parameters. */
float dof_aperturesize;
float dof_distance;
float dof_invsensorsize;
@@ -265,37 +323,15 @@ typedef struct WORKBENCH_PrivateData {
float dof_blades;
float dof_rotation;
float dof_ratio;
- bool dof_enabled;
- /* Color Management */
- bool use_color_management;
- bool use_color_render_settings;
+ /** True if any volume needs to be rendered. */
+ bool volumes_do;
+ /** Convenience boolean. */
+ bool dof_enabled;
+ bool is_playback;
+ bool is_navigating;
} WORKBENCH_PrivateData; /* Transient data */
-typedef struct WORKBENCH_EffectInfo {
- /** View */
- struct DRWView *view;
- /** Last projection matrix to see if view is still valid. */
- float last_mat[4][4];
- int jitter_index;
- float taa_mix_factor;
- bool view_updated;
-} WORKBENCH_EffectInfo;
-
-typedef struct WORKBENCH_MaterialData {
- float base_color[3], metallic;
- float roughness, alpha;
- eV3DShadingColorType color_type;
- int interp;
- Image *ima;
- ImageUser *iuser;
-
- /* Linked shgroup for drawing */
- DRWShadingGroup *shgrp;
- /* forward rendering */
- DRWShadingGroup *shgrp_object_outline;
-} WORKBENCH_MaterialData;
-
typedef struct WORKBENCH_ObjectData {
DrawData dd;
@@ -307,20 +343,21 @@ typedef struct WORKBENCH_ObjectData {
bool shadow_bbox_dirty;
} WORKBENCH_ObjectData;
-typedef struct WORKBENCH_WorldData {
- DrawData dd;
- /* The cached `GPUUniformBuffer`, that is reused between draw calls. */
+typedef struct WORKBENCH_ViewLayerData {
+ /** Depth of field sample location array.*/
+ struct GPUUniformBuffer *dof_sample_ubo;
+ /** All constant data used for a render loop.*/
struct GPUUniformBuffer *world_ubo;
-} WORKBENCH_WorldData;
-
-/* Enumeration containing override options for base color rendering.
- * This is used to during painting to force the base color to show what you are
- * painting using the selected lighting model. */
-typedef enum WORKBENCH_ColorOverride {
- WORKBENCH_COLOR_OVERRIDE_OFF = 0,
- WORKBENCH_COLOR_OVERRIDE_TEXTURE = CTX_MODE_PAINT_TEXTURE,
- WORKBENCH_COLOR_OVERRIDE_VERTEX = CTX_MODE_PAINT_VERTEX,
-} WORKBENCH_ColorOverride;
+ /** Cavity sample location array.*/
+ struct GPUUniformBuffer *cavity_sample_ubo;
+ /** Blue noise texture used to randomize the sampling of some effects.*/
+ struct GPUTexture *cavity_jitter_tx;
+ /** Materials ubos allocated in a memblock for easy bookeeping. */
+ struct BLI_memblock *material_ubo;
+ struct BLI_memblock *material_ubo_data;
+ /** Number of samples for which cavity_sample_ubo is valid. */
+ int cavity_sample_count;
+} WORKBENCH_ViewLayerData;
/* inline helper functions */
BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd)
@@ -333,234 +370,129 @@ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *w
return false;
}
-BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd)
-{
- if (DRW_state_is_image_render()) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (draw_ctx->v3d) {
- return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA;
- }
- else {
- return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA;
- }
- }
- else {
- return !(IS_NAVIGATING(wpd) || wpd->is_playback) &&
- wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
- }
-}
-
-BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd)
-{
- if (DRW_state_is_image_render()) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (draw_ctx->v3d) {
- return draw_ctx->scene->display.viewport_aa == SCE_DISPLAY_AA_FXAA;
- }
- else {
- return draw_ctx->scene->display.render_aa == SCE_DISPLAY_AA_FXAA;
- }
- }
- else {
- if (wpd->preferences->viewport_aa == SCE_DISPLAY_AA_FXAA) {
- return true;
- }
-
- /* when navigating or animation playback use FXAA if scene uses TAA. */
- return (IS_NAVIGATING(wpd) || wpd->is_playback) &&
- wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
- }
-}
-
-/** Is texture paint mode enabled (globally) */
-BLI_INLINE bool workbench_is_in_texture_paint_mode(void)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT;
-}
-
-/** Is vertex paint mode enabled (globally) */
-BLI_INLINE bool workbench_is_in_vertex_paint_mode(void)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- return draw_ctx->object_mode == OB_MODE_VERTEX_PAINT;
-}
-
-/* Must the `View3DShading.color_type` be overriden for the given object. */
-BLI_INLINE WORKBENCH_ColorOverride workbench_object_color_override_get(Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (ob->type == OB_MESH && (draw_ctx->obact == ob)) {
- const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
- draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
- if (mode == CTX_MODE_PAINT_TEXTURE) {
- return WORKBENCH_COLOR_OVERRIDE_TEXTURE;
- }
- else if (mode == CTX_MODE_PAINT_VERTEX) {
- return WORKBENCH_COLOR_OVERRIDE_VERTEX;
- }
- }
-
- return WORKBENCH_COLOR_OVERRIDE_OFF;
-}
-
-BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd)
-{
- return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) ||
- workbench_is_in_texture_paint_mode() || workbench_is_in_vertex_paint_mode();
-}
-
-/**
- * Get the default texture format to be used by the color and history buffers.
- *
- * Use GPU_RGBA16F for final renderings and for drawing textures. This
- * allows displaying HDRI textures. Vertex Colors uses GPU_RGBA16 to resolve
- * color banding issues (T66100). All other modes use GPU_RGBA8 to reduce
- * bandwidth and gpu memory.
- */
-BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_PrivateData *wpd)
-{
- eGPUTextureFormat result;
- if (DRW_state_is_image_render() || workbench_is_in_texture_paint_mode() ||
- TEXTURE_DRAWING_ENABLED(wpd)) {
- result = GPU_RGBA16F;
- }
- else {
- result = GPU_RGBA16;
- }
- return result;
-}
-
-/* workbench_deferred.c */
-void workbench_deferred_engine_init(WORKBENCH_Data *vedata);
-void workbench_deferred_engine_free(void);
-void workbench_deferred_draw_scene(WORKBENCH_Data *vedata);
-void workbench_deferred_draw_finish(WORKBENCH_Data *vedata);
-void workbench_deferred_cache_init(WORKBENCH_Data *vedata);
-void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob);
-void workbench_deferred_cache_finish(WORKBENCH_Data *vedata);
-
-/* workbench_forward.c */
-void workbench_forward_engine_init(WORKBENCH_Data *vedata);
-void workbench_forward_engine_free(void);
-void workbench_forward_draw_scene(WORKBENCH_Data *vedata);
-void workbench_forward_draw_finish(WORKBENCH_Data *vedata);
-void workbench_forward_cache_init(WORKBENCH_Data *vedata);
-void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob);
-void workbench_forward_cache_finish(WORKBENCH_Data *vedata);
-
-/* For OIT in deferred */
-void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg);
-void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg);
-WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(
- WORKBENCH_Data *vedata,
- Object *ob,
- Material *mat,
- Image *ima,
- ImageUser *iuser,
- eV3DShadingColorType color_type,
- int interp);
-
-/* workbench_effect_aa.c */
-void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx);
-void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx);
-
-/* workbench_effect_fxaa.c */
-void workbench_fxaa_engine_init(void);
-void workbench_fxaa_engine_free(void);
-DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx);
-
-/* workbench_effect_taa.c */
-void workbench_taa_engine_init(WORKBENCH_Data *vedata);
-void workbench_taa_engine_free(void);
-DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx);
-void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata);
-void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata);
-void workbench_taa_view_updated(WORKBENCH_Data *vedata);
-int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
-int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata);
-
+/* workbench_opaque.c */
+void workbench_opaque_engine_init(WORKBENCH_Data *data);
+void workbench_opaque_cache_init(WORKBENCH_Data *data);
+
+/* workbench_transparent.c */
+void workbench_transparent_engine_init(WORKBENCH_Data *data);
+void workbench_transparent_cache_init(WORKBENCH_Data *data);
+void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
+
+/* workbench_shadow.c */
+void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
+void workbench_shadow_cache_init(WORKBENCH_Data *data);
+void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat);
+
+/* workbench_shader.c */
+GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair);
+GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled);
+GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd);
+GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *wpd);
+
+GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair);
+GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
+ bool hair,
+ bool tiled);
+GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd);
+
+GPUShader *workbench_shader_shadow_pass_get(bool manifold);
+GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap);
+
+GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature);
+GPUShader *workbench_shader_outline_get(void);
+
+GPUShader *workbench_shader_antialiasing_accumulation_get(void);
+GPUShader *workbench_shader_antialiasing_get(int stage);
+
+GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic);
+
+void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
+ GPUShader **downsample_sh,
+ GPUShader **blur1_sh,
+ GPUShader **blur2_sh,
+ GPUShader **resolve_sh);
+
+void workbench_shader_library_ensure(void);
+void workbench_shader_free(void);
+
+/* workbench_effect_antialiasing.c */
+int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd);
+void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata);
+void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata);
+void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata);
+bool workbench_antialiasing_setup(WORKBENCH_Data *vedata);
+void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata);
+
+/* workbench_effect_cavity.c */
+void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
+void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd);
+void workbench_cavity_cache_init(WORKBENCH_Data *data);
+
+/* workbench_effect_outline.c */
+void workbench_outline_cache_init(WORKBENCH_Data *data);
/* workbench_effect_dof.c */
-void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera);
-void workbench_dof_engine_free(void);
-void workbench_dof_create_pass(WORKBENCH_Data *vedata,
- GPUTexture **dof_input,
- GPUTexture *noise_tex);
+void workbench_dof_engine_init(WORKBENCH_Data *vedata);
+void workbench_dof_cache_init(WORKBENCH_Data *vedata);
void workbench_dof_draw_pass(WORKBENCH_Data *vedata);
/* workbench_materials.c */
-eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
- Image *ima,
- Object *ob,
- bool use_sculpt_pbvh);
-void workbench_material_get_image_and_mat(
- Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat);
-char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override);
-void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
- Object *ob,
- Material *mat,
- WORKBENCH_MaterialData *data,
- int color_type);
-uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost);
-int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd);
-int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override);
-int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override);
-void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
- DRWShadingGroup *grp,
- WORKBENCH_MaterialData *material,
- Object *ob,
- const bool deferred,
- const bool is_tiled,
- const int interp);
-void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
- const WORKBENCH_MaterialData *source_material);
-
-/* workbench_studiolight.c */
-void studiolight_update_world(WORKBENCH_PrivateData *wpd,
- StudioLight *sl,
- WORKBENCH_UBO_World *wd);
-void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]);
-bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed);
-float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed);
-bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed);
+void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ Material *mat,
+ WORKBENCH_UBO_Material *data,
+ eV3DShadingColorType color_type);
+
+DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ eV3DShadingColorType color_type,
+ bool hair,
+ bool *r_transp);
+DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ Image *ima,
+ ImageUser *iuser,
+ int interp,
+ bool hair);
+
+#define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \
+ workbench_material_setup_ex(wpd, ob, mat_nr, color_type, false, r_transp)
+#define workbench_image_setup(wpd, ob, mat_nr, ima, iuser, interp) \
+ workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, false)
+
+#define workbench_material_hair_setup(wpd, ob, mat_nr, color_type) \
+ workbench_material_setup_ex(wpd, ob, mat_nr, color_type, true, 0)
+#define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \
+ workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, true)
/* workbench_data.c */
-void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info);
void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
-void workbench_private_data_free(WORKBENCH_PrivateData *wpd);
-void workbench_private_data_get_light_direction(float r_light_direction[3]);
-void workbench_clear_color_get(float color[4]);
+void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd);
+void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd);
+struct GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd);
/* workbench_volume.c */
-void workbench_volume_engine_init(void);
-void workbench_volume_engine_free(void);
+void workbench_volume_engine_init(WORKBENCH_Data *vedata);
void workbench_volume_cache_init(WORKBENCH_Data *vedata);
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
- Scene *scene,
- Object *ob,
+ struct Scene *UNUSED(scene),
+ struct Object *ob,
struct ModifierData *md);
-void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd);
+void workbench_volume_draw_pass(WORKBENCH_Data *vedata);
+void workbench_volume_draw_finish(WORKBENCH_Data *vedata);
+
+/* workbench_engine.c */
+void workbench_engine_init(void *ved);
+void workbench_cache_init(void *ved);
+void workbench_cache_populate(void *ved, Object *ob);
+void workbench_cache_finish(void *ved);
+void workbench_draw_sample(void *ved);
+void workbench_draw_finish(void *ved);
/* workbench_render.c */
-void workbench_render(WORKBENCH_Data *vedata,
+void workbench_render(void *ved,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
const struct rcti *rect);
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 6e005e7ccaf..5a315e80a47 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -41,20 +41,12 @@
#include "workbench_private.h"
-static void workbench_render_deferred_cache(void *vedata,
- struct Object *ob,
- struct RenderEngine *UNUSED(engine),
- struct Depsgraph *UNUSED(depsgraph))
+static void workbench_render_cache(void *vedata,
+ struct Object *ob,
+ struct RenderEngine *UNUSED(engine),
+ struct Depsgraph *UNUSED(depsgraph))
{
- workbench_deferred_solid_cache_populate(vedata, ob);
-}
-
-static void workbench_render_forward_cache(void *vedata,
- struct Object *ob,
- struct RenderEngine *UNUSED(engine),
- struct Depsgraph *UNUSED(depsgraph))
-{
- workbench_forward_cache_populate(vedata, ob);
+ workbench_cache_populate(vedata, ob);
}
static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph)
@@ -171,18 +163,11 @@ static void workbench_render_result_z(struct RenderLayer *rl,
}
}
-static void workbench_render_framebuffers_finish(void)
-{
-}
-
-void workbench_render(WORKBENCH_Data *data,
- RenderEngine *engine,
- RenderLayer *render_layer,
- const rcti *rect)
+void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect)
{
+ WORKBENCH_Data *data = ved;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
Depsgraph *depsgraph = draw_ctx->depsgraph;
workbench_render_matrices_init(engine, depsgraph);
@@ -191,60 +176,32 @@ void workbench_render(WORKBENCH_Data *data,
return;
}
- const bool deferred = !XRAY_FLAG_ENABLED(&scene->display);
+ workbench_engine_init(data);
- if (deferred) {
- /* Init engine. */
- workbench_deferred_engine_init(data);
+ workbench_cache_init(data);
+ DRW_render_object_iter(data, engine, depsgraph, workbench_render_cache);
+ workbench_cache_finish(data);
- /* Init objects. */
- workbench_deferred_cache_init(data);
- DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache);
- workbench_deferred_cache_finish(data);
- DRW_render_instance_buffer_finish();
+ DRW_render_instance_buffer_finish();
- /* Also we weed to have a correct fbo bound for DRW_hair_update */
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_hair_update();
-
- /* Draw. */
- int num_samples = workbench_taa_calculate_num_iterations(data);
- for (int sample = 0; sample < num_samples; sample++) {
- if (RE_engine_test_break(engine)) {
- break;
- }
- workbench_deferred_draw_scene(data);
- }
+ /* Also we weed to have a correct fbo bound for DRW_hair_update */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_hair_update();
- workbench_deferred_draw_finish(data);
- }
- else {
- /* Init engine. */
- workbench_forward_engine_init(data);
-
- /* Init objects. */
- workbench_forward_cache_init(data);
- DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache);
- workbench_forward_cache_finish(data);
- DRW_render_instance_buffer_finish();
-
- /* Also we weed to have a correct fbo bound for DRW_hair_update */
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_hair_update();
-
- /* Draw. */
- int num_samples = workbench_taa_calculate_num_iterations(data);
- for (int sample = 0; sample < num_samples; sample++) {
- if (RE_engine_test_break(engine)) {
- break;
- }
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
- workbench_forward_draw_scene(data);
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
+ if (RE_engine_test_break(engine)) {
+ break;
}
-
- workbench_forward_draw_finish(data);
+ workbench_update_world_ubo(wpd);
+ workbench_draw_sample(data);
}
+ workbench_draw_finish(data);
+
/* Write render output. */
const char *viewname = RE_GetActiveRenderView(engine->re);
RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
@@ -260,8 +217,6 @@ void workbench_render(WORKBENCH_Data *data,
rp->rect);
workbench_render_result_z(render_layer, viewname, rect);
-
- workbench_render_framebuffers_finish();
}
void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c
new file mode 100644
index 00000000000..14a980fe628
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_shader.c
@@ -0,0 +1,533 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_smaa_lib_glsl[];
+
+extern char datatoc_workbench_prepass_vert_glsl[];
+extern char datatoc_workbench_prepass_hair_vert_glsl[];
+extern char datatoc_workbench_prepass_frag_glsl[];
+
+extern char datatoc_workbench_effect_cavity_frag_glsl[];
+extern char datatoc_workbench_effect_outline_frag_glsl[];
+extern char datatoc_workbench_effect_dof_frag_glsl[];
+extern char datatoc_workbench_effect_taa_frag_glsl[];
+extern char datatoc_workbench_effect_smaa_frag_glsl[];
+extern char datatoc_workbench_effect_smaa_vert_glsl[];
+
+extern char datatoc_workbench_composite_frag_glsl[];
+
+extern char datatoc_workbench_transparent_accum_frag_glsl[];
+extern char datatoc_workbench_transparent_resolve_frag_glsl[];
+
+extern char datatoc_workbench_merge_infront_frag_glsl[];
+
+extern char datatoc_workbench_shadow_vert_glsl[];
+extern char datatoc_workbench_shadow_geom_glsl[];
+extern char datatoc_workbench_shadow_caps_geom_glsl[];
+extern char datatoc_workbench_shadow_debug_frag_glsl[];
+
+extern char datatoc_workbench_volume_vert_glsl[];
+extern char datatoc_workbench_volume_frag_glsl[];
+
+extern char datatoc_workbench_cavity_lib_glsl[];
+extern char datatoc_workbench_common_lib_glsl[];
+extern char datatoc_workbench_curvature_lib_glsl[];
+extern char datatoc_workbench_data_lib_glsl[];
+extern char datatoc_workbench_image_lib_glsl[];
+extern char datatoc_workbench_matcap_lib_glsl[];
+extern char datatoc_workbench_material_lib_glsl[];
+extern char datatoc_workbench_shader_interface_lib_glsl[];
+extern char datatoc_workbench_world_light_lib_glsl[];
+
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+
+/* Maximum number of variations. */
+#define MAX_LIGHTING 3
+#define MAX_COLOR 3
+#define MAX_GEOM 2
+
+enum {
+ VOLUME_SH_SLICE = 0,
+ VOLUME_SH_COBA,
+ VOLUME_SH_CUBIC,
+};
+
+#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
+
+static struct {
+ struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_COLOR];
+ struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_LIGHTING][MAX_COLOR];
+
+ struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
+ struct GPUShader *oit_resolve_sh;
+ struct GPUShader *outline_sh;
+ struct GPUShader *merge_infront_sh;
+
+ struct GPUShader *shadow_depth_pass_sh[2];
+ struct GPUShader *shadow_depth_fail_sh[2][2];
+
+ struct GPUShader *cavity_sh[2][2];
+
+ struct GPUShader *dof_prepare_sh;
+ struct GPUShader *dof_downsample_sh;
+ struct GPUShader *dof_blur1_sh;
+ struct GPUShader *dof_blur2_sh;
+ struct GPUShader *dof_resolve_sh;
+
+ struct GPUShader *aa_accum_sh;
+ struct GPUShader *smaa_sh[3];
+
+ struct GPUShader *volume_sh[2][2][2];
+
+ struct DRWShaderLibrary *lib;
+} e_data = {{{{NULL}}}};
+
+void workbench_shader_library_ensure(void)
+{
+ if (e_data.lib == NULL) {
+ e_data.lib = DRW_shader_library_create();
+ /* NOTE: Theses needs to be ordered by dependencies. */
+ DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib);
+ }
+}
+
+static char *workbench_build_defines(
+ WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) {
+ BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
+ }
+ else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) {
+ BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
+ }
+ else {
+ BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
+ }
+
+ if (NORMAL_ENCODING_ENABLED()) {
+ BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
+ }
+
+ if (textured) {
+ BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
+ }
+ if (tiled) {
+ BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
+ }
+ if (cavity) {
+ BLI_dynstr_append(ds, "#define USE_CAVITY\n");
+ }
+ if (curvature) {
+ BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled)
+{
+ BLI_assert(2 < MAX_COLOR);
+ return (textured) ? (tiled ? 2 : 1) : 0;
+}
+
+static GPUShader *workbench_shader_get_ex(
+ WORKBENCH_PrivateData *wpd, bool transp, bool hair, bool textured, bool tiled)
+{
+ int color = workbench_color_index(wpd, textured, tiled);
+ int light = wpd->shading.light;
+ BLI_assert(light < MAX_LIGHTING);
+ struct GPUShader **shader =
+ (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][hair][light][color] :
+ &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][hair][color];
+
+ if (*shader == NULL) {
+ char *defines = workbench_build_defines(wpd, textured, tiled, false, false);
+
+ char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl :
+ datatoc_workbench_prepass_frag_glsl;
+ char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file);
+
+ char *vert_file = hair ? datatoc_workbench_prepass_hair_vert_glsl :
+ datatoc_workbench_prepass_vert_glsl;
+ char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file);
+
+ const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg];
+
+ *shader = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL},
+ .frag = (const char *[]){frag_src, NULL},
+ .defs = (const char *[]){sh_cfg_data->def,
+ defines,
+ transp ? "#define TRANSPARENT_MATERIAL\n" :
+ "#define OPAQUE_MATERIAL\n",
+ NULL},
+ });
+
+ MEM_freeN(defines);
+ MEM_freeN(frag_src);
+ MEM_freeN(vert_src);
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair)
+{
+ return workbench_shader_get_ex(wpd, false, hair, false, false);
+}
+
+GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled)
+{
+ return workbench_shader_get_ex(wpd, false, hair, true, tiled);
+}
+
+GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair)
+{
+ return workbench_shader_get_ex(wpd, true, hair, false, false);
+}
+
+GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
+ bool hair,
+ bool tiled)
+{
+ return workbench_shader_get_ex(wpd, true, hair, true, tiled);
+}
+
+GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
+{
+ int light = wpd->shading.light;
+ struct GPUShader **shader = &e_data.opaque_composite_sh[light];
+ BLI_assert(light < MAX_LIGHTING);
+
+ if (*shader == NULL) {
+ char *defines = workbench_build_defines(wpd, false, false, false, false);
+ char *frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_composite_frag_glsl);
+
+ *shader = DRW_shader_create_fullscreen(frag, defines);
+
+ MEM_freeN(defines);
+ MEM_freeN(frag);
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
+{
+ if (e_data.merge_infront_sh == NULL) {
+ char *frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_workbench_merge_infront_frag_glsl);
+
+ e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL);
+
+ MEM_freeN(frag);
+ }
+ return e_data.merge_infront_sh;
+}
+
+GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd)
+{
+ if (e_data.oit_resolve_sh == NULL) {
+ char *defines = workbench_build_defines(wpd, false, false, false, false);
+
+ e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_transparent_resolve_frag_glsl, defines);
+
+ MEM_freeN(defines);
+ }
+ return e_data.oit_resolve_sh;
+}
+
+static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap)
+{
+ struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] :
+ &e_data.shadow_depth_fail_sh[manifold][cap];
+
+ if (*shader == NULL) {
+#if DEBUG_SHADOW_VOLUME
+ const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
+#else
+ const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl;
+#endif
+
+ *shader = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_view_lib_glsl,
+ datatoc_workbench_shadow_vert_glsl,
+ NULL},
+ .geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl :
+ datatoc_workbench_shadow_geom_glsl,
+ NULL},
+ .frag = (const char *[]){shadow_frag, NULL},
+ .defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n",
+ (manifold) ? "" : "#define DOUBLE_MANIFOLD\n",
+ NULL},
+ });
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_shadow_pass_get(bool manifold)
+{
+ return workbench_shader_shadow_pass_get_ex(true, manifold, false);
+}
+
+GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap)
+{
+ return workbench_shader_shadow_pass_get_ex(false, manifold, cap);
+}
+
+GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
+{
+ BLI_assert(cavity || curvature);
+ struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
+
+ if (*shader == NULL) {
+ char *defines = workbench_build_defines(NULL, false, false, cavity, curvature);
+ char *frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_workbench_effect_cavity_frag_glsl);
+
+ *shader = DRW_shader_create_fullscreen(frag, defines);
+
+ MEM_freeN(defines);
+ MEM_freeN(frag);
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_outline_get(void)
+{
+ if (e_data.outline_sh == NULL) {
+ char *frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_workbench_effect_outline_frag_glsl);
+
+ e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL);
+
+ MEM_freeN(frag);
+ }
+ return e_data.outline_sh;
+}
+
+void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
+ GPUShader **downsample_sh,
+ GPUShader **blur1_sh,
+ GPUShader **blur2_sh,
+ GPUShader **resolve_sh)
+{
+ if (e_data.dof_prepare_sh == NULL) {
+ e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define PREPARE\n");
+
+ e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define DOWNSAMPLE\n");
+#if 0 /* TODO(fclem) finish COC min_max optimization */
+ e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_VERTICAL\n");
+
+ e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_HORIZONTAL\n");
+
+ e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_VERTICAL\n");
+
+ e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_HORIZONTAL\n");
+#endif
+ e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR1\n");
+
+ e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR2\n");
+
+ e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define RESOLVE\n");
+ }
+
+ *prepare_sh = e_data.dof_prepare_sh;
+ *downsample_sh = e_data.dof_downsample_sh;
+ *blur1_sh = e_data.dof_blur1_sh;
+ *blur2_sh = e_data.dof_blur2_sh;
+ *resolve_sh = e_data.dof_resolve_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_accumulation_get(void)
+{
+ if (e_data.aa_accum_sh == NULL) {
+ char *frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_effect_taa_frag_glsl);
+
+ e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL);
+
+ MEM_freeN(frag);
+ }
+ return e_data.aa_accum_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_get(int stage)
+{
+ BLI_assert(stage < 3);
+ if (!e_data.smaa_sh[stage]) {
+ char stage_define[32];
+ BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
+
+ e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 1\n",
+ "#define SMAA_INCLUDE_PS 0\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_workbench_effect_smaa_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 0\n",
+ "#define SMAA_INCLUDE_PS 1\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_workbench_effect_smaa_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define SMAA_GLSL_3\n",
+ "#define SMAA_RT_METRICS viewportMetrics\n",
+ "#define SMAA_PRESET_HIGH\n",
+ "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n",
+ "#define SMAA_NO_DISCARD\n",
+ stage_define,
+ NULL,
+ },
+ });
+ }
+ return e_data.smaa_sh[stage];
+}
+
+GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic)
+{
+ GPUShader **shader = &e_data.volume_sh[slice][coba][cubic];
+
+ if (*shader == NULL) {
+ DynStr *ds = BLI_dynstr_new();
+
+ if (slice) {
+ BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
+ }
+ if (coba) {
+ BLI_dynstr_append(ds, "#define USE_COBA\n");
+ }
+ if (cubic) {
+ BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
+ }
+
+ char *defines = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ char *vert = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_volume_vert_glsl);
+ char *frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_volume_frag_glsl);
+
+ *shader = DRW_shader_create(vert, NULL, frag, defines);
+
+ MEM_freeN(vert);
+ MEM_freeN(frag);
+ MEM_freeN(defines);
+ }
+ return *shader;
+}
+
+void workbench_shader_free(void)
+{
+ for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.opaque_composite_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_composite_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.shadow_depth_pass_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.smaa_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.smaa_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.volume_sh[0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+
+ DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_sh);
+ DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
+
+ DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c
new file mode 100644
index 00000000000..efd0ad9134e
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_shadow.c
@@ -0,0 +1,367 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Shadow:
+ *
+ * Use stencil shadow buffer to cast a sharp shadow over opaque surfaces.
+ *
+ * After the main pre-pass we render shadow volumes using custom depth & stencil states to
+ * set the stencil of shadowed area to anything but 0.
+ *
+ * Then the shading pass will shade the areas with stencil not equal 0 differently.
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_object.h"
+
+#include "BLI_math.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+static void compute_parallel_lines_nor_and_dist(const float v1[2],
+ const float v2[2],
+ const float v3[2],
+ float r_line[4])
+{
+ sub_v2_v2v2(r_line, v2, v1);
+ /* Find orthogonal vector. */
+ SWAP(float, r_line[0], r_line[1]);
+ r_line[0] = -r_line[0];
+ /* Edge distances. */
+ r_line[2] = dot_v2v2(r_line, v1);
+ r_line[3] = dot_v2v2(r_line, v3);
+ /* Make sure r_line[2] is the minimum. */
+ if (r_line[2] > r_line[3]) {
+ SWAP(float, r_line[2], r_line[3]);
+ }
+}
+
+static void workbench_shadow_update(WORKBENCH_PrivateData *wpd)
+{
+ wpd->shadow_changed = !compare_v3v3(
+ wpd->shadow_cached_direction, wpd->shadow_direction_ws, 1e-5f);
+
+ if (wpd->shadow_changed) {
+ float up[3] = {0.0f, 0.0f, 1.0f};
+ unit_m4(wpd->shadow_mat);
+
+ /* TODO fix singularity. */
+ copy_v3_v3(wpd->shadow_mat[2], wpd->shadow_direction_ws);
+ cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
+ normalize_v3(wpd->shadow_mat[0]);
+ cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
+
+ invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
+
+ copy_v3_v3(wpd->shadow_cached_direction, wpd->shadow_direction_ws);
+ }
+
+ float planes[6][4];
+ DRW_culling_frustum_planes_get(NULL, planes);
+ /* we only need the far plane. */
+ copy_v4_v4(wpd->shadow_far_plane, planes[2]);
+
+ BoundBox frustum_corners;
+ DRW_culling_frustum_corners_get(NULL, &frustum_corners);
+
+ float shadow_near_corners[4][3];
+ mul_v3_mat3_m4v3(shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
+ mul_v3_mat3_m4v3(shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
+ mul_v3_mat3_m4v3(shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
+ mul_v3_mat3_m4v3(shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
+
+ INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
+ for (int i = 0; i < 4; i++) {
+ minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, shadow_near_corners[i]);
+ }
+
+ compute_parallel_lines_nor_and_dist(shadow_near_corners[0],
+ shadow_near_corners[1],
+ shadow_near_corners[2],
+ wpd->shadow_near_sides[0]);
+ compute_parallel_lines_nor_and_dist(shadow_near_corners[1],
+ shadow_near_corners[2],
+ shadow_near_corners[0],
+ wpd->shadow_near_sides[1]);
+}
+
+void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+
+ float view_matrix[4][4];
+ DRW_view_viewmat_get(NULL, view_matrix, false);
+
+ /* Turn the light in a way where it's more user friendly to control. */
+ copy_v3_v3(wpd->shadow_direction_ws, scene->display.light_direction);
+ SWAP(float, wpd->shadow_direction_ws[2], wpd->shadow_direction_ws[1]);
+ wpd->shadow_direction_ws[2] = -wpd->shadow_direction_ws[2];
+ wpd->shadow_direction_ws[0] = -wpd->shadow_direction_ws[0];
+
+ /* Shadow direction. */
+ mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->shadow_direction_ws);
+
+ /* Clamp to avoid overshadowing and shading errors. */
+ float focus = clamp_f(scene->display.shadow_focus, 0.0001f, 0.99999f);
+ wd->shadow_shift = scene->display.shadow_shift;
+ wd->shadow_focus = 1.0f - focus * (1.0f - wd->shadow_shift);
+
+ if (SHADOW_ENABLED(wpd)) {
+ wd->shadow_mul = wpd->shading.shadow_intensity;
+ wd->shadow_add = 1.0f - wd->shadow_mul;
+ }
+ else {
+ wd->shadow_mul = 0.0f;
+ wd->shadow_add = 1.0f;
+ }
+}
+
+void workbench_shadow_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (SHADOW_ENABLED(wpd)) {
+ workbench_shadow_update(wpd);
+
+#if DEBUG_SHADOW_VOLUME
+ DRWState depth_pass_state = DRW_STATE_DEPTH_LESS;
+ DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL;
+#else
+ DRWState depth_pass_state = DRW_STATE_WRITE_STENCIL_SHADOW_PASS;
+ DRWState depth_fail_state = DRW_STATE_WRITE_STENCIL_SHADOW_FAIL;
+ DRWState state = DRW_STATE_DEPTH_LESS | DRW_STATE_STENCIL_ALWAYS;
+#endif
+
+ /* TODO(fclem) Merge into one pass with subpasses. */
+ DRW_PASS_CREATE(psl->shadow_ps[0], state | depth_pass_state);
+ DRW_PASS_CREATE(psl->shadow_ps[1], state | depth_fail_state);
+
+ /* Stencil Shadow passes. */
+ for (int manifold = 0; manifold < 2; manifold++) {
+ sh = workbench_shader_shadow_pass_get(manifold);
+ wpd->shadow_pass_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[0]);
+ DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */
+
+ sh = workbench_shader_shadow_fail_get(manifold, false);
+ wpd->shadow_fail_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]);
+ DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */
+
+ sh = workbench_shader_shadow_fail_get(manifold, true);
+ wpd->shadow_fail_caps_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]);
+ }
+ }
+ else {
+ psl->shadow_ps[0] = NULL;
+ psl->shadow_ps[1] = NULL;
+ }
+}
+
+static BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ if (oed->shadow_bbox_dirty || wpd->shadow_changed) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
+
+ /* Get AABB in shadow space. */
+ INIT_MINMAX(oed->shadow_min, oed->shadow_max);
+
+ /* From object space to shadow space */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ for (int i = 0; i < 8; i++) {
+ float corner[3];
+ mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
+ minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
+ }
+ oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
+ /* Extend towards infinity. */
+ oed->shadow_max[2] += 1e4f;
+
+ /* Get extended AABB in world space. */
+ BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
+ }
+ oed->shadow_bbox_dirty = false;
+ }
+
+ return &oed->shadow_bbox;
+}
+
+static bool workbench_shadow_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
+ const DRWView *default_view = DRW_view_default_get();
+ return DRW_culling_box_test(default_view, shadow_bbox);
+}
+
+static float workbench_shadow_object_shadow_distance(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
+
+ int corners[4] = {0, 3, 4, 7};
+ float dist = 1e4f, dist_isect;
+ for (int i = 0; i < 4; i++) {
+ if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
+ wpd->shadow_cached_direction,
+ wpd->shadow_far_plane,
+ &dist_isect,
+ true)) {
+ if (dist_isect < dist) {
+ dist = dist_isect;
+ }
+ }
+ else {
+ /* All rays are parallels. If one fails, the other will too. */
+ break;
+ }
+ }
+ return max_ii(dist - oed->shadow_depth, 0);
+}
+
+static bool workbench_shadow_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ /* Just to be sure the min, max are updated. */
+ workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
+ /* Test if near plane is in front of the shadow. */
+ if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
+ return false;
+ }
+
+ /* Separation Axis Theorem test */
+
+ /* Test bbox sides first (faster) */
+ if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
+ (oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
+ (oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
+ (oed->shadow_max[1] < wpd->shadow_near_min[1])) {
+ return false;
+ }
+ /* Test projected near rectangle sides */
+ const float pts[4][2] = {
+ {oed->shadow_min[0], oed->shadow_min[1]},
+ {oed->shadow_min[0], oed->shadow_max[1]},
+ {oed->shadow_max[0], oed->shadow_min[1]},
+ {oed->shadow_max[0], oed->shadow_max[1]},
+ };
+
+ for (int i = 0; i < 2; i++) {
+ float min_dst = FLT_MAX, max_dst = -FLT_MAX;
+ for (int j = 0; j < 4; j++) {
+ float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
+ /* Do min max */
+ if (min_dst > dst) {
+ min_dst = dst;
+ }
+ if (max_dst < dst) {
+ max_dst = dst;
+ }
+ }
+
+ if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) {
+ return false;
+ }
+ }
+ /* No separation axis found. Both shape intersect. */
+ return true;
+}
+
+static void workbench_init_object_data(DrawData *dd)
+{
+ WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
+ data->shadow_bbox_dirty = true;
+}
+
+void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat)
+{
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+
+ bool is_manifold;
+ struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold);
+ if (geom_shadow == NULL) {
+ return;
+ }
+
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id,
+ &draw_engine_workbench,
+ sizeof(WORKBENCH_ObjectData),
+ &workbench_init_object_data,
+ NULL);
+
+ if (workbench_shadow_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
+ mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->shadow_direction_ws);
+
+ DRWShadingGroup *grp;
+ bool use_shadow_pass_technique = !workbench_shadow_camera_in_object_shadow(
+ wpd, ob, engine_object_data);
+
+ /* Shadow pass technique needs object to be have all its surface opaque. */
+ if (has_transp_mat) {
+ use_shadow_pass_technique = false;
+ }
+
+ if (use_shadow_pass_technique) {
+ grp = DRW_shgroup_create_sub(wpd->shadow_pass_grp[is_manifold]);
+ DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f);
+ DRW_shgroup_call_no_cull(grp, geom_shadow, ob);
+#if DEBUG_SHADOW_VOLUME
+ DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
+#endif
+ }
+ else {
+ float extrude_distance = workbench_shadow_object_shadow_distance(
+ wpd, ob, engine_object_data);
+
+ /* TODO(fclem): only use caps if they are in the view frustum. */
+ const bool need_caps = true;
+ if (need_caps) {
+ grp = DRW_shgroup_create_sub(wpd->shadow_fail_caps_grp[is_manifold]);
+ DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
+ DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob);
+ }
+
+ grp = DRW_shgroup_create_sub(wpd->shadow_fail_grp[is_manifold]);
+ DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
+ DRW_shgroup_call_no_cull(grp, geom_shadow, ob);
+#if DEBUG_SHADOW_VOLUME
+ DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
+#endif
+ }
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
deleted file mode 100644
index 1fb0b394cb1..00000000000
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * 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.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-#include "BKE_studiolight.h"
-
-#include "workbench_private.h"
-
-#include "BKE_object.h"
-
-#include "BLI_math.h"
-
-void studiolight_update_world(WORKBENCH_PrivateData *wpd,
- StudioLight *studiolight,
- WORKBENCH_UBO_World *wd)
-{
- float view_matrix[4][4], rot_matrix[4][4];
- DRW_view_viewmat_get(NULL, view_matrix, false);
-
- if (USE_WORLD_ORIENTATION(wpd)) {
- axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
- mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
- swap_v3_v3(rot_matrix[2], rot_matrix[1]);
- negate_v3(rot_matrix[2]);
- }
- else {
- unit_m4(rot_matrix);
- }
-
- if (U.edit_studio_light) {
- studiolight = BKE_studiolight_studio_edit_get();
- }
-
- /* Studio Lights. */
- for (int i = 0; i < 4; i++) {
- WORKBENCH_UBO_Light *light = &wd->lights[i];
-
- SolidLight *sl = &studiolight->light[i];
- if (sl->flag) {
- copy_v3_v3(light->light_direction, sl->vec);
- mul_mat3_m4_v3(rot_matrix, light->light_direction);
- /* We should predivide the power by PI but that makes the lights really dim. */
- copy_v3_v3(light->specular_color, sl->spec);
- copy_v3_v3(light->diffuse_color, sl->col);
- light->wrapped = sl->smooth;
- }
- else {
- copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
- copy_v3_fl(light->specular_color, 0.0f);
- copy_v3_fl(light->diffuse_color, 0.0f);
- }
- }
-
- copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
-}
-
-static void compute_parallel_lines_nor_and_dist(const float v1[2],
- const float v2[2],
- const float v3[2],
- float r_line[4])
-{
- sub_v2_v2v2(r_line, v2, v1);
- /* Find orthogonal vector. */
- SWAP(float, r_line[0], r_line[1]);
- r_line[0] = -r_line[0];
- /* Edge distances. */
- r_line[2] = dot_v2v2(r_line, v1);
- r_line[3] = dot_v2v2(r_line, v3);
- /* Make sure r_line[2] is the minimum. */
- if (r_line[2] > r_line[3]) {
- SWAP(float, r_line[2], r_line[3]);
- }
-}
-
-void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
-{
- wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f);
-
- if (wpd->shadow_changed) {
- float up[3] = {0.0f, 0.0f, 1.0f};
- unit_m4(wpd->shadow_mat);
-
- /* TODO fix singularity. */
- copy_v3_v3(wpd->shadow_mat[2], light_direction);
- cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
- normalize_v3(wpd->shadow_mat[0]);
- cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
-
- invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
-
- copy_v3_v3(wpd->cached_shadow_direction, light_direction);
- }
-
- float planes[6][4];
- DRW_culling_frustum_planes_get(NULL, planes);
- /* we only need the far plane. */
- copy_v4_v4(wpd->shadow_far_plane, planes[2]);
-
- BoundBox frustum_corners;
- DRW_culling_frustum_corners_get(NULL, &frustum_corners);
-
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
-
- INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
- for (int i = 0; i < 4; i++) {
- minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
- }
-
- compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0],
- wpd->shadow_near_corners[1],
- wpd->shadow_near_corners[2],
- wpd->shadow_near_sides[0]);
- compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1],
- wpd->shadow_near_corners[2],
- wpd->shadow_near_corners[0],
- wpd->shadow_near_sides[1]);
-}
-
-static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) {
- float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
-
- /* Get AABB in shadow space. */
- INIT_MINMAX(oed->shadow_min, oed->shadow_max);
-
- /* From object space to shadow space */
- BoundBox *bbox = BKE_object_boundbox_get(ob);
- for (int i = 0; i < 8; i++) {
- float corner[3];
- mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
- minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
- }
- oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
- /* Extend towards infinity. */
- oed->shadow_max[2] += 1e4f;
-
- /* Get extended AABB in world space. */
- BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
- for (int i = 0; i < 8; i++) {
- mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
- }
- oed->shadow_bbox_dirty = false;
- }
-
- return &oed->shadow_bbox;
-}
-
-bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
- const DRWView *default_view = DRW_view_default_get();
- return DRW_culling_box_test(default_view, shadow_bbox);
-}
-
-float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
-
- int corners[4] = {0, 3, 4, 7};
- float dist = 1e4f, dist_isect;
- for (int i = 0; i < 4; i++) {
- if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
- wpd->cached_shadow_direction,
- wpd->shadow_far_plane,
- &dist_isect,
- true)) {
- if (dist_isect < dist) {
- dist = dist_isect;
- }
- }
- else {
- /* All rays are parallels. If one fails, the other will too. */
- break;
- }
- }
- return max_ii(dist - oed->shadow_depth, 0);
-}
-
-bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- /* Just to be sure the min, max are updated. */
- studiolight_object_shadow_bbox_get(wpd, ob, oed);
-
- /* Test if near plane is in front of the shadow. */
- if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
- return false;
- }
-
- /* Separation Axis Theorem test */
-
- /* Test bbox sides first (faster) */
- if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
- (oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
- (oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
- (oed->shadow_max[1] < wpd->shadow_near_min[1])) {
- return false;
- }
-
- /* Test projected near rectangle sides */
- const float pts[4][2] = {
- {oed->shadow_min[0], oed->shadow_min[1]},
- {oed->shadow_min[0], oed->shadow_max[1]},
- {oed->shadow_max[0], oed->shadow_min[1]},
- {oed->shadow_max[0], oed->shadow_max[1]},
- };
-
- for (int i = 0; i < 2; i++) {
- float min_dst = FLT_MAX, max_dst = -FLT_MAX;
- for (int j = 0; j < 4; j++) {
- float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
- /* Do min max */
- if (min_dst > dst) {
- min_dst = dst;
- }
- if (max_dst < dst) {
- max_dst = dst;
- }
- }
-
- if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) {
- return false;
- }
- }
-
- /* No separation axis found. Both shape intersect. */
- return true;
-}
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
new file mode 100644
index 00000000000..39aa721a41c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Transparent Pipeline:
+ *
+ * Use Weight Blended Order Independent Transparency to render transparent surfaces.
+ *
+ * The rendering is broken down in two passes:
+ * - the accumulation pass where we render all the surfaces and accumulate all the weights.
+ * - the resolve pass where we divide the accumulated information by the weights.
+ *
+ * An additional re-render of the transparent surfaces is sometime done in order to have their
+ * correct depth and object ids correctly written.
+ */
+
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_extensions.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+void workbench_transparent_engine_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_FramebufferList *fbl = data->fbl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DrawEngineType *owner = (DrawEngineType *)&workbench_transparent_engine_init;
+
+ /* Reuse same format as opaque pipeline to reuse the textures. */
+ /* Note: Floating point texture is required for the reveal_tex as it is used for
+ * the alpha accumulation component (see accumulation shader for more explanation). */
+ const eGPUTextureFormat accum_tex_format = GPU_RGBA16F;
+ const eGPUTextureFormat reveal_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA32F;
+
+ wpd->accum_buffer_tx = DRW_texture_pool_query_fullscreen(accum_tex_format, owner);
+ wpd->reveal_buffer_tx = DRW_texture_pool_query_fullscreen(reveal_tex_format, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->transp_accum_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx),
+ });
+}
+
+static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
+ DRWShadingGroup *grp)
+{
+ DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
+
+ if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
+ struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture;
+ struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
+ const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
+ spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
+ }
+}
+
+void workbench_transparent_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ {
+ int transp = 1;
+ for (int infront = 0; infront < 2; infront++) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_OIT;
+
+ DRWPass *pass;
+ if (infront) {
+ DRW_PASS_CREATE(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->transp_accum_infront_ps;
+ }
+ else {
+ DRW_PASS_CREATE(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->transp_accum_ps;
+ }
+
+ for (int hair = 0; hair < 2; hair++) {
+ wpd->prepass[transp][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
+
+ sh = workbench_shader_transparent_get(wpd, hair);
+
+ wpd->prepass[transp][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
+ workbench_transparent_lighting_uniforms(wpd, grp);
+
+ wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
+
+ sh = workbench_shader_transparent_image_get(wpd, hair, false);
+
+ wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ workbench_transparent_lighting_uniforms(wpd, grp);
+
+ sh = workbench_shader_transparent_image_get(wpd, hair, true);
+
+ wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ workbench_transparent_lighting_uniforms(wpd, grp);
+ }
+ }
+ }
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+
+ DRW_PASS_CREATE(psl->transp_resolve_ps, state);
+
+ sh = workbench_shader_transparent_resolve_get(wpd);
+
+ grp = DRW_shgroup_create(sh, psl->transp_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "transparentAccum", wpd->accum_buffer_tx);
+ DRW_shgroup_uniform_texture(grp, "transparentRevealage", wpd->reveal_buffer_tx);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+/* Redraw the transparent passes but with depth test
+ * to output correct outline IDs and depth. */
+void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data)
+{
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ WORKBENCH_FramebufferList *fbl = data->fbl;
+ WORKBENCH_PassList *psl = data->psl;
+
+ const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f;
+ const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass;
+
+ if (do_transparent_depth_pass) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+
+ if (!DRW_pass_is_empty(psl->transp_accum_ps)) {
+ GPU_framebuffer_bind(fbl->opaque_fb);
+ /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */
+ DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state);
+ DRW_draw_pass(psl->transp_accum_ps);
+ }
+
+ if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) {
+ GPU_framebuffer_bind(fbl->opaque_infront_fb);
+ /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */
+ DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state);
+ DRW_draw_pass(psl->transp_accum_infront_ps);
+ }
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 2f7296fb40f..a3072b834bd 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -35,87 +35,23 @@
#include "GPU_draw.h"
-enum {
- VOLUME_SH_SLICE = 0,
- VOLUME_SH_COBA,
- VOLUME_SH_CUBIC,
-};
-
-#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
-
-static struct {
- struct GPUShader *volume_sh[VOLUME_SH_MAX];
- struct GPUShader *volume_coba_sh;
- struct GPUTexture *dummy_tex;
- struct GPUTexture *dummy_coba_tex;
-} e_data = {{NULL}};
-
-extern char datatoc_workbench_volume_vert_glsl[];
-extern char datatoc_workbench_volume_frag_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
-
-static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
+void workbench_volume_engine_init(WORKBENCH_Data *vedata)
{
- int id = 0;
- id += (slice) ? (1 << VOLUME_SH_SLICE) : 0;
- id += (coba) ? (1 << VOLUME_SH_COBA) : 0;
- id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0;
-
- if (!e_data.volume_sh[id]) {
- DynStr *ds = BLI_dynstr_new();
-
- if (slice) {
- BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
- }
- if (coba) {
- BLI_dynstr_append(ds, "#define USE_COBA\n");
- }
- if (cubic) {
- BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
- }
-
- char *defines = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_gpu_shader_common_obinfos_lib_glsl);
-
- e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
- NULL,
- datatoc_workbench_volume_frag_glsl,
- libs,
- defines);
-
- MEM_freeN(libs);
- MEM_freeN(defines);
- }
-
- return e_data.volume_sh[id];
-}
+ WORKBENCH_TextureList *txl = vedata->txl;
-void workbench_volume_engine_init(void)
-{
- if (!e_data.dummy_tex) {
+ if (txl->dummy_volume_tx == NULL) {
float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- e_data.dummy_tex = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL);
- e_data.dummy_coba_tex = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL);
+ txl->dummy_volume_tx = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL);
+ txl->dummy_coba_tx = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL);
}
}
-void workbench_volume_engine_free(void)
-{
- for (int i = 0; i < VOLUME_SH_MAX; i++) {
- DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
- }
- DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
- DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex);
-}
-
void workbench_volume_cache_init(WORKBENCH_Data *vedata)
{
- vedata->psl->volume_pass = DRW_pass_create(
+ vedata->psl->volume_ps = DRW_pass_create(
"Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
+
+ vedata->stl->wpd->volumes_do = false;
}
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
@@ -125,8 +61,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
{
FluidModifierData *mmd = (FluidModifierData *)md;
FluidDomainSettings *mds = mmd->domain;
- WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
- WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_TextureList *txl = vedata->txl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
DRWShadingGroup *grp = NULL;
@@ -146,14 +82,16 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
GPU_create_smoke(mmd, 1);
}
- if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) {
+ if ((!mds->use_coba && (mds->tex_density == NULL && mds->tex_color == NULL)) ||
+ (mds->use_coba && mds->tex_field == NULL)) {
return;
}
const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
mds->axis_slice_method == AXIS_SLICE_SINGLE);
const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC);
- GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp);
+
+ GPUShader *sh = workbench_shader_volume_get(use_slice, mds->use_coba, cubic_interp);
if (use_slice) {
float invviewmat[4][4];
@@ -167,7 +105,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
/* 0.05f to achieve somewhat the same opacity as the full view. */
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
- grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
+ grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
@@ -175,7 +113,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
}
else {
double noise_ofs;
- BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs);
+ BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
float dim[3], step_length, max_slice;
float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]};
mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel));
@@ -185,8 +123,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
mul_v3_v3(dim, slice_ct);
step_length = len_v3(dim);
- grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
@@ -201,12 +139,13 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
static float white[3] = {1.0f, 1.0f, 1.0f};
bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
(mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
- DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex);
+ DRW_shgroup_uniform_texture(
+ grp, "densityTexture", (mds->tex_color) ? mds->tex_color : mds->tex_density);
DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow);
DRW_shgroup_uniform_texture(
- grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex);
+ grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : txl->dummy_volume_tx);
DRW_shgroup_uniform_texture(
- grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex);
+ grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : txl->dummy_coba_tx);
DRW_shgroup_uniform_vec3(
grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1);
}
@@ -223,8 +162,22 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd));
}
-void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
+void workbench_volume_draw_pass(WORKBENCH_Data *vedata)
{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (wpd->volumes_do) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->volume_ps);
+ }
+}
+
+void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+
/* Free Smoke Textures after rendering */
/* XXX This is a waste of processing and GPU bandwidth if nothing
* is updated. But the problem is since Textures are stored in the
@@ -236,4 +189,4 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
GPU_free_smoke(mmd);
}
BLI_freelistN(&wpd->smoke_domains);
-}
+} \ No newline at end of file
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index cc257b80daf..8ed7bb25336 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -81,6 +81,7 @@ typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
typedef struct DRWView DRWView;
+typedef struct DRWShaderLibrary DRWShaderLibrary;
/* TODO Put it somewhere else? */
typedef struct BoundSphere {
@@ -148,6 +149,8 @@ struct GPUTexture *DRW_texture_pool_query_2d(int w,
int h,
eGPUTextureFormat format,
DrawEngineType *engine_type);
+struct GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format,
+ DrawEngineType *engine_type);
struct GPUTexture *DRW_texture_create_1d(int w,
eGPUTextureFormat format,
@@ -163,6 +166,8 @@ struct GPUTexture *DRW_texture_create_cube(int w,
eGPUTextureFormat format,
DRWTextureFlag flags,
const float *fpixels);
+struct GPUTexture *DRW_texture_create_cube_array(
+ int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels);
void DRW_texture_ensure_fullscreen_2d(struct GPUTexture **tex,
eGPUTextureFormat format,
@@ -211,16 +216,17 @@ struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *def
struct GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig slot);
struct GPUMaterial *DRW_shader_find_from_world(struct World *wo,
const void *engine_type,
- int options,
+ const int options,
bool deferred);
struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma,
const void *engine_type,
- int options,
+ const int options,
bool deferred);
struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
struct World *wo,
const void *engine_type,
- int options,
+ const int options,
+ const bool is_volume_shader,
const char *vert,
const char *geom,
const char *frag_lib,
@@ -229,7 +235,8 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
struct Material *ma,
const void *engine_type,
- int options,
+ const int options,
+ const bool is_volume_shader,
const char *vert,
const char *geom,
const char *frag_lib,
@@ -244,51 +251,72 @@ void DRW_shader_free(struct GPUShader *shader);
} \
} while (0)
-/* Batches */
+DRWShaderLibrary *DRW_shader_library_create(void);
+
+/* Warning: Each library must be added after all its dependencies. */
+void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name);
+#define DRW_SHADER_LIB_ADD(lib, lib_name) \
+ DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl")
+
+char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code);
+
+void DRW_shader_library_free(DRWShaderLibrary *lib);
+#define DRW_SHADER_LIB_FREE_SAFE(lib) \
+ do { \
+ if (lib != NULL) { \
+ DRW_shader_library_free(lib); \
+ lib = NULL; \
+ } \
+ } while (0)
+/* Batches */
+/* DRWState is a bitmask that stores the current render state and the desired render state. Based
+ * on the differences the minimum state changes can be invoked to setup the desired render state.
+ *
+ * The Write Stencil, Stencil test, Depth test and Blend state options are mutual exclusive
+ * therefore they aren't ordered as a bit mask.*/
typedef enum {
/** Write mask */
DRW_STATE_WRITE_DEPTH = (1 << 0),
DRW_STATE_WRITE_COLOR = (1 << 1),
+ /* Write Stencil. These options are mutual exclusive and packed into 2 bits */
DRW_STATE_WRITE_STENCIL = (1 << 2),
- DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 3),
- DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (1 << 4),
-
- /** Depth test */
- DRW_STATE_DEPTH_ALWAYS = (1 << 5),
- DRW_STATE_DEPTH_LESS = (1 << 6),
- DRW_STATE_DEPTH_LESS_EQUAL = (1 << 7),
- DRW_STATE_DEPTH_EQUAL = (1 << 8),
- DRW_STATE_DEPTH_GREATER = (1 << 9),
- DRW_STATE_DEPTH_GREATER_EQUAL = (1 << 10),
+ DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (2 << 2),
+ DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (3 << 2),
+ /** Depth test. These options are mutual exclusive and packed into 3 bits */
+ DRW_STATE_DEPTH_ALWAYS = (1 << 4),
+ DRW_STATE_DEPTH_LESS = (2 << 4),
+ DRW_STATE_DEPTH_LESS_EQUAL = (3 << 4),
+ DRW_STATE_DEPTH_EQUAL = (4 << 4),
+ DRW_STATE_DEPTH_GREATER = (5 << 4),
+ DRW_STATE_DEPTH_GREATER_EQUAL = (6 << 4),
/** Culling test */
- DRW_STATE_CULL_BACK = (1 << 11),
- DRW_STATE_CULL_FRONT = (1 << 12),
- /** Stencil test */
- DRW_STATE_STENCIL_ALWAYS = (1 << 13),
- DRW_STATE_STENCIL_EQUAL = (1 << 14),
- DRW_STATE_STENCIL_NEQUAL = (1 << 15),
-
- /** Blend state */
- DRW_STATE_BLEND_ADD = (1 << 16),
+ DRW_STATE_CULL_BACK = (1 << 7),
+ DRW_STATE_CULL_FRONT = (1 << 8),
+ /** Stencil test . These options are mutal exclusive and packed into 2 bits*/
+ DRW_STATE_STENCIL_ALWAYS = (1 << 9),
+ DRW_STATE_STENCIL_EQUAL = (2 << 9),
+ DRW_STATE_STENCIL_NEQUAL = (3 << 9),
+
+ /** Blend state. These options are mutual exclusive and packed into 4 bits */
+ DRW_STATE_BLEND_ADD = (1 << 11),
/** Same as additive but let alpha accumulate without premult. */
- DRW_STATE_BLEND_ADD_FULL = (1 << 17),
+ DRW_STATE_BLEND_ADD_FULL = (2 << 11),
/** Standard alpha blending. */
- DRW_STATE_BLEND_ALPHA = (1 << 18),
+ DRW_STATE_BLEND_ALPHA = (3 << 11),
/** Use that if color is already premult by alpha. */
- DRW_STATE_BLEND_ALPHA_PREMUL = (1 << 19),
- DRW_STATE_BLEND_BACKGROUND = (1 << 20),
- DRW_STATE_BLEND_OIT = (1 << 21),
- DRW_STATE_BLEND_MUL = (1 << 22),
- DRW_STATE_BLEND_SUB = (1 << 23),
+ DRW_STATE_BLEND_ALPHA_PREMUL = (4 << 11),
+ DRW_STATE_BLEND_BACKGROUND = (5 << 11),
+ DRW_STATE_BLEND_OIT = (6 << 11),
+ DRW_STATE_BLEND_MUL = (7 << 11),
+ DRW_STATE_BLEND_SUB = (8 << 11),
/** Use dual source blending. WARNING: Only one color buffer allowed. */
- DRW_STATE_BLEND_CUSTOM = (1 << 24),
+ DRW_STATE_BLEND_CUSTOM = (9 << 11),
+ DRW_STATE_LOGIC_INVERT = (10 << 11),
- DRW_STATE_IN_FRONT_SELECT = (1 << 25),
- DRW_STATE_LOGIC_INVERT = (1 << 26),
- DRW_STATE_SHADOW_OFFSET = (1 << 27),
- DRW_STATE_CLIP_PLANES = (1 << 28),
- // DRW_STATE_WIRE_SMOOTH = (1 << 29), /* UNUSED */
+ DRW_STATE_IN_FRONT_SELECT = (1 << 27),
+ DRW_STATE_SHADOW_OFFSET = (1 << 28),
+ DRW_STATE_CLIP_PLANES = (1 << 29),
DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30),
/** DO NOT USE. Assumed always enabled. Only used internally. */
DRW_STATE_PROGRAM_POINT_SIZE = (1u << 31),
@@ -401,18 +429,21 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint
DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \
} while (0)
+/* Can only be called during iter phase. */
+uint32_t DRW_object_resource_id_get(Object *UNUSED(ob));
+
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
/* Reminders:
* - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
* stencil_value being the value stored in the stencil buffer.
- * - (writemask & reference) is what gets written if the test condition is fullfiled.
+ * - (write-mask & reference) is what gets written if the test condition is fulfilled.
**/
void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
- uint comp_mask);
+ uint compare_mask);
/* TODO remove this function. Obsolete version. mask is actually reference value. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 24d3b7fa7b6..5818d84a7af 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -177,6 +177,11 @@ struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object,
struct DRWPass *hair_pass,
struct GPUShader *shader);
+struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
+ struct ParticleSystem *psys,
+ struct ModifierData *md,
+ struct DRWShadingGroup *shgrp);
+
struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 08256b931ba..c88071dc6d6 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -36,6 +36,7 @@
#include "GPU_batch.h"
#include "GPU_shader.h"
+#include "GPU_vertex_buffer.h"
#include "draw_hair_private.h"
@@ -62,6 +63,8 @@ static int g_tf_target_width;
static int g_tf_target_height;
#endif
+static GPUVertBuf *g_dummy_vbo = NULL;
+static GPUTexture *g_dummy_texture = NULL;
static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL};
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
@@ -102,12 +105,29 @@ void DRW_hair_init(void)
#else
g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
#endif
+
+ if (g_dummy_vbo == NULL) {
+ /* initialize vertex format */
+ GPUVertFormat format = {0};
+ uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ g_dummy_vbo = GPU_vertbuf_create_with_format(&format);
+
+ float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_vertbuf_data_alloc(g_dummy_vbo, 1);
+ GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(g_dummy_vbo);
+
+ g_dummy_texture = GPU_texture_create_from_vertbuf(g_dummy_vbo);
+ }
}
static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
ParticleSystem *psys,
ModifierData *md,
DRWPass *hair_pass,
+ DRWShadingGroup *shgrp_parent,
struct GPUMaterial *gpu_mat,
GPUShader *gpu_shader)
{
@@ -127,7 +147,10 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
object, psys, md, &hair_cache, subdiv, thickness_res);
DRWShadingGroup *shgrp;
- if (gpu_mat) {
+ if (shgrp_parent) {
+ shgrp = DRW_shgroup_create_sub(shgrp_parent);
+ }
+ else if (gpu_mat) {
shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass);
}
else if (gpu_shader) {
@@ -151,6 +174,17 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
}
}
+ /* Fix issue with certain driver not drawing anything if there is no texture bound to
+ * "ac", "au", "u" or "c". */
+ if (hair_cache->num_uv_layers == 0) {
+ DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
+ DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
+ }
+ if (hair_cache->num_col_layers == 0) {
+ DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
+ DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
+ }
+
if ((dupli_parent != NULL) && (dupli_object != NULL)) {
if (dupli_object->type & OB_DUPLICOLLECTION) {
copy_m4_m4(dupli_mat, dupli_parent->obmat);
@@ -220,7 +254,15 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
DRWShadingGroup *DRW_shgroup_hair_create(
Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader)
{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader);
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader);
+}
+
+DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
+ ParticleSystem *psys,
+ ModifierData *md,
+ DRWShadingGroup *shgrp)
+{
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL);
}
DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
@@ -229,7 +271,7 @@ DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
DRWPass *hair_pass,
struct GPUMaterial *material)
{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL);
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL);
}
void DRW_hair_update(void)
@@ -313,4 +355,7 @@ void DRW_hair_free(void)
for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(g_refine_shaders[i]);
}
+
+ GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
+ DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
}
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index b9711b4f88f..6d81d82a6cf 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1118,45 +1118,23 @@ 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 */
-static void drw_engines_enable_from_engine(RenderEngineType *engine_type,
- eDrawType drawtype,
- bool use_xray)
+static void drw_engines_enable_from_engine(RenderEngineType *engine_type, eDrawType drawtype)
{
switch (drawtype) {
case OB_WIRE:
- use_drw_engine(&draw_engine_workbench_transparent);
- break;
-
case OB_SOLID:
- if (use_xray) {
- use_drw_engine(&draw_engine_workbench_transparent);
- }
- else {
- use_drw_engine(&draw_engine_workbench_solid);
- }
+ use_drw_engine(DRW_engine_viewport_workbench_type.draw_engine);
break;
-
case OB_MATERIAL:
case OB_RENDER:
default:
- /* TODO layers */
if (engine_type->draw_engine != NULL) {
use_drw_engine(engine_type->draw_engine);
}
-
- if ((engine_type->flag & RE_INTERNAL) == 0) {
- drw_engines_enable_external();
+ else if ((engine_type->flag & RE_INTERNAL) == 0) {
+ use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
}
break;
}
@@ -1182,7 +1160,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
const eDrawType drawtype = v3d->shading.type;
const bool use_xray = XRAY_ENABLED(v3d);
- drw_engines_enable_from_engine(engine_type, drawtype, use_xray);
+ drw_engines_enable_from_engine(engine_type, drawtype);
if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) {
use_drw_engine(&draw_engine_gpencil_type);
}
@@ -1608,6 +1586,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
GPU_blend(true);
}
+ GPU_matrix_identity_set();
+ GPU_matrix_identity_projection_set();
+
GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management);
if (draw_background) {
@@ -2646,9 +2627,6 @@ void DRW_engines_register(void)
RE_engines_register(&DRW_engine_viewport_eevee_type);
RE_engines_register(&DRW_engine_viewport_workbench_type);
- DRW_engine_register(&draw_engine_workbench_solid);
- DRW_engine_register(&draw_engine_workbench_transparent);
-
DRW_engine_register(&draw_engine_gpencil_type);
DRW_engine_register(&draw_engine_overlay_type);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 83142da051a..be0dd7751ed 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -562,6 +562,16 @@ static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
return handle;
}
+uint32_t DRW_object_resource_id_get(Object *UNUSED(ob))
+{
+ DRWResourceHandle handle = DST.ob_handle;
+ if (handle == 0) {
+ /* Handle not yet allocated. Return next handle. */
+ handle = DST.resource_handle;
+ }
+ return handle;
+}
+
static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
float (*obmat)[4],
Object *ob)
@@ -693,14 +703,14 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf,
static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
- uint comp_mask)
+ uint compare_mask)
{
BLI_assert(write_mask <= 0xFF);
BLI_assert(reference <= 0xFF);
- BLI_assert(comp_mask <= 0xFF);
+ BLI_assert(compare_mask <= 0xFF);
DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
cmd->write_mask = write_mask;
- cmd->comp_mask = comp_mask;
+ cmd->comp_mask = compare_mask;
cmd->ref = reference;
}
@@ -1341,9 +1351,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
- uint comp_mask)
+ uint compare_mask)
{
- drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask);
+ drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask);
}
/* TODO remove this function. */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 85525ea7b55..3d1b43537b7 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -114,19 +114,20 @@ void drw_state_set(DRWState state)
/* Stencil Write */
if (test) {
glStencilMask(0xFF);
- if (test & DRW_STATE_WRITE_STENCIL) {
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- }
- else if (test & DRW_STATE_WRITE_STENCIL_SHADOW_PASS) {
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
- }
- else if (test & DRW_STATE_WRITE_STENCIL_SHADOW_FAIL) {
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
- }
- else {
- BLI_assert(0);
+ switch (test) {
+ case DRW_STATE_WRITE_STENCIL:
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ break;
+ case DRW_STATE_WRITE_STENCIL_SHADOW_PASS:
+ glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
+ break;
+ case DRW_STATE_WRITE_STENCIL_SHADOW_FAIL:
+ glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
+ break;
+ default:
+ BLI_assert(0);
}
}
else {
@@ -191,26 +192,27 @@ void drw_state_set(DRWState state)
if (test) {
glEnable(GL_DEPTH_TEST);
- if (state & DRW_STATE_DEPTH_LESS) {
- glDepthFunc(GL_LESS);
- }
- else if (state & DRW_STATE_DEPTH_LESS_EQUAL) {
- 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_GREATER_EQUAL) {
- glDepthFunc(GL_GEQUAL);
- }
- else if (state & DRW_STATE_DEPTH_ALWAYS) {
- glDepthFunc(GL_ALWAYS);
- }
- else {
- BLI_assert(0);
+ switch (test) {
+ case DRW_STATE_DEPTH_LESS:
+ glDepthFunc(GL_LESS);
+ break;
+ case DRW_STATE_DEPTH_LESS_EQUAL:
+ glDepthFunc(GL_LEQUAL);
+ break;
+ case DRW_STATE_DEPTH_EQUAL:
+ glDepthFunc(GL_EQUAL);
+ break;
+ case DRW_STATE_DEPTH_GREATER:
+ glDepthFunc(GL_GREATER);
+ break;
+ case DRW_STATE_DEPTH_GREATER_EQUAL:
+ glDepthFunc(GL_GEQUAL);
+ break;
+ case DRW_STATE_DEPTH_ALWAYS:
+ glDepthFunc(GL_ALWAYS);
+ break;
+ default:
+ BLI_assert(0);
}
}
else {
@@ -244,62 +246,63 @@ void drw_state_set(DRWState state)
if (test) {
glEnable(GL_BLEND);
- if ((state & DRW_STATE_BLEND_ALPHA) != 0) {
- glBlendFuncSeparate(GL_SRC_ALPHA,
- GL_ONE_MINUS_SRC_ALPHA, /* RGB */
- GL_ONE,
- GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
- }
- else if ((state & DRW_STATE_BLEND_BACKGROUND) != 0) {
- /* Special blend to add color under and multiply dst by alpha. */
- glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA,
- GL_SRC_ALPHA, /* RGB */
- GL_ZERO,
- GL_SRC_ALPHA); /* Alpha */
- }
- else if ((state & DRW_STATE_BLEND_ALPHA_PREMUL) != 0) {
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- }
- else if ((state & DRW_STATE_BLEND_MUL) != 0) {
- glBlendFunc(GL_DST_COLOR, GL_ZERO);
- }
- else if ((state & DRW_STATE_BLEND_OIT) != 0) {
- glBlendFuncSeparate(GL_ONE,
- GL_ONE, /* RGB */
- GL_ZERO,
- GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
- }
- else if ((state & DRW_STATE_BLEND_ADD) != 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_BLEND_ADD_FULL) != 0) {
- /* Let alpha accumulate. */
- glBlendFunc(GL_ONE, GL_ONE);
- }
- else if ((state & DRW_STATE_BLEND_SUB) != 0) {
- glBlendFunc(GL_ONE, GL_ONE);
- }
- else if ((state & DRW_STATE_BLEND_CUSTOM) != 0) {
- /* Custom blend parameters using dual source blending.
- * Can only be used with one Draw Buffer. */
- glBlendFunc(GL_ONE, GL_SRC1_COLOR);
- }
- else if ((state & DRW_STATE_LOGIC_INVERT) != 0) {
- /* Replace logic op by blend func to support floating point framebuffer. */
- glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR,
- GL_ZERO, /* RGB */
- GL_ZERO,
- GL_ONE); /* Alpha */
- }
- else {
- BLI_assert(0);
+ switch (test) {
+ case DRW_STATE_BLEND_ALPHA:
+ glBlendFuncSeparate(GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA, /* RGB */
+ GL_ONE,
+ GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
+ break;
+ case DRW_STATE_BLEND_BACKGROUND:
+ /* Special blend to add color under and multiply dst by alpha. */
+ glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA,
+ GL_SRC_ALPHA, /* RGB */
+ GL_ZERO,
+ GL_SRC_ALPHA); /* Alpha */
+ break;
+ case DRW_STATE_BLEND_ALPHA_PREMUL:
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ case DRW_STATE_BLEND_MUL:
+ glBlendFunc(GL_DST_COLOR, GL_ZERO);
+ break;
+ case DRW_STATE_BLEND_OIT:
+ glBlendFuncSeparate(GL_ONE,
+ GL_ONE, /* RGB */
+ GL_ZERO,
+ GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
+ break;
+ case DRW_STATE_BLEND_ADD:
+ /* Do not let alpha accumulate but premult the source RGB by it. */
+ glBlendFuncSeparate(GL_SRC_ALPHA,
+ GL_ONE, /* RGB */
+ GL_ZERO,
+ GL_ONE); /* Alpha */
+ break;
+ case DRW_STATE_BLEND_ADD_FULL:
+ /* Let alpha accumulate. */
+ glBlendFunc(GL_ONE, GL_ONE);
+ break;
+ case DRW_STATE_BLEND_SUB:
+ glBlendFunc(GL_ONE, GL_ONE);
+ break;
+ case DRW_STATE_BLEND_CUSTOM:
+ /* Custom blend parameters using dual source blending.
+ * Can only be used with one Draw Buffer. */
+ glBlendFunc(GL_ONE, GL_SRC1_COLOR);
+ break;
+ case DRW_STATE_LOGIC_INVERT:
+ /* Replace logic op by blend func to support floating point framebuffer. */
+ glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR,
+ GL_ZERO, /* RGB */
+ GL_ZERO,
+ GL_ONE); /* Alpha */
+ break;
+ default:
+ BLI_assert(0);
}
- if ((state & DRW_STATE_BLEND_SUB) != 0) {
+ if (test == DRW_STATE_BLEND_SUB) {
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
}
else {
@@ -402,17 +405,17 @@ static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_
/* Reminders:
* - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
* stencil_value being the value stored in the stencil buffer.
- * - (writemask & reference) is what gets written if the test condition is fullfiled.
+ * - (write-mask & reference) is what gets written if the test condition is fulfilled.
**/
glStencilMask(write_mask);
-
- if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) {
+ DRWState stencil_test = DST.state & DRW_STATE_STENCIL_TEST_ENABLED;
+ if (stencil_test == DRW_STATE_STENCIL_ALWAYS) {
glStencilFunc(GL_ALWAYS, reference, compare_mask);
}
- else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) {
+ else if (stencil_test == DRW_STATE_STENCIL_EQUAL) {
glStencilFunc(GL_EQUAL, reference, compare_mask);
}
- else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) {
+ else if (stencil_test == DRW_STATE_STENCIL_NEQUAL) {
glStencilFunc(GL_NOTEQUAL, reference, compare_mask);
}
}
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 9c34cdbac3b..7b08f44921f 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -24,6 +24,7 @@
#include "DNA_world_types.h"
#include "DNA_material_types.h"
+#include "BLI_dynstr.h"
#include "BLI_listbase.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -282,6 +283,8 @@ void DRW_deferred_shader_remove(GPUMaterial *mat)
/* -------------------------------------------------------------------- */
+/** \{ */
+
GPUShader *DRW_shader_create(const char *vert,
const char *geom,
const char *frag,
@@ -356,7 +359,7 @@ GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig sh_cfg)
GPUMaterial *DRW_shader_find_from_world(World *wo,
const void *engine_type,
- int options,
+ const int options,
bool deferred)
{
GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
@@ -372,7 +375,7 @@ GPUMaterial *DRW_shader_find_from_world(World *wo,
GPUMaterial *DRW_shader_find_from_material(Material *ma,
const void *engine_type,
- int options,
+ const int options,
bool deferred)
{
GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
@@ -389,7 +392,8 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma,
GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
World *wo,
const void *engine_type,
- int options,
+ const int options,
+ const bool is_volume_shader,
const char *vert,
const char *geom,
const char *frag_lib,
@@ -409,6 +413,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
&wo->gpumaterial,
engine_type,
options,
+ is_volume_shader,
vert,
geom,
frag_lib,
@@ -426,7 +431,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
Material *ma,
const void *engine_type,
- int options,
+ const int options,
+ const bool is_volume_shader,
const char *vert,
const char *geom,
const char *frag_lib,
@@ -446,6 +452,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
&ma->gpumaterial,
engine_type,
options,
+ is_volume_shader,
vert,
geom,
frag_lib,
@@ -464,3 +471,129 @@ void DRW_shader_free(GPUShader *shader)
{
GPU_shader_free(shader);
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shader Library
+ *
+ * Simple include system for glsl files.
+ *
+ * Usage: Create a DRWShaderLibrary and add the library in the right order.
+ * You can have nested dependencies but each new library needs to have all its dependencies already
+ * added to the DRWShaderLibrary.
+ * Finally you can use DRW_shader_library_create_shader_string to get a shader string that also
+ * contains the needed libraries for this shader.
+ * \{ */
+
+/* 32 because we use a 32bit bitmap. */
+#define MAX_LIB 32
+#define MAX_LIB_NAME 64
+#define MAX_LIB_DEPS 8
+
+struct DRWShaderLibrary {
+ char *libs[MAX_LIB];
+ char libs_name[MAX_LIB][MAX_LIB_NAME];
+ uint32_t libs_deps[MAX_LIB];
+};
+
+DRWShaderLibrary *DRW_shader_library_create(void)
+{
+ return MEM_callocN(sizeof(DRWShaderLibrary), "DRWShaderLibrary");
+}
+
+void DRW_shader_library_free(DRWShaderLibrary *lib)
+{
+ MEM_SAFE_FREE(lib);
+}
+
+static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name)
+{
+ for (int i = 0; i < MAX_LIB; i++) {
+ if (lib->libs[i]) {
+ if (!strncmp(lib->libs_name[i], name, strlen(lib->libs_name[i]))) {
+ return i;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ return -1;
+}
+
+/* Return bitmap of dependencies. */
+static uint32_t drw_shader_dependencies_get(DRWShaderLibrary *lib, char *lib_code)
+{
+ /* Search dependencies. */
+ uint32_t deps = 0;
+ char *haystack = lib_code;
+ while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) {
+ haystack += 16;
+ int dep = drw_shader_library_search(lib, haystack);
+ if (dep == -1) {
+ printf(
+ "Error: Dependency not found.\n"
+ "This might be due to bad lib ordering.\n");
+ BLI_assert(0);
+ }
+ else {
+ deps |= 1u << (uint32_t)dep;
+ }
+ }
+ return deps;
+}
+
+void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name)
+{
+ int index = -1;
+ for (int i = 0; i < MAX_LIB; i++) {
+ if (lib->libs[i] == NULL) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index > -1) {
+ lib->libs[index] = lib_code;
+ BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME);
+ }
+ else {
+ printf("Error: Too many libraries. Cannot add %s.\n", lib_name);
+ BLI_assert(0);
+ }
+
+ lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code);
+}
+
+/* Return an allocN'ed string containing the shader code with its dependencies prepended.
+ * Caller must free the string with MEM_freeN after use. */
+char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code)
+{
+ uint32_t deps = drw_shader_dependencies_get(lib, shader_code);
+
+ DynStr *ds = BLI_dynstr_new();
+ /* Add all dependencies recursively. */
+ for (int i = MAX_LIB - 1; i > -1; i--) {
+ if (lib->libs[i] && (deps & (1u << (uint32_t)i))) {
+ deps |= lib->libs_deps[i];
+ }
+ }
+ /* Concatenate all needed libs into one string. */
+ for (int i = 0; i < MAX_LIB; i++) {
+ if (deps & 1u) {
+ BLI_dynstr_append(ds, lib->libs[i]);
+ }
+ deps = deps >> 1;
+ }
+
+ BLI_dynstr_append(ds, shader_code);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c
index 373810b2f7f..3f11fe9d11e 100644
--- a/source/blender/draw/intern/draw_manager_texture.c
+++ b/source/blender/draw/intern/draw_manager_texture.c
@@ -123,6 +123,15 @@ GPUTexture *DRW_texture_create_cube(int w,
return tex;
}
+GPUTexture *DRW_texture_create_cube_array(
+ int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_cube_array(w, d, format, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
GPUTexture *DRW_texture_pool_query_2d(int w,
int h,
eGPUTextureFormat format,
@@ -134,6 +143,13 @@ GPUTexture *DRW_texture_pool_query_2d(int w,
return tex;
}
+GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format,
+ DrawEngineType *engine_type)
+{
+ const float *size = DRW_viewport_size_get();
+ return DRW_texture_pool_query_2d((int)size[0], (int)size[1], format, engine_type);
+}
+
void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex,
eGPUTextureFormat format,
DRWTextureFlag flags)
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index dcf0377ffc0..4b0a4bcf46b 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1790,81 +1790,63 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
bDopeSheet *ads = ac->ads;
size_t items = 0;
- if (ads->filterflag & ADS_FILTER_GP_3DONLY) {
- Scene *scene = (Scene *)ads->source;
- ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
- Base *base;
-
- /* Active scene's GPencil block first - No parent item needed... */
- if (scene->gpd) {
- items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
- }
-
- /* Objects in the scene */
- for (base = view_layer->object_bases.first; base; base = base->next) {
- /* Only consider this object if it has got some GP data (saving on all the other tests) */
- if (base->object && (base->object->type == OB_GPENCIL)) {
- Object *ob = base->object;
-
- /* firstly, check if object can be included, by the following factors:
- * - if only visible, must check for layer and also viewport visibility
- * --> while tools may demand only visible, user setting takes priority
- * as user option controls whether sets of channels get included while
- * tool-flag takes into account collapsed/open channels too
- * - if only selected, must check if object is selected
- * - there must be animation data to edit (this is done recursively as we
- * try to add the channels)
- */
- if ((filter_mode & ANIMFILTER_DATA_VISIBLE) &&
- !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
- /* Layer visibility - we check both object and base,
- * since these may not be in sync yet. */
- if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
- continue;
- }
-
- /* outliner restrict-flag */
- if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
- continue;
- }
+ Scene *scene = (Scene *)ads->source;
+ ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
+ Base *base;
+
+ /* Active scene's GPencil block first - No parent item needed... */
+ if (scene->gpd) {
+ items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
+ }
+
+ /* Objects in the scene */
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ /* Only consider this object if it has got some GP data (saving on all the other tests) */
+ if (base->object && (base->object->type == OB_GPENCIL)) {
+ Object *ob = base->object;
+
+ /* firstly, check if object can be included, by the following factors:
+ * - if only visible, must check for layer and also viewport visibility
+ * --> while tools may demand only visible, user setting takes priority
+ * as user option controls whether sets of channels get included while
+ * tool-flag takes into account collapsed/open channels too
+ * - if only selected, must check if object is selected
+ * - there must be animation data to edit (this is done recursively as we
+ * try to add the channels)
+ */
+ if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+ /* Layer visibility - we check both object and base,
+ * since these may not be in sync yet. */
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
+ continue;
}
- /* check selection and object type filters only for Object mode */
- if (ob->mode == OB_MODE_OBJECT) {
- if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
- /* only selected should be shown */
- continue;
- }
- }
- /* check if object belongs to the filtering group if option to filter
- * objects by the grouped status is on
- * - used to ease the process of doing multiple-character choreographies
- */
- if (ads->filter_grp != NULL) {
- if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) {
- continue;
- }
+ /* outliner restrict-flag */
+ if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
+ continue;
}
-
- /* finally, include this object's grease pencil data-block. */
- /* XXX: Should we store these under expanders per item? */
- items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
}
- }
- }
- else {
- bGPdata *gpd;
- /* Grab all Grease Pencil data-blocks directly from main,
- * but only those that seem to be useful somewhere */
- for (gpd = ac->bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- /* only show if gpd is used by something... */
- if (ID_REAL_USERS(gpd) < 1) {
- continue;
+ /* check selection and object type filters only for Object mode */
+ if (ob->mode == OB_MODE_OBJECT) {
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
+ /* only selected should be shown */
+ continue;
+ }
+ }
+ /* check if object belongs to the filtering group if option to filter
+ * objects by the grouped status is on
+ * - used to ease the process of doing multiple-character choreographies
+ */
+ if (ads->filter_grp != NULL) {
+ if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) {
+ continue;
+ }
}
- /* add GP frames from this data-block. */
- items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
+ /* finally, include this object's grease pencil data-block. */
+ /* XXX: Should we store these under expanders per item? */
+ items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
}
}
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index 5b729c856c0..f631d08f3e4 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -177,8 +177,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
icon = RNA_struct_ui_icon(ptr.type);
/* valid path - remove the invalid tag since we now know how to use it saving
- * users manual effort to reenable using "Revive Disabled FCurves" [#29629]
- */
+ * users manual effort to re-enable using "Revive Disabled FCurves" T29629. */
fcu->flag &= ~FCURVE_DISABLED;
}
else {
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 0f288c0d8b8..47eb09cdf3d 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -1461,6 +1461,13 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons
EditBone *ebone_act = CTX_data_active_bone(C);
const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name);
+
+ /* This will mostly happen for corner cases where the user tried to access this
+ * before having any valid pose data for the armature. */
+ if (pchan_active == NULL) {
+ return;
+ }
+
const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index d8cd4d20579..f7d22223b55 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -119,21 +119,25 @@ static void move_geom_draw(const wmGizmo *gz,
immUniformColor4fv(color);
+ /* Use the final scale as a radius if it's not already applied to the final matrix. */
+ const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f;
+
if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) {
if (filled) {
- imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
+ imm_draw_circle_fill_2d(pos, 0, 0, radius, DIAL_RESOLUTION);
}
else {
- imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
+ imm_draw_circle_wire_2d(pos, 0, 0, radius, DIAL_RESOLUTION);
}
}
else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) {
+ const float radius_diag = M_SQRT1_2 * radius;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, 1.0f, 1.0f);
- immVertex2f(pos, -1.0f, -1.0f);
+ immVertex2f(pos, radius_diag, radius_diag);
+ immVertex2f(pos, -radius_diag, -radius_diag);
- immVertex2f(pos, -1.0f, 1.0f);
- immVertex2f(pos, 1.0f, -1.0f);
+ immVertex2f(pos, -radius_diag, radius_diag);
+ immVertex2f(pos, radius_diag, -radius_diag);
immEnd();
}
else {
@@ -260,6 +264,9 @@ static int gizmo_move_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init);
+ if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) {
+ mul_v2_fl(prop_delta, gz->scale_final);
+ }
prop_delta[2] = 0.0f;
}
@@ -394,8 +401,10 @@ static int gizmo_move_test_select(bContext *C, wmGizmo *gz, const int mval[2])
return -1;
}
- /* The 'gz->scale_final' is already applied when projecting. */
- if (len_squared_v2(point_local) < 1.0f) {
+ /* The 'gz->scale_final' is already applied to the projection
+ * when #WM_GIZMO_DRAW_NO_SCALE isn't set. */
+ const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f;
+ if (len_squared_v2(point_local) < radius) {
return 0;
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 56351fbfb9a..46788eba370 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -3280,8 +3280,10 @@ static void gpencil_add_guide_points(const tGPsdata *p,
}
}
-/* Add fake points for missing mouse movements when the artist draw very fast creating an arc
- * with the vertice in the midle of the segment and using the angle of the previous segment. */
+/**
+ * Add fake points for missing mouse movements when the artist draw very fast creating an arc
+ * with the vertex in the middle of the segment and using the angle of the previous segment.
+ */
static void gpencil_add_fake_points(const wmEvent *event, tGPsdata *p)
{
Brush *brush = p->brush;
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index adc009efd16..5db331280f8 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -231,8 +231,8 @@ static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene)
static bool gp_brush_invert_check(tGP_BrushEditData *gso)
{
/* The basic setting is the brush's setting (from the panel) */
- bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0);
-
+ bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0) ||
+ (gso->brush->gpencil_settings->sculpt_flag & BRUSH_DIR_IN);
/* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
if (gso->flag & GP_SCULPT_FLAG_INVERT) {
invert ^= true;
@@ -1744,7 +1744,8 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
/* compute multiframe falloff factor */
if (gso->use_multiframe_falloff) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ /* Falloff depends on distance to active frame
+ * (relative to the overall frame range). */
gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
}
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 5b5a306aa25..c730d1b493e 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -1099,10 +1099,9 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* Always do active frame; Otherwise, only include selected frames */
if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- /* compute multiframe falloff factor */
+ /* Compute multi-frame falloff factor. */
if (gso->use_multiframe_falloff) {
- /* Faloff depends on distance to active frame (relative to the overall frame range)
- */
+ /* Falloff depends on distance to active frame (relative to the overall frame range) */
gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
}
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 6b337afa559..c519129cdf7 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -110,7 +110,7 @@ typedef struct tGP_BrushWeightpaintData {
/* Start of new paint */
bool first;
- /* Is multiframe editing enabled, and are we using falloff for that? */
+ /* Is multi-frame editing enabled, and are we using falloff for that? */
bool is_multiframe;
bool use_multiframe_falloff;
@@ -127,10 +127,10 @@ typedef struct tGP_BrushWeightpaintData {
/* - Effect 2D vector */
float dvec[2];
- /* - multiframe falloff factor */
+ /* - multi-frame falloff factor. */
float mf_falloff;
- /* brush geometry (bounding box) */
+ /* brush geometry (bounding box). */
rcti brush_rect;
/* Temp data to save selected points */
@@ -206,7 +206,7 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu
float brush_fallof = BKE_brush_curve_strength(brush, distance, (float)radius);
influence *= brush_fallof;
- /* apply multiframe falloff */
+ /* apply multi-frame falloff */
influence *= gso->mf_falloff;
/* return influence */
@@ -585,7 +585,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai
/* Active Frame or MultiFrame? */
if (gso->is_multiframe) {
- /* init multiframe falloff options */
+ /* init multi-frame falloff options */
int f_init = 0;
int f_end = 0;
@@ -596,10 +596,10 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* Always do active frame; Otherwise, only include selected frames */
if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- /* compute multiframe falloff factor */
+ /* Compute multi-frame falloff factor. */
if (gso->use_multiframe_falloff) {
- /* Faloff depends on distance to active frame (relative to the overall frame range)
- */
+ /* Falloff depends on distance to active frame
+ * (relative to the overall frame range). */
gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
}
@@ -656,7 +656,7 @@ static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *
gso->brush_rect.xmax = mouse[0] + radius;
gso->brush_rect.ymax = mouse[1] + radius;
- /* Calc 2D direction vector and relative angle. */
+ /* Calculate 2D direction vector and relative angle. */
brush_calc_dvec_2d(gso);
changed = gp_weightpaint_brush_apply_to_layers(C, gso);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 277f330ad50..dba95c5106e 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2382,6 +2382,9 @@ struct ID *UI_context_active_but_get_tab_ID(struct bContext *C);
uiBut *UI_region_active_but_get(struct ARegion *region);
uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct rcti *isect);
+uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
+ const int xy[2],
+ bool only_clip);
/* uiFontStyle.align */
typedef enum eFontStyle_Align {
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 6da9bacd865..833631f871d 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -8268,6 +8268,13 @@ uiBut *UI_region_but_find_rect_over(const ARegion *region, const rcti *rect_px)
return ui_but_find_rect_over(region, rect_px);
}
+uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
+ const int xy[2],
+ bool only_clip)
+{
+ return ui_block_find_mouse_over_ex(region, xy[0], xy[1], only_clip);
+}
+
/**
* Version of #UI_context_active_but_get that also returns RNA property info.
* Helper function for insert keyframe, reset to default, etc operators.
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 24977848ae4..a2e239884a3 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -951,6 +951,14 @@ bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+uiBlock *ui_block_find_mouse_over_ex(const struct ARegion *region,
+ const int x,
+ const int y,
+ bool only_clip);
+uiBlock *ui_block_find_mouse_over(const struct ARegion *region,
+ const struct wmEvent *event,
+ bool only_clip);
+
uiBut *ui_region_find_first_but_test_flag(struct ARegion *region,
int flag_include,
int flag_exclude);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 03434b12ddb..52488027662 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -505,6 +505,40 @@ bool UI_block_can_add_separator(const uiBlock *block)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Block (#uiBlock) Spatial
+ * \{ */
+
+uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
+ const int x,
+ const int y,
+ bool only_clip)
+{
+ if (!ui_region_contains_point_px(region, x, y)) {
+ return NULL;
+ }
+ for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ if (only_clip) {
+ if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) {
+ continue;
+ }
+ }
+ float mx = x, my = y;
+ ui_window_to_block_fl(region, block, &mx, &my);
+ if (BLI_rctf_isect_pt(&block->rect, mx, my)) {
+ return block;
+ }
+ }
+ return NULL;
+}
+
+uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, bool only_clip)
+{
+ return ui_block_find_mouse_over_ex(region, event->x, event->y, only_clip);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Region (#ARegion) State
* \{ */
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index d688e2cb658..1c4bc33240a 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -349,7 +349,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_begin(ob, "mask slice");
/* TODO: The ideal functionality would be to preserve the current face sets and add a new one
- * for the new triangles, but this datalayer needs to be rebuild in order to make sculpt mode
+ * for the new triangles, but this data-layer needs to be rebuild in order to make sculpt mode
* not crash when modifying the geometry. */
CustomData_free_layers(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly);
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index dc825871bb7..8f31fa0a1fa 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -943,7 +943,7 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob,
}
/**
- * Wrapper for objectmode/editmode.
+ * Wrapper for object-mode/edit-mode.
*
* call #BM_mesh_elem_table_ensure first for editmesh.
*/
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 94e210b7243..95d044554f1 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -890,14 +890,14 @@ enum {
static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
{
- if (scene->eevee.light_cache != NULL) {
+ if (scene->eevee.light_cache_data != NULL) {
int subset = RNA_enum_get(op->ptr, "subset");
switch (subset) {
case LIGHTCACHE_SUBSET_ALL:
- scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE;
+ scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE;
break;
case LIGHTCACHE_SUBSET_CUBE:
- scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE;
+ scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE;
break;
case LIGHTCACHE_SUBSET_DIRTY:
/* Leave tag untouched. */
@@ -1046,7 +1046,7 @@ static bool light_cache_free_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- return scene->eevee.light_cache;
+ return scene->eevee.light_cache_data;
}
static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1057,12 +1057,12 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
wmWindowManager *wm = CTX_wm_manager(C);
WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE);
- if (!scene->eevee.light_cache) {
+ if (!scene->eevee.light_cache_data) {
return OPERATOR_CANCELLED;
}
- EEVEE_lightcache_free(scene->eevee.light_cache);
- scene->eevee.light_cache = NULL;
+ EEVEE_lightcache_free(scene->eevee.light_cache_data);
+ scene->eevee.light_cache_data = NULL;
EEVEE_lightcache_info_update(&scene->eevee);
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index ad940a8e87d..114cb54636a 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -182,6 +182,8 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep
}
}
+ BKE_scene_free_view_layer_depsgraph(scene, layer);
+
BKE_view_layer_free(layer);
DEG_id_tag_update(&scene->id, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 6fe1ba0b817..fed3c2f03a4 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -377,17 +377,6 @@ static void PALETTE_OT_extract_from_image(wmOperatorType *ot)
}
/* Sort Palette color by Hue and Saturation. */
-static bool palette_sort_poll(bContext *C)
-{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Palette *palette = paint->palette;
- if (palette) {
- return true;
- }
-
- return false;
-}
-
static int palette_sort_exec(bContext *C, wmOperator *op)
{
const int type = RNA_enum_get(op->ptr, "type");
@@ -477,7 +466,7 @@ static void PALETTE_OT_sort(wmOperatorType *ot)
/* api callbacks */
ot->exec = palette_sort_exec;
- ot->poll = palette_sort_poll;
+ ot->poll = palette_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -522,7 +511,7 @@ static void PALETTE_OT_color_move(wmOperatorType *ot)
/* api callbacks */
ot->exec = palette_color_move_exec;
- ot->poll = palette_sort_poll;
+ ot->poll = palette_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -531,17 +520,6 @@ static void PALETTE_OT_color_move(wmOperatorType *ot)
}
/* Join Palette swatches. */
-static bool palette_join_poll(bContext *C)
-{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Palette *palette = paint->palette;
- if (palette) {
- return true;
- }
-
- return false;
-}
-
static int palette_join_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -599,7 +577,7 @@ static void PALETTE_OT_join(wmOperatorType *ot)
/* api callbacks */
ot->exec = palette_join_exec;
- ot->poll = palette_join_poll;
+ ot->poll = palette_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b25cdbe39c1..5a830a90092 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -7030,7 +7030,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
if (cache->first_time ||
!((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) ||
- (brush->sculpt_tool == SCULPT_TOOL_ROTATE))) {
+ (brush->sculpt_tool == SCULPT_TOOL_ROTATE) ||
+ (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
+ brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) {
RNA_float_get_array(ptr, "location", cache->true_location);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index 038d0e5a08c..f2671b66f7f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -58,7 +58,6 @@
#include <math.h>
#include <stdlib.h>
-
typedef struct MultiplaneScrapeSampleData {
float area_cos[2][3];
float area_nos[2][3];
@@ -223,7 +222,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-
/* Public functions. */
/* Main Brush Function. */
@@ -400,9 +398,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
}
void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
- SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha)
+ SculptSession *ss,
+ const float outline_col[3],
+ const float outline_alpha)
{
float local_mat_inv[4][4];
invert_m4_m4(local_mat_inv, ss->cache->stroke_local_mat);
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 7e32c3d2b5f..ee1496c96bb 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -38,14 +38,14 @@
#include "../space_info/textview.h"
-static int console_line_data(struct TextViewContext *tvc,
- uchar fg[4],
- uchar UNUSED(bg[4]),
- int *UNUSED(icon),
- uchar UNUSED(icon_fg[4]),
- uchar UNUSED(icon_bg[4]))
+static enum eTextViewContext_LineFlag console_line_data(TextViewContext *tvc,
+ uchar fg[4],
+ uchar UNUSED(bg[4]),
+ int *UNUSED(icon),
+ uchar UNUSED(icon_fg[4]),
+ uchar UNUSED(icon_bg[4]))
{
- ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter;
+ const ConsoleLine *cl_iter = tvc->iter;
int fg_id = TH_TEXT;
switch (cl_iter->type) {
@@ -67,7 +67,7 @@ static int console_line_data(struct TextViewContext *tvc,
return TVC_LINE_FG;
}
-void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy)
+void console_scrollback_prompt_begin(SpaceConsole *sc, ConsoleLine *cl_dummy)
{
/* fake the edit line being in the scroll buffer */
ConsoleLine *cl = sc->history.last;
@@ -81,7 +81,7 @@ void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_du
memcpy(cl_dummy->line + prompt_len, cl->line, cl->len + 1);
BLI_addtail(&sc->scrollback, cl_dummy);
}
-void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dummy)
+void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy)
{
MEM_freeN(cl_dummy->line);
BLI_remlink(&sc->scrollback, cl_dummy);
@@ -112,14 +112,13 @@ static int console_textview_step(TextViewContext *tvc)
return ((tvc->iter = (void *)((Link *)tvc->iter)->prev) != NULL);
}
-static int console_textview_line_get(struct TextViewContext *tvc, const char **line, int *len)
+static void console_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len)
{
- ConsoleLine *cl = (ConsoleLine *)tvc->iter;
- *line = cl->line;
- *len = cl->len;
+ const ConsoleLine *cl = tvc->iter;
+ *r_line = cl->line;
+ *r_len = cl->len;
// printf("'%s' %d\n", *line, cl->len);
BLI_assert(cl->line[cl->len] == '\0' && (cl->len == 0 || cl->line[cl->len - 1] != '\0'));
- return 1;
}
static void console_cursor_wrap_offset(
@@ -144,7 +143,7 @@ static void console_cursor_wrap_offset(
return;
}
-static void console_textview_draw_cursor(struct TextViewContext *tvc,
+static void console_textview_draw_cursor(TextViewContext *tvc,
int cwidth,
int columns,
int descender)
@@ -201,7 +200,7 @@ static void console_textview_draw_rect_calc(const ARegion *region,
r_draw_rect_outer->ymax = region->winy;
}
-static int console_textview_main__internal(struct SpaceConsole *sc,
+static int console_textview_main__internal(SpaceConsole *sc,
const ARegion *region,
const bool do_draw,
const int mval[2],
@@ -243,19 +242,19 @@ static int console_textview_main__internal(struct SpaceConsole *sc,
return ret;
}
-void console_textview_main(struct SpaceConsole *sc, const ARegion *region)
+void console_textview_main(SpaceConsole *sc, const ARegion *region)
{
const int mval[2] = {INT_MAX, INT_MAX};
console_textview_main__internal(sc, region, true, mval, NULL, NULL);
}
-int console_textview_height(struct SpaceConsole *sc, const ARegion *region)
+int console_textview_height(SpaceConsole *sc, const ARegion *region)
{
const int mval[2] = {INT_MAX, INT_MAX};
return console_textview_main__internal(sc, region, false, mval, NULL, NULL);
}
-int console_char_pick(struct SpaceConsole *sc, const ARegion *region, const int mval[2])
+int console_char_pick(SpaceConsole *sc, const ARegion *region, const int mval[2])
{
int r_mval_pick_offset = 0;
void *mval_pick_item = NULL;
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 4d5f59cdb7c..0a5ca81484c 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -39,14 +39,14 @@
#include "textview.h"
#include "GPU_framebuffer.h"
-static int report_line_data(struct TextViewContext *tvc,
- uchar fg[4],
- uchar bg[4],
- int *icon,
- uchar icon_fg[4],
- uchar icon_bg[4])
+static enum eTextViewContext_LineFlag report_line_data(TextViewContext *tvc,
+ uchar fg[4],
+ uchar bg[4],
+ int *r_icon,
+ uchar r_icon_fg[4],
+ uchar r_icon_bg[4])
{
- Report *report = (Report *)tvc->iter;
+ const Report *report = tvc->iter;
/* Same text color no matter what type of report. */
UI_GetThemeColor4ubv((report->flag & SELECT) ? TH_INFO_SELECTED_TEXT : TH_TEXT, fg);
@@ -64,35 +64,35 @@ static int report_line_data(struct TextViewContext *tvc,
if (report->type & RPT_ERROR_ALL) {
icon_fg_id = TH_INFO_ERROR_TEXT;
icon_bg_id = TH_INFO_ERROR;
- *icon = ICON_CANCEL;
+ *r_icon = ICON_CANCEL;
}
else if (report->type & RPT_WARNING_ALL) {
icon_fg_id = TH_INFO_WARNING_TEXT;
icon_bg_id = TH_INFO_WARNING;
- *icon = ICON_ERROR;
+ *r_icon = ICON_ERROR;
}
else if (report->type & RPT_INFO_ALL) {
icon_fg_id = TH_INFO_INFO_TEXT;
icon_bg_id = TH_INFO_INFO;
- *icon = ICON_INFO;
+ *r_icon = ICON_INFO;
}
else if (report->type & RPT_DEBUG_ALL) {
icon_fg_id = TH_INFO_DEBUG_TEXT;
icon_bg_id = TH_INFO_DEBUG;
- *icon = ICON_SYSTEM;
+ *r_icon = ICON_SYSTEM;
}
else if (report->type & RPT_PROPERTY) {
icon_fg_id = TH_INFO_PROPERTY_TEXT;
icon_bg_id = TH_INFO_PROPERTY;
- *icon = ICON_OPTIONS;
+ *r_icon = ICON_OPTIONS;
}
else if (report->type & RPT_OPERATOR) {
icon_fg_id = TH_INFO_OPERATOR_TEXT;
icon_bg_id = TH_INFO_OPERATOR;
- *icon = ICON_CHECKMARK;
+ *r_icon = ICON_CHECKMARK;
}
else {
- *icon = ICON_NONE;
+ *r_icon = ICON_NONE;
}
if (report->flag & SELECT) {
@@ -100,9 +100,9 @@ static int report_line_data(struct TextViewContext *tvc,
icon_bg_id = TH_INFO_SELECTED_TEXT;
}
- if (*icon != ICON_NONE) {
- UI_GetThemeColor4ubv(icon_fg_id, icon_fg);
- UI_GetThemeColor4ubv(icon_bg_id, icon_bg);
+ if (*r_icon != ICON_NONE) {
+ UI_GetThemeColor4ubv(icon_fg_id, r_icon_fg);
+ UI_GetThemeColor4ubv(icon_bg_id, r_icon_bg);
return TVC_LINE_FG | TVC_LINE_BG | TVC_LINE_ICON | TVC_LINE_ICON_FG | TVC_LINE_ICON_BG;
}
else {
@@ -113,7 +113,7 @@ static int report_line_data(struct TextViewContext *tvc,
/* reports! */
static void report_textview_init__internal(TextViewContext *tvc)
{
- Report *report = (Report *)tvc->iter;
+ const Report *report = tvc->iter;
const char *str = report->message;
const char *next_str = strchr(str + tvc->iter_char, '\n');
@@ -127,9 +127,9 @@ static void report_textview_init__internal(TextViewContext *tvc)
static int report_textview_skip__internal(TextViewContext *tvc)
{
- SpaceInfo *sinfo = (SpaceInfo *)tvc->arg1;
+ const SpaceInfo *sinfo = tvc->arg1;
const int report_mask = info_report_mask(sinfo);
- while (tvc->iter && (((Report *)tvc->iter)->type & report_mask) == 0) {
+ while (tvc->iter && (((const Report *)tvc->iter)->type & report_mask) == 0) {
tvc->iter = (void *)((Link *)tvc->iter)->prev;
}
return (tvc->iter != NULL);
@@ -137,7 +137,7 @@ static int report_textview_skip__internal(TextViewContext *tvc)
static int report_textview_begin(TextViewContext *tvc)
{
- ReportList *reports = (ReportList *)tvc->arg2;
+ const ReportList *reports = tvc->arg2;
tvc->lheight = 14 * UI_DPI_FAC;
tvc->sel_start = 0;
@@ -170,7 +170,7 @@ static void report_textview_end(TextViewContext *UNUSED(tvc))
static int report_textview_step(TextViewContext *tvc)
{
/* simple case, but no newline support */
- Report *report = (Report *)tvc->iter;
+ const Report *report = tvc->iter;
if (report->len <= tvc->iter_char_next) {
tvc->iter = (void *)((Link *)tvc->iter)->prev;
@@ -195,12 +195,11 @@ static int report_textview_step(TextViewContext *tvc)
}
}
-static int report_textview_line_get(struct TextViewContext *tvc, const char **line, int *len)
+static void report_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len)
{
- Report *report = (Report *)tvc->iter;
- *line = report->message + tvc->iter_char;
- *len = tvc->iter_char_next - tvc->iter_char;
- return 1;
+ const Report *report = tvc->iter;
+ *r_line = report->message + tvc->iter_char;
+ *r_len = tvc->iter_char_next - tvc->iter_char;
}
static void info_textview_draw_rect_calc(const ARegion *region,
@@ -220,9 +219,9 @@ static void info_textview_draw_rect_calc(const ARegion *region,
r_draw_rect_outer->ymax = region->winy;
}
-static int info_textview_main__internal(struct SpaceInfo *sinfo,
+static int info_textview_main__internal(const SpaceInfo *sinfo,
const ARegion *region,
- ReportList *reports,
+ const ReportList *reports,
const bool do_draw,
const int mval[2],
void **r_mval_pick_item,
@@ -259,9 +258,9 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo,
return ret;
}
-void *info_text_pick(struct SpaceInfo *sinfo,
+void *info_text_pick(const SpaceInfo *sinfo,
const ARegion *region,
- ReportList *reports,
+ const ReportList *reports,
int mval_y)
{
void *mval_pick_item = NULL;
@@ -271,13 +270,13 @@ void *info_text_pick(struct SpaceInfo *sinfo,
return (void *)mval_pick_item;
}
-int info_textview_height(struct SpaceInfo *sinfo, const ARegion *region, ReportList *reports)
+int info_textview_height(const SpaceInfo *sinfo, const ARegion *region, const ReportList *reports)
{
int mval[2] = {INT_MAX, INT_MAX};
return info_textview_main__internal(sinfo, region, reports, false, mval, NULL, NULL);
}
-void info_textview_main(struct SpaceInfo *sinfo, const ARegion *region, ReportList *reports)
+void info_textview_main(const SpaceInfo *sinfo, const ARegion *region, const ReportList *reports)
{
int mval[2] = {INT_MAX, INT_MAX};
info_textview_main__internal(sinfo, region, reports, true, mval, NULL, NULL);
diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h
index 443a1659690..79bfb1fa047 100644
--- a/source/blender/editors/space_info/info_intern.h
+++ b/source/blender/editors/space_info/info_intern.h
@@ -45,19 +45,19 @@ void FILE_OT_find_missing_files(struct wmOperatorType *ot);
void INFO_OT_reports_display_update(struct wmOperatorType *ot);
/* info_draw.c */
-void *info_text_pick(struct SpaceInfo *sinfo,
+void *info_text_pick(const struct SpaceInfo *sinfo,
const struct ARegion *region,
- ReportList *reports,
+ const struct ReportList *reports,
int mouse_y);
-int info_textview_height(struct SpaceInfo *sinfo,
+int info_textview_height(const struct SpaceInfo *sinfo,
const struct ARegion *region,
- struct ReportList *reports);
-void info_textview_main(struct SpaceInfo *sinfo,
+ const struct ReportList *reports);
+void info_textview_main(const struct SpaceInfo *sinfo,
const struct ARegion *region,
- struct ReportList *reports);
+ const struct ReportList *reports);
/* info_report.c */
-int info_report_mask(struct SpaceInfo *sinfo);
+int info_report_mask(const struct SpaceInfo *sinfo);
void INFO_OT_select_pick(struct wmOperatorType *ot); /* report selection */
void INFO_OT_select_all(struct wmOperatorType *ot);
void INFO_OT_select_box(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 1b01ac95866..303e2bbaec9 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -72,7 +72,7 @@ static void reports_select_all(ReportList *reports, int report_mask, int action)
}
}
-int info_report_mask(SpaceInfo *UNUSED(sinfo))
+int info_report_mask(const SpaceInfo *UNUSED(sinfo))
{
#if 0
int report_mask = 0;
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index a33ed91570d..54b7c477791 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -21,6 +21,14 @@
#ifndef __TEXTVIEW_H__
#define __TEXTVIEW_H__
+enum eTextViewContext_LineFlag {
+ TVC_LINE_FG = (1 << 0),
+ TVC_LINE_BG = (1 << 1),
+ TVC_LINE_ICON = (1 << 2),
+ TVC_LINE_ICON_FG = (1 << 3),
+ TVC_LINE_ICON_BG = (1 << 4)
+};
+
typedef struct TextViewContext {
/** Font size scaled by the interface size. */
int lheight;
@@ -40,22 +48,22 @@ typedef struct TextViewContext {
/* callbacks */
int (*begin)(struct TextViewContext *tvc);
void (*end)(struct TextViewContext *tvc);
- void *arg1;
- void *arg2;
+ const void *arg1;
+ const void *arg2;
/* iterator */
int (*step)(struct TextViewContext *tvc);
- int (*line_get)(struct TextViewContext *tvc, const char **, int *);
- int (*line_data)(struct TextViewContext *tvc,
- unsigned char fg[4],
- unsigned char bg[4],
- int *icon,
- unsigned char icon_fg[4],
- unsigned char icon_bg[4]);
+ void (*line_get)(struct TextViewContext *tvc, const char **r_line, int *r_len);
+ enum eTextViewContext_LineFlag (*line_data)(struct TextViewContext *tvc,
+ uchar fg[4],
+ uchar bg[4],
+ int *r_icon,
+ uchar r_icon_fg[4],
+ uchar r_icon_bg[4]);
void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender);
/* constant theme colors */
void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]);
- void *iter;
+ const void *iter;
int iter_index;
/** Char index, used for multi-line report display. */
int iter_char;
@@ -72,12 +80,4 @@ int textview_draw(struct TextViewContext *tvc,
void **r_mval_pick_item,
int *r_mval_pick_offset);
-enum {
- TVC_LINE_FG = (1 << 0),
- TVC_LINE_BG = (1 << 1),
- TVC_LINE_ICON = (1 << 2),
- TVC_LINE_ICON_FG = (1 << 3),
- TVC_LINE_ICON_BG = (1 << 4)
-};
-
#endif /* __TEXTVIEW_H__ */
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index d3c7374e782..951c26b69e0 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -981,6 +981,7 @@ void ED_spacetype_node(void)
art->listener = node_region_listener;
art->cursor = node_cursor;
art->event_cursor = true;
+ art->clip_gizmo_events_by_ui = true;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 8c884783913..8ec7d5a166b 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1422,7 +1422,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa))
{
Scene *scene = CTX_data_scene(C);
- LightCache *lcache = scene->eevee.light_cache;
+ LightCache *lcache = scene->eevee.light_cache_data;
if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) {
lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bd92193206f..bfbc9b6825b 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1987,7 +1987,7 @@ static bool ed_object_select_pick(bContext *C,
is_obedit = (vc.obedit != NULL);
if (object) {
- /* signal for view3d_opengl_select to skip editmode objects */
+ /* Signal for #view3d_opengl_select to skip edit-mode objects. */
vc.obedit = NULL;
}
@@ -2003,7 +2003,7 @@ static bool ed_object_select_pick(bContext *C,
/* This block uses the control key to make the object selected
* by its center point rather than its contents */
- /* in editmode do not activate */
+ /* In edit-mode do not activate. */
if (obcenter) {
/* note; shift+alt goes to group-flush-selecting */
@@ -2337,11 +2337,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
bool toggle = RNA_boolean_get(op->ptr, "toggle");
bool center = RNA_boolean_get(op->ptr, "center");
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
- /* only force object select for editmode to support vertex parenting,
- * or paint-select to allow pose bone select with vert/face select */
+ /* Only force object select for edit-mode to support vertex parenting,
+ * or paint-select to allow pose bone select with vert/face select. */
bool object = (RNA_boolean_get(op->ptr, "object") &&
(obedit || BKE_paint_select_elem_test(obact) ||
- /* so its possible to select bones in weightpaint mode (LMB select) */
+ /* so its possible to select bones in weight-paint mode (LMB select) */
(obact && (obact->mode & OB_MODE_WEIGHT_PAINT) &&
BKE_object_pose_armature_get(obact))));
@@ -2358,8 +2358,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
obact = NULL;
/* ack, this is incorrect but to do this correctly we would need an
- * alternative editmode/objectmode keymap, this copies the functionality
- * from 2.4x where Ctrl+Select in editmode does object select only */
+ * alternative edit-mode/object-mode keymap, this copies the functionality
+ * from 2.4x where Ctrl+Select in edit-mode does object select only. */
center = false;
}
@@ -2493,12 +2493,12 @@ void VIEW3D_OT_select(wmOperatorType *ot)
"center",
0,
"Center",
- "Use the object center when selecting, in editmode used to extend object selection");
+ "Use the object center when selecting, in edit-mode used to extend object selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)");
+ prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit-mode only)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_int_vector(ot->srna,
@@ -3286,7 +3286,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
}
FOREACH_OBJECT_IN_MODE_END;
}
- else { /* no editmode, unified for bones and objects */
+ else { /* No edit-mode, unified for bones and objects. */
if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
/* XXX, this is not selection, could be it's own operator. */
changed_multi = ED_sculpt_mask_box_select(
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 17e69ff38b8..efd7879c8b2 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -228,10 +228,11 @@ void createTransGPencil(bContext *C, TransInfo *t)
for (gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- /* if multiframe and falloff, recalculate and save value */
+ /* If multi-frame and falloff, recalculate and save value. */
float falloff = 1.0f; /* by default no falloff */
if ((is_multiedit) && (use_multiframe_falloff)) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ /* Falloff depends on distance to active frame
+ * (relative to the overall frame range). */
falloff = BKE_gpencil_multiframe_falloff_calc(
gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index bb4d50fcf54..716df24f195 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1102,7 +1102,7 @@ static void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED);
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 752d482fae2..2f305989f82 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -50,11 +50,9 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
copy_v3_v3(t->values_final, t->values);
- /*
- * OPTIMIZATION:
- * This still recalcs transformation on mouse move
- * while it should only recalc on constraint change
- * */
+ /* OPTIMIZATION:
+ * This still recalculates transformation on mouse move
+ * while it should only recalculate on constraint change. */
/* if an axis has been selected */
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 5ed27d9a648..f521fa3c702 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -95,18 +95,6 @@ void GPU_create_smoke_velocity(struct FluidModifierData *mmd);
/* Delayed free of OpenGL buffers by main thread */
void GPU_free_unused_buffers(struct Main *bmain);
-/* utilities */
-typedef enum eGPUAttrMask {
- GPU_DEPTH_BUFFER_BIT = (1 << 0),
- GPU_ENABLE_BIT = (1 << 1),
- GPU_SCISSOR_BIT = (1 << 2),
- GPU_VIEWPORT_BIT = (1 << 3),
- GPU_BLEND_BIT = (1 << 4),
-} eGPUAttrMask;
-
-void gpuPushAttr(eGPUAttrMask mask);
-void gpuPopAttr(void);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 245f7f47510..4ffe4a53a52 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -44,6 +44,7 @@ int GPU_max_ubo_size(void);
float GPU_max_line_width(void);
void GPU_get_dfdy_factors(float fac[2]);
bool GPU_arb_base_instance_is_supported(void);
+bool GPU_arb_texture_cube_map_array_is_supported(void);
bool GPU_mip_render_workaround(void);
bool GPU_depth_blitting_workaround(void);
bool GPU_unused_fb_slot_workaround(void);
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 37fe30bc96b..da00306bf9f 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -98,12 +98,9 @@ typedef enum eGPUBuiltin {
GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
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_TEMPERATURE = (1 << 18),
- GPU_BARYCENTRIC_TEXCO = (1 << 19),
- GPU_BARYCENTRIC_DIST = (1 << 20),
- GPU_WORLD_NORMAL = (1 << 21),
+ GPU_BARYCENTRIC_TEXCO = (1 << 16),
+ GPU_BARYCENTRIC_DIST = (1 << 17),
+ GPU_WORLD_NORMAL = (1 << 18),
} eGPUBuiltin;
typedef enum eGPUMatFlag {
@@ -145,6 +142,7 @@ GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iu
GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser);
GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer);
+GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name);
GPUNodeLink *GPU_builtin(eGPUBuiltin builtin);
bool GPU_link(GPUMaterial *mat, const char *name, ...);
@@ -178,7 +176,8 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct bNodeTree *ntree,
struct ListBase *gpumaterials,
const void *engine_type,
- int options,
+ const int options,
+ const bool is_volume_shader,
const char *vert_code,
const char *geom_code,
const char *frag_lib,
@@ -191,7 +190,6 @@ void GPU_materials_free(struct Main *bmain);
struct Scene *GPU_material_scene(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
-struct ListBase *GPU_material_get_inputs(GPUMaterial *material);
struct Material *GPU_material_get_material(GPUMaterial *material);
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
@@ -199,8 +197,10 @@ struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material);
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void);
-bool GPU_material_use_domain_surface(GPUMaterial *mat);
-bool GPU_material_use_domain_volume(GPUMaterial *mat);
+bool GPU_material_has_surface_output(GPUMaterial *mat);
+bool GPU_material_has_volume_output(GPUMaterial *mat);
+
+bool GPU_material_is_volume_shader(GPUMaterial *mat);
void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag);
bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag);
@@ -230,8 +230,16 @@ typedef struct GPUMaterialTexture {
int users;
} GPUMaterialTexture;
+typedef struct GPUMaterialVolumeGrid {
+ struct GPUMaterialVolumeGrid *next, *prev;
+ char *name;
+ char sampler_name[32]; /* Name of sampler in GLSL. */
+ int users;
+} GPUMaterialVolumeGrid;
+
ListBase GPU_material_attributes(GPUMaterial *material);
ListBase GPU_material_textures(GPUMaterial *material);
+ListBase GPU_material_volume_grids(GPUMaterial *material);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 894ef22e963..9ce91d31d69 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -65,6 +65,18 @@ void GPU_finish(void);
void GPU_logic_op_invert_set(bool enable);
+/* Attribute push & pop. */
+typedef enum eGPUAttrMask {
+ GPU_DEPTH_BUFFER_BIT = (1 << 0),
+ GPU_ENABLE_BIT = (1 << 1),
+ GPU_SCISSOR_BIT = (1 << 2),
+ GPU_VIEWPORT_BIT = (1 << 3),
+ GPU_BLEND_BIT = (1 << 4),
+} eGPUAttrMask;
+
+void gpuPushAttr(eGPUAttrMask mask);
+void gpuPopAttr(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 50b7c23059d..892452a2738 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -162,6 +162,12 @@ GPUTexture *GPU_texture_create_nD(int w,
int samples,
const bool can_rescale,
char err_out[256]);
+GPUTexture *GPU_texture_cube_create(int w,
+ int d,
+ const void *pixels,
+ eGPUTextureFormat tex_format,
+ eGPUDataFormat gpu_data_format,
+ char err_out[256]);
GPUTexture *GPU_texture_create_1d(int w,
eGPUTextureFormat data_type,
@@ -185,6 +191,9 @@ GPUTexture *GPU_texture_create_cube(int w,
eGPUTextureFormat data_type,
const float *pixels,
char err_out[256]);
+GPUTexture *GPU_texture_create_cube_array(
+ int w, int d, eGPUTextureFormat data_type, const float *pixels, char err_out[256]);
+
GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert);
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer);
@@ -238,6 +247,7 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat);
void GPU_texture_filters(GPUTexture *tex,
eGPUFilterFunction min_filter,
eGPUFilterFunction mag_filter);
+void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels);
void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment);
int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb);
@@ -251,6 +261,7 @@ void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h);
int GPU_texture_layers(const GPUTexture *tex);
eGPUTextureFormat GPU_texture_format(const GPUTexture *tex);
int GPU_texture_samples(const GPUTexture *tex);
+bool GPU_texture_array(const GPUTexture *tex);
bool GPU_texture_cube(const GPUTexture *tex);
bool GPU_texture_depth(const GPUTexture *tex);
bool GPU_texture_stencil(const GPUTexture *tex);
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 553ecb65529..bcaa95c2f59 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -269,15 +269,6 @@ static const char *gpu_builtin_name(eGPUBuiltin builtin)
else if (builtin == GPU_OBJECT_INFO) {
return "unfobjectinfo";
}
- else if (builtin == GPU_VOLUME_DENSITY) {
- return "sampdensity";
- }
- else if (builtin == GPU_VOLUME_FLAME) {
- return "sampflame";
- }
- else if (builtin == GPU_VOLUME_TEMPERATURE) {
- return "unftemperature";
- }
else if (builtin == GPU_BARYCENTRIC_TEXCO) {
return "unfbarycentrictex";
}
@@ -341,6 +332,11 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
}
}
+ /* Volume Grids */
+ for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) {
+ BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name);
+ }
+
/* Print other uniforms */
for (node = graph->nodes.first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
@@ -350,12 +346,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
builtins |= input->builtin;
name = gpu_builtin_name(input->builtin);
- if (BLI_str_startswith(name, "samp")) {
- if ((input->builtin == GPU_VOLUME_DENSITY) || (input->builtin == GPU_VOLUME_FLAME)) {
- BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name);
- }
- }
- else if (BLI_str_startswith(name, "unf")) {
+ if (BLI_str_startswith(name, "unf")) {
BLI_dynstr_appendf(ds, "uniform %s %s;\n", gpu_data_type_to_string(input->type), name);
}
else {
@@ -438,6 +429,9 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f
else if (input->source == GPU_SOURCE_TEX_TILED_MAPPING) {
BLI_dynstr_append(ds, input->texture->tiled_mapping_name);
}
+ else if (input->source == GPU_SOURCE_VOLUME_GRID) {
+ BLI_dynstr_append(ds, input->volume_grid->sampler_name);
+ }
else if (input->source == GPU_SOURCE_OUTPUT) {
codegen_convert_datatype(
ds, input->link->output->type, input->type, "tmp", input->link->output->id);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index d674f8600c2..33bc3ced5b2 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -861,6 +861,7 @@ static void gpu_texture_update_from_ibuf(
* available. It is also required when requesting the GPUTexture for a render result. */
GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, int textarget)
{
+#ifndef GPU_STANDALONE
if (ima == NULL) {
return NULL;
}
@@ -919,10 +920,13 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf,
GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
return *tex;
+#endif
+ return NULL;
}
GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, int textarget)
{
+#ifndef GPU_STANDALONE
if (clip == NULL) {
return NULL;
}
@@ -945,6 +949,9 @@ GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, in
*tex = GPU_texture_from_bindcode(textarget, bindcode);
return *tex;
+#else
+ return NULL;
+#endif
}
void GPU_free_texture_movieclip(struct MovieClip *clip)
@@ -1270,6 +1277,7 @@ void GPU_create_gl_tex_compressed(unsigned int *bind, int textarget, Image *ima,
* re-uploaded to OpenGL */
void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
{
+#ifndef GPU_STANDALONE
if (!GTS.domipmap) {
return;
}
@@ -1321,10 +1329,12 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
}
}
}
+#endif /* GPU_STANDALONE */
}
void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
+#ifndef GPU_STANDALONE
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
@@ -1346,6 +1356,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
}
BKE_image_release_ibuf(ima, ibuf, NULL);
+#endif
}
static LinkNode *image_free_queue = NULL;
@@ -1526,177 +1537,3 @@ void GPU_state_init(void)
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
}
}
-
-/** \name Framebuffer color depth, for selection codes
- * \{ */
-
-#define STATE_STACK_DEPTH 16
-
-typedef struct {
- eGPUAttrMask mask;
-
- /* GL_ENABLE_BIT */
- uint is_blend : 1;
- uint is_cull_face : 1;
- uint is_depth_test : 1;
- uint is_dither : 1;
- uint is_lighting : 1;
- uint is_line_smooth : 1;
- uint is_color_logic_op : 1;
- uint is_multisample : 1;
- uint is_polygon_offset_line : 1;
- uint is_polygon_offset_fill : 1;
- uint is_polygon_smooth : 1;
- uint is_sample_alpha_to_coverage : 1;
- uint is_scissor_test : 1;
- uint is_stencil_test : 1;
-
- bool is_clip_plane[6];
-
- /* GL_DEPTH_BUFFER_BIT */
- /* uint is_depth_test : 1; */
- int depth_func;
- double depth_clear_value;
- bool depth_write_mask;
-
- /* GL_SCISSOR_BIT */
- int scissor_box[4];
- /* uint is_scissor_test : 1; */
-
- /* GL_VIEWPORT_BIT */
- int viewport[4];
- double near_far[2];
-} GPUAttrValues;
-
-typedef struct {
- GPUAttrValues attr_stack[STATE_STACK_DEPTH];
- uint top;
-} GPUAttrStack;
-
-static GPUAttrStack state = {
- .top = 0,
-};
-
-#define AttrStack state
-#define Attr state.attr_stack[state.top]
-
-/**
- * Replacement for glPush/PopAttributes
- *
- * We don't need to cover all the options of legacy OpenGL
- * but simply the ones used by Blender.
- */
-void gpuPushAttr(eGPUAttrMask mask)
-{
- Attr.mask = mask;
-
- if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
- Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
- glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func);
- glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value);
- glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask);
- }
-
- if ((mask & GPU_ENABLE_BIT) != 0) {
- Attr.is_blend = glIsEnabled(GL_BLEND);
-
- for (int i = 0; i < 6; i++) {
- Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
- }
-
- Attr.is_cull_face = glIsEnabled(GL_CULL_FACE);
- Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
- Attr.is_dither = glIsEnabled(GL_DITHER);
- Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
- Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
- Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE);
- Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
- Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
- Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
- Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
- Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
- Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
- }
-
- if ((mask & GPU_SCISSOR_BIT) != 0) {
- Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
- glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box);
- }
-
- if ((mask & GPU_VIEWPORT_BIT) != 0) {
- glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far);
- glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport);
- }
-
- if ((mask & GPU_BLEND_BIT) != 0) {
- Attr.is_blend = glIsEnabled(GL_BLEND);
- }
-
- BLI_assert(AttrStack.top < STATE_STACK_DEPTH);
- AttrStack.top++;
-}
-
-static void restore_mask(GLenum cap, const bool value)
-{
- if (value) {
- glEnable(cap);
- }
- else {
- glDisable(cap);
- }
-}
-
-void gpuPopAttr(void)
-{
- BLI_assert(AttrStack.top > 0);
- AttrStack.top--;
-
- GLint mask = Attr.mask;
-
- if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
- restore_mask(GL_DEPTH_TEST, Attr.is_depth_test);
- glDepthFunc(Attr.depth_func);
- glClearDepth(Attr.depth_clear_value);
- glDepthMask(Attr.depth_write_mask);
- }
-
- if ((mask & GPU_ENABLE_BIT) != 0) {
- restore_mask(GL_BLEND, Attr.is_blend);
-
- for (int i = 0; i < 6; i++) {
- restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]);
- }
-
- restore_mask(GL_CULL_FACE, Attr.is_cull_face);
- restore_mask(GL_DEPTH_TEST, Attr.is_depth_test);
- restore_mask(GL_DITHER, Attr.is_dither);
- restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth);
- restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op);
- restore_mask(GL_MULTISAMPLE, Attr.is_multisample);
- restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line);
- restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill);
- restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth);
- restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage);
- restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test);
- restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test);
- }
-
- if ((mask & GPU_VIEWPORT_BIT) != 0) {
- glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]);
- glDepthRange(Attr.near_far[0], Attr.near_far[1]);
- }
-
- if ((mask & GPU_SCISSOR_BIT) != 0) {
- restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test);
- glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]);
- }
-
- if ((mask & GPU_BLEND_BIT) != 0) {
- restore_mask(GL_BLEND, Attr.is_blend);
- }
-}
-
-#undef Attr
-#undef AttrStack
-
-/** \} */
diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/gpu/intern/gpu_draw_smoke.c
index 5cca472148a..546faadbda4 100644
--- a/source/blender/gpu/intern/gpu_draw_smoke.c
+++ b/source/blender/gpu/intern/gpu_draw_smoke.c
@@ -122,13 +122,12 @@ static GPUTexture *create_transfer_function(int type, const struct ColorBand *co
return tex;
}
-static void swizzle_texture_channel_rrrr(GPUTexture *tex)
+static void swizzle_texture_channel_single(GPUTexture *tex)
{
+ /* Swizzle texture channels so that we get useful RGBA values when sampling
+ * a texture with fewer channels, e.g. when using density as color. */
GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
+ GPU_texture_swizzle_channel_auto(tex, 1);
GPU_texture_unbind(tex);
}
@@ -186,60 +185,59 @@ static GPUTexture *create_field_texture(FluidDomainSettings *mds)
GPUTexture *tex = GPU_texture_create_nD(
mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
- swizzle_texture_channel_rrrr(tex);
+ swizzle_texture_channel_single(tex);
return tex;
}
static GPUTexture *create_density_texture(FluidDomainSettings *mds, int highres)
{
- float *data = NULL, *source;
- int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells;
+ int *dim = (highres) ? mds->res_noise : mds->res;
+
+ float *data;
+ if (highres) {
+ data = manta_smoke_turbulence_get_density(mds->fluid);
+ }
+ else {
+ data = manta_smoke_get_density(mds->fluid);
+ }
+
+ GPUTexture *tex = GPU_texture_create_nD(
+ dim[0], dim[1], dim[2], 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+
+ swizzle_texture_channel_single(tex);
+
+ return tex;
+}
+
+static GPUTexture *create_color_texture(FluidDomainSettings *mds, int highres)
+{
const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) :
manta_smoke_has_colors(mds->fluid);
+
+ if (!has_color) {
+ return NULL;
+ }
+
+ int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells;
int *dim = (highres) ? mds->res_noise : mds->res;
- eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8;
+ float *data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
- if (has_color) {
- data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
+ if (data == NULL) {
+ return NULL;
}
if (highres) {
- if (has_color) {
- manta_smoke_turbulence_get_rgba(mds->fluid, data, 0);
- }
- else {
- source = manta_smoke_turbulence_get_density(mds->fluid);
- }
+ manta_smoke_turbulence_get_rgba(mds->fluid, data, 0);
}
else {
- if (has_color) {
- manta_smoke_get_rgba(mds->fluid, data, 0);
- }
- else {
- source = manta_smoke_get_density(mds->fluid);
- }
+ manta_smoke_get_rgba(mds->fluid, data, 0);
}
- GPUTexture *tex = GPU_texture_create_nD(dim[0],
- dim[1],
- dim[2],
- 3,
- (has_color) ? data : source,
- format,
- GPU_DATA_FLOAT,
- 0,
- true,
- NULL);
- if (data) {
- MEM_freeN(data);
- }
+ GPUTexture *tex = GPU_texture_create_nD(
+ dim[0], dim[1], dim[2], 3, data, GPU_RGBA8, GPU_DATA_FLOAT, 0, true, NULL);
+
+ MEM_freeN(data);
- if (format == GPU_R8) {
- /* Swizzle the RGBA components to read the Red channel so
- * that the shader stay the same for colored and non color
- * density textures. */
- swizzle_texture_channel_rrrr(tex);
- }
return tex;
}
@@ -264,7 +262,7 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres)
GPUTexture *tex = GPU_texture_create_nD(
dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
- swizzle_texture_channel_rrrr(tex);
+ swizzle_texture_channel_single(tex);
return tex;
}
@@ -280,35 +278,40 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres)
void GPU_free_smoke(FluidModifierData *mmd)
{
if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
- if (mmd->domain->tex) {
- GPU_texture_free(mmd->domain->tex);
+ if (mmd->domain->tex_density) {
+ GPU_texture_free(mmd->domain->tex_density);
+ mmd->domain->tex_density = NULL;
+ }
+
+ if (mmd->domain->tex_color) {
+ GPU_texture_free(mmd->domain->tex_color);
+ mmd->domain->tex_color = NULL;
}
- mmd->domain->tex = NULL;
if (mmd->domain->tex_shadow) {
GPU_texture_free(mmd->domain->tex_shadow);
+ mmd->domain->tex_shadow = NULL;
}
- mmd->domain->tex_shadow = NULL;
if (mmd->domain->tex_flame) {
GPU_texture_free(mmd->domain->tex_flame);
+ mmd->domain->tex_flame = NULL;
}
- mmd->domain->tex_flame = NULL;
if (mmd->domain->tex_flame_coba) {
GPU_texture_free(mmd->domain->tex_flame_coba);
+ mmd->domain->tex_flame_coba = NULL;
}
- mmd->domain->tex_flame_coba = NULL;
if (mmd->domain->tex_coba) {
GPU_texture_free(mmd->domain->tex_coba);
+ mmd->domain->tex_coba = NULL;
}
- mmd->domain->tex_coba = NULL;
if (mmd->domain->tex_field) {
GPU_texture_free(mmd->domain->tex_field);
+ mmd->domain->tex_field = NULL;
}
- mmd->domain->tex_field = NULL;
}
}
@@ -338,8 +341,11 @@ void GPU_create_smoke(FluidModifierData *mmd, int highres)
if (mmd->type & MOD_FLUID_TYPE_DOMAIN) {
FluidDomainSettings *mds = mmd->domain;
- if (!mds->tex) {
- mds->tex = create_density_texture(mds, highres);
+ if (!mds->tex_density) {
+ mds->tex_density = create_density_texture(mds, highres);
+ }
+ if (!mds->tex_color) {
+ mds->tex_color = create_color_texture(mds, highres);
}
if (!mds->tex_flame) {
mds->tex_flame = create_flame_texture(mds, highres);
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 4676cc3b244..f497ed22bec 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -78,6 +78,8 @@ static struct GPUGlobal {
/* Some Intel drivers have limited support for `GLEW_ARB_base_instance` so in
* these cases it is best to indicate that it is not supported. See T67951 */
bool glew_arb_base_instance_is_supported;
+ /* Cubemap Array support. */
+ bool glew_arb_texture_cube_map_array_is_supported;
/* Some Intel drivers have issues with using mips as framebuffer targets if
* GL_TEXTURE_MAX_LEVEL is higher than the target mip.
* We need a workaround in this cases. */
@@ -197,6 +199,11 @@ bool GPU_arb_base_instance_is_supported(void)
return GG.glew_arb_base_instance_is_supported;
}
+bool GPU_arb_texture_cube_map_array_is_supported(void)
+{
+ return GG.glew_arb_texture_cube_map_array_is_supported;
+}
+
bool GPU_mip_render_workaround(void)
{
return GG.mip_render_workaround;
@@ -281,6 +288,7 @@ void gpu_extensions_init(void)
}
GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance;
+ GG.glew_arb_texture_cube_map_array_is_supported = GLEW_ARB_texture_cube_map_array;
gpu_detect_mip_render_workaround();
if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) {
@@ -348,7 +356,11 @@ void gpu_extensions_exit(void)
bool GPU_mem_stats_supported(void)
{
+#ifndef GPU_STANDALONE
return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM);
+#else
+ return false;
+#endif
}
void GPU_mem_stats_get(int *totalmem, int *freemem)
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
index bd3de96d636..671335ca702 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -23,7 +23,9 @@
* GPU immediate mode work-alike
*/
-#include "UI_resources.h"
+#ifndef GPU_STANDALONE
+# include "UI_resources.h"
+#endif
#include "GPU_attr_binding.h"
#include "GPU_immediate.h"
@@ -910,6 +912,8 @@ void immUniformColor4ubv(const uchar rgba[4])
immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]);
}
+#ifndef GPU_STANDALONE
+
void immUniformThemeColor(int color_id)
{
float color[4];
@@ -958,3 +962,5 @@ void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col);
immUniformColor4ub(col[0], col[1], col[2], col[3]);
}
+
+#endif /* GPU_STANDALONE */
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index c99b7fc8a67..96dc437e10b 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -64,12 +64,16 @@ void GPU_init(void)
immInit();
}
+#ifndef GPU_STANDALONE
gpu_pbvh_init();
+#endif
}
void GPU_exit(void)
{
+#ifndef GPU_STANDALONE
gpu_pbvh_exit();
+#endif
if (!G.background) {
immDestroy();
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index b2658839d67..8a4a88d0663 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -70,6 +70,7 @@ struct GPUMaterial {
const void *engine_type; /* attached engine type */
int options; /* to identify shader variations (shadow, probe, world background...) */
+ bool is_volume_shader; /* is volumetric shader */
/* Nodes */
GPUNodeGraph graph;
@@ -80,7 +81,8 @@ struct GPUMaterial {
/* XXX: Should be in Material. But it depends on the output node
* used and since the output selection is different for GPUMaterial...
*/
- int domain;
+ bool has_volume_output;
+ bool has_surface_output;
/* Only used by Eevee to know which bsdf are used. */
int flag;
@@ -109,8 +111,8 @@ struct GPUMaterial {
};
enum {
- GPU_DOMAIN_SURFACE = (1 << 0),
- GPU_DOMAIN_VOLUME = (1 << 1),
+ GPU_USE_SURFACE_OUTPUT = (1 << 0),
+ GPU_USE_VOLUME_OUTPUT = (1 << 1),
};
/* Functions */
@@ -567,6 +569,11 @@ ListBase GPU_material_textures(GPUMaterial *material)
return material->graph.textures;
}
+ListBase GPU_material_volume_grids(GPUMaterial *material)
+{
+ return material->graph.volume_grids;
+}
+
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
{
if (!material->graph.outlink) {
@@ -592,14 +599,19 @@ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
/* Code generation */
-bool GPU_material_use_domain_surface(GPUMaterial *mat)
+bool GPU_material_has_surface_output(GPUMaterial *mat)
+{
+ return mat->has_surface_output;
+}
+
+bool GPU_material_has_volume_output(GPUMaterial *mat)
{
- return (mat->domain & GPU_DOMAIN_SURFACE);
+ return mat->has_volume_output;
}
-bool GPU_material_use_domain_volume(GPUMaterial *mat)
+bool GPU_material_is_volume_shader(GPUMaterial *mat)
{
- return (mat->domain & GPU_DOMAIN_VOLUME);
+ return mat->is_volume_shader;
}
void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag)
@@ -636,7 +648,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
struct bNodeTree *ntree,
ListBase *gpumaterials,
const void *engine_type,
- int options,
+ const int options,
+ const bool is_volume_shader,
const char *vert_code,
const char *geom_code,
const char *frag_lib,
@@ -655,6 +668,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
mat->scene = scene;
mat->engine_type = engine_type;
mat->options = options;
+ mat->is_volume_shader = is_volume_shader;
#ifndef NDEBUG
BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
#else
@@ -670,8 +684,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
gpu_material_ramp_texture_build(mat);
- SET_FLAG_FROM_TEST(mat->domain, has_surface_output, GPU_DOMAIN_SURFACE);
- SET_FLAG_FROM_TEST(mat->domain, has_volume_output, GPU_DOMAIN_VOLUME);
+ mat->has_surface_output = has_surface_output;
+ mat->has_volume_output = has_volume_output;
if (mat->graph.outlink) {
/* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index de35b43109f..0d5cc46c0b9 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -119,6 +119,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->source = GPU_SOURCE_TEX_TILED_MAPPING;
input->texture = link->texture;
break;
+ case GPU_NODE_LINK_VOLUME_GRID:
+ input->source = GPU_SOURCE_VOLUME_GRID;
+ input->volume_grid = link->volume_grid;
+ break;
case GPU_NODE_LINK_ATTR:
input->source = GPU_SOURCE_ATTR;
input->attr = link->attr;
@@ -321,6 +325,31 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
return tex;
}
+static GPUMaterialVolumeGrid *gpu_node_graph_add_volume_grid(GPUNodeGraph *graph, const char *name)
+{
+ /* Find existing volume grid. */
+ int num_grids = 0;
+ GPUMaterialVolumeGrid *grid = graph->volume_grids.first;
+ for (; grid; grid = grid->next) {
+ if (STREQ(grid->name, name)) {
+ break;
+ }
+ num_grids++;
+ }
+
+ /* Add new requested volume grid. */
+ if (grid == NULL) {
+ grid = MEM_callocN(sizeof(*grid), __func__);
+ grid->name = BLI_strdup(name);
+ BLI_snprintf(grid->sampler_name, sizeof(grid->sampler_name), "vsamp%d", num_grids);
+ BLI_addtail(&graph->volume_grids, grid);
+ }
+
+ grid->users++;
+
+ return grid;
+}
+
/* Creating Inputs */
GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name)
@@ -394,6 +423,30 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro
return link;
}
+GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name)
+{
+ /* NOTE: this could be optimized by automatically merging duplicate
+ * lookups of the same attribute. */
+ GPUNodeGraph *graph = gpu_material_node_graph(mat);
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_VOLUME_GRID;
+ link->volume_grid = gpu_node_graph_add_volume_grid(graph, name);
+
+ /* Two special cases, where we adjust the output values of smoke grids to
+ * bring the into standard range without having to modify the grid values. */
+ if (strcmp(name, "color") == 0) {
+ GPU_link(mat, "node_attribute_volume_color", link, &link);
+ }
+ else if (strcmp(name, "temperature") == 0) {
+ GPU_link(mat, "node_attribute_volume_temperature", link, &link);
+ }
+ else {
+ GPU_link(mat, "node_attribute_volume", link, &link);
+ }
+
+ return link;
+}
+
GPUNodeLink *GPU_builtin(eGPUBuiltin builtin)
{
GPUNodeLink *link = gpu_node_link_create();
@@ -537,6 +590,9 @@ static void gpu_inputs_free(ListBase *inputs)
else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) {
input->texture->users--;
}
+ else if (ELEM(input->source, GPU_SOURCE_VOLUME_GRID)) {
+ input->volume_grid->users--;
+ }
if (input->link) {
gpu_node_link_free(input->link);
@@ -579,6 +635,11 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
void gpu_node_graph_free(GPUNodeGraph *graph)
{
gpu_node_graph_free_nodes(graph);
+
+ for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) {
+ MEM_SAFE_FREE(grid->name);
+ }
+ BLI_freelistN(&graph->volume_grids);
BLI_freelistN(&graph->textures);
BLI_freelistN(&graph->attributes);
}
@@ -637,4 +698,12 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
BLI_freelinkN(&graph->textures, tex);
}
}
+
+ for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first, *next = NULL; grid; grid = next) {
+ next = grid->next;
+ if (grid->users == 0) {
+ MEM_SAFE_FREE(grid->name);
+ BLI_freelinkN(&graph->volume_grids, grid);
+ }
+ }
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 9214bd7f1ba..ceaeea2bfa8 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -48,6 +48,8 @@ typedef enum eGPUDataSource {
GPU_SOURCE_STRUCT,
GPU_SOURCE_TEX,
GPU_SOURCE_TEX_TILED_MAPPING,
+ GPU_SOURCE_VOLUME_GRID,
+ GPU_SOURCE_VOLUME_GRID_TRANSFORM,
} eGPUDataSource;
typedef enum {
@@ -59,6 +61,7 @@ typedef enum {
GPU_NODE_LINK_IMAGE,
GPU_NODE_LINK_IMAGE_TILED,
GPU_NODE_LINK_IMAGE_TILED_MAPPING,
+ GPU_NODE_LINK_VOLUME_GRID,
GPU_NODE_LINK_OUTPUT,
GPU_NODE_LINK_UNIFORM,
} GPUNodeLinkType;
@@ -88,6 +91,8 @@ struct GPUNodeLink {
eGPUBuiltin builtin;
/* GPU_NODE_LINK_COLORBAND */
struct GPUTexture **colorband;
+ /* GPU_NODE_LINK_VOLUME_GRID */
+ struct GPUMaterialVolumeGrid *volume_grid;
/* GPU_NODE_LINK_OUTPUT */
struct GPUOutput *output;
/* GPU_NODE_LINK_ATTR */
@@ -126,6 +131,8 @@ typedef struct GPUInput {
struct GPUMaterialTexture *texture;
/* GPU_SOURCE_ATTR */
struct GPUMaterialAttribute *attr;
+ /* GPU_SOURCE_VOLUME_GRID */
+ struct GPUMaterialVolumeGrid *volume_grid;
};
} GPUInput;
@@ -139,6 +146,7 @@ typedef struct GPUNodeGraph {
/* Requested attributes and textures. */
ListBase attributes;
ListBase textures;
+ ListBase volume_grids;
} GPUNodeGraph;
/* Node Graph */
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 1fb83b628e1..498de13e10f 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -30,6 +30,7 @@
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
+#include "GPU_state.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c
index 6e8b062cff0..578546f3af9 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.c
+++ b/source/blender/gpu/intern/gpu_select_sample_query.c
@@ -26,9 +26,8 @@
#include <stdlib.h>
-#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_select.h"
+#include "GPU_state.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
@@ -37,10 +36,6 @@
#include "BLI_utildefines.h"
-#include "PIL_time.h"
-
-#include "BKE_global.h"
-
#include "gpu_select_private.h"
/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index c950a1daaa5..0993d69e14d 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -46,7 +46,7 @@
/* Adjust these constants as needed. */
#define MAX_DEFINE_LENGTH 256
-#define MAX_EXT_DEFINE_LENGTH 256
+#define MAX_EXT_DEFINE_LENGTH 512
/* Non-generated shaders */
extern char datatoc_gpu_shader_depth_only_frag_glsl[];
@@ -235,6 +235,10 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
if (GLEW_ARB_shader_draw_parameters) {
strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n");
}
+ if (GPU_arb_texture_cube_map_array_is_supported()) {
+ strcat(defines, "#extension GL_ARB_texture_cube_map_array : enable\n");
+ strcat(defines, "#define GPU_ARB_texture_cube_map_array\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c
index caf97a620ab..9ff518aec1b 100644
--- a/source/blender/gpu/intern/gpu_state.c
+++ b/source/blender/gpu/intern/gpu_state.c
@@ -18,7 +18,12 @@
* \ingroup gpu
*/
-#include "DNA_userdef_types.h"
+#ifndef GPU_STANDALONE
+# include "DNA_userdef_types.h"
+# define PIXELSIZE (U.pixelsize)
+#else
+# define PIXELSIZE (1.0f)
+#endif
#include "BLI_utildefines.h"
@@ -107,7 +112,7 @@ void GPU_line_smooth(bool enable)
void GPU_line_width(float width)
{
float max_size = GPU_max_line_width();
- float final_size = width * U.pixelsize;
+ float final_size = width * PIXELSIZE;
/* Fix opengl errors on certain platform / drivers. */
CLAMP(final_size, 1.0f, max_size);
glLineWidth(final_size);
@@ -115,7 +120,7 @@ void GPU_line_width(float width)
void GPU_point_size(float size)
{
- glPointSize(size * U.pixelsize);
+ glPointSize(size * PIXELSIZE);
}
void GPU_polygon_smooth(bool enable)
@@ -189,3 +194,177 @@ void GPU_logic_op_invert_set(bool enable)
glEnable(GL_DITHER);
}
}
+
+/** \name GPU Push/Pop State
+ * \{ */
+
+#define STATE_STACK_DEPTH 16
+
+typedef struct {
+ eGPUAttrMask mask;
+
+ /* GL_ENABLE_BIT */
+ uint is_blend : 1;
+ uint is_cull_face : 1;
+ uint is_depth_test : 1;
+ uint is_dither : 1;
+ uint is_lighting : 1;
+ uint is_line_smooth : 1;
+ uint is_color_logic_op : 1;
+ uint is_multisample : 1;
+ uint is_polygon_offset_line : 1;
+ uint is_polygon_offset_fill : 1;
+ uint is_polygon_smooth : 1;
+ uint is_sample_alpha_to_coverage : 1;
+ uint is_scissor_test : 1;
+ uint is_stencil_test : 1;
+
+ bool is_clip_plane[6];
+
+ /* GL_DEPTH_BUFFER_BIT */
+ /* uint is_depth_test : 1; */
+ int depth_func;
+ double depth_clear_value;
+ bool depth_write_mask;
+
+ /* GL_SCISSOR_BIT */
+ int scissor_box[4];
+ /* uint is_scissor_test : 1; */
+
+ /* GL_VIEWPORT_BIT */
+ int viewport[4];
+ double near_far[2];
+} GPUAttrValues;
+
+typedef struct {
+ GPUAttrValues attr_stack[STATE_STACK_DEPTH];
+ uint top;
+} GPUAttrStack;
+
+static GPUAttrStack state = {
+ .top = 0,
+};
+
+#define AttrStack state
+#define Attr state.attr_stack[state.top]
+
+/**
+ * Replacement for glPush/PopAttributes
+ *
+ * We don't need to cover all the options of legacy OpenGL
+ * but simply the ones used by Blender.
+ */
+void gpuPushAttr(eGPUAttrMask mask)
+{
+ Attr.mask = mask;
+
+ if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+ Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func);
+ glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value);
+ glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask);
+ }
+
+ if ((mask & GPU_ENABLE_BIT) != 0) {
+ Attr.is_blend = glIsEnabled(GL_BLEND);
+
+ for (int i = 0; i < 6; i++) {
+ Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
+ }
+
+ Attr.is_cull_face = glIsEnabled(GL_CULL_FACE);
+ Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ Attr.is_dither = glIsEnabled(GL_DITHER);
+ Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
+ Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
+ Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE);
+ Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
+ Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
+ Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
+ Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
+ Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+ Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
+ }
+
+ if ((mask & GPU_SCISSOR_BIT) != 0) {
+ Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+ glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box);
+ }
+
+ if ((mask & GPU_VIEWPORT_BIT) != 0) {
+ glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far);
+ glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport);
+ }
+
+ if ((mask & GPU_BLEND_BIT) != 0) {
+ Attr.is_blend = glIsEnabled(GL_BLEND);
+ }
+
+ BLI_assert(AttrStack.top < STATE_STACK_DEPTH);
+ AttrStack.top++;
+}
+
+static void restore_mask(GLenum cap, const bool value)
+{
+ if (value) {
+ glEnable(cap);
+ }
+ else {
+ glDisable(cap);
+ }
+}
+
+void gpuPopAttr(void)
+{
+ BLI_assert(AttrStack.top > 0);
+ AttrStack.top--;
+
+ GLint mask = Attr.mask;
+
+ if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+ restore_mask(GL_DEPTH_TEST, Attr.is_depth_test);
+ glDepthFunc(Attr.depth_func);
+ glClearDepth(Attr.depth_clear_value);
+ glDepthMask(Attr.depth_write_mask);
+ }
+
+ if ((mask & GPU_ENABLE_BIT) != 0) {
+ restore_mask(GL_BLEND, Attr.is_blend);
+
+ for (int i = 0; i < 6; i++) {
+ restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]);
+ }
+
+ restore_mask(GL_CULL_FACE, Attr.is_cull_face);
+ restore_mask(GL_DEPTH_TEST, Attr.is_depth_test);
+ restore_mask(GL_DITHER, Attr.is_dither);
+ restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth);
+ restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op);
+ restore_mask(GL_MULTISAMPLE, Attr.is_multisample);
+ restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line);
+ restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill);
+ restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth);
+ restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage);
+ restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test);
+ restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test);
+ }
+
+ if ((mask & GPU_VIEWPORT_BIT) != 0) {
+ glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]);
+ glDepthRange(Attr.near_far[0], Attr.near_far[1]);
+ }
+
+ if ((mask & GPU_SCISSOR_BIT) != 0) {
+ restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test);
+ glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]);
+ }
+
+ if ((mask & GPU_BLEND_BIT) != 0) {
+ restore_mask(GL_BLEND, Attr.is_blend);
+ }
+}
+
+#undef Attr
+#undef AttrStack
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 9ef42592b55..7b51b03096f 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -109,7 +109,7 @@ static uint gpu_texture_memory_footprint_compute(GPUTexture *tex)
return tex->bytesize * tex->w * tex->h * tex->d * samp;
case GL_TEXTURE_CUBE_MAP:
return tex->bytesize * 6 * tex->w * tex->h * samp;
- case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY_ARB:
return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp;
default:
return 0;
@@ -138,6 +138,7 @@ static const char *gl_enum_to_str(GLenum e)
#define ENUM_TO_STRING(e) [GL_##e] = STRINGIFY_ARG(e)
static const char *enum_strings[] = {
ENUM_TO_STRING(TEXTURE_CUBE_MAP),
+ ENUM_TO_STRING(TEXTURE_CUBE_MAP_ARRAY),
ENUM_TO_STRING(TEXTURE_2D),
ENUM_TO_STRING(TEXTURE_2D_ARRAY),
ENUM_TO_STRING(TEXTURE_1D),
@@ -202,6 +203,25 @@ static int gpu_get_component_count(eGPUTextureFormat format)
}
}
+static uint gpu_get_data_format_bytesize(int comp, eGPUDataFormat data_format)
+{
+ switch (data_format) {
+ case GPU_DATA_FLOAT:
+ return sizeof(float) * comp;
+ case GPU_DATA_INT:
+ case GPU_DATA_UNSIGNED_INT:
+ return sizeof(int) * comp;
+ case GPU_DATA_UNSIGNED_INT_24_8:
+ case GPU_DATA_10_11_11_REV:
+ return sizeof(int);
+ case GPU_DATA_UNSIGNED_BYTE:
+ return sizeof(char) * comp;
+ default:
+ BLI_assert(0);
+ return 0;
+ }
+}
+
/* Definitely not complete, edit according to the gl specification. */
static void gpu_validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat data_format)
{
@@ -679,6 +699,7 @@ GPUTexture *GPU_texture_create_nD(int w,
}
else {
tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY;
+ tex->format_flag |= GPU_FORMAT_ARRAY;
}
}
else if (n == 1) {
@@ -687,6 +708,7 @@ GPUTexture *GPU_texture_create_nD(int w,
}
else {
tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY;
+ tex->format_flag |= GPU_FORMAT_ARRAY;
}
}
else if (n == 3) {
@@ -839,17 +861,12 @@ GPUTexture *GPU_texture_create_nD(int w,
return tex;
}
-static GPUTexture *GPU_texture_cube_create(int w,
- int d,
- const float *fpixels_px,
- const float *fpixels_py,
- const float *fpixels_pz,
- const float *fpixels_nx,
- const float *fpixels_ny,
- const float *fpixels_nz,
- eGPUTextureFormat tex_format,
- eGPUDataFormat gpu_data_format,
- char err_out[256])
+GPUTexture *GPU_texture_cube_create(int w,
+ int d,
+ const void *pixels,
+ eGPUTextureFormat tex_format,
+ eGPUDataFormat gpu_data_format,
+ char err_out[256])
{
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->w = w;
@@ -867,8 +884,21 @@ static GPUTexture *GPU_texture_cube_create(int w,
tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP;
}
else {
- BLI_assert(false && "Cubemap array Not implemented yet");
- // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY;
+ tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
+ tex->format_flag |= GPU_FORMAT_ARRAY;
+
+ if (!GPU_arb_texture_cube_map_array_is_supported()) {
+ fprintf(stderr, "ERROR: Attempt to create a cubemap array without hardware support!\n");
+ BLI_assert(0);
+ GPU_texture_free(tex);
+ return NULL;
+ }
+
+ if (d > GPU_max_texture_layers() / 6) {
+ BLI_assert(0);
+ GPU_texture_free(tex);
+ return NULL;
+ }
}
GLenum internalformat = gpu_get_gl_internalformat(tex_format);
@@ -905,60 +935,42 @@ static GPUTexture *GPU_texture_cube_create(int w,
glBindTexture(tex->target, tex->bindcode);
/* Upload Texture */
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X,
- 0,
- internalformat,
- tex->w,
- tex->h,
- 0,
- data_format,
- data_type,
- fpixels_px);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
- 0,
- internalformat,
- tex->w,
- tex->h,
- 0,
- data_format,
- data_type,
- fpixels_py);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
- 0,
- internalformat,
- tex->w,
- tex->h,
- 0,
- data_format,
- data_type,
- fpixels_pz);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
- 0,
- internalformat,
- tex->w,
- tex->h,
- 0,
- data_format,
- data_type,
- fpixels_nx);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
- 0,
- internalformat,
- tex->w,
- tex->h,
- 0,
- data_format,
- data_type,
- fpixels_ny);
- glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
- 0,
- internalformat,
- tex->w,
- tex->h,
- 0,
- data_format,
- data_type,
- fpixels_nz);
+ if (d == 0) {
+ const char *pixels_px, *pixels_py, *pixels_pz, *pixels_nx, *pixels_ny, *pixels_nz;
+
+ if (pixels) {
+ size_t face_ofs = w * w * gpu_get_data_format_bytesize(tex->components, gpu_data_format);
+ pixels_px = (char *)pixels + 0 * face_ofs;
+ pixels_nx = (char *)pixels + 1 * face_ofs;
+ pixels_py = (char *)pixels + 2 * face_ofs;
+ pixels_ny = (char *)pixels + 3 * face_ofs;
+ pixels_pz = (char *)pixels + 4 * face_ofs;
+ pixels_nz = (char *)pixels + 5 * face_ofs;
+ }
+ else {
+ pixels_px = pixels_py = pixels_pz = pixels_nx = pixels_ny = pixels_nz = NULL;
+ }
+
+ GLuint face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_px);
+ glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nx);
+ glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_py);
+ glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_ny);
+ glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_pz);
+ glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nz);
+ }
+ else {
+ glTexImage3D(tex->target,
+ 0,
+ internalformat,
+ tex->w,
+ tex->h,
+ tex->d * 6,
+ 0,
+ data_format,
+ data_type,
+ pixels);
+ }
/* Texture Parameters */
if (GPU_texture_stencil(tex) || /* Does not support filtering */
@@ -1131,33 +1143,16 @@ GPUTexture *GPU_texture_create_cube(int w,
char err_out[256])
{
BLI_assert(w > 0);
- const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz;
- const int channels = gpu_get_component_count(tex_format);
-
- if (fpixels) {
- int face_ofs = w * w * channels;
- fpixels_px = fpixels + 0 * face_ofs;
- fpixels_nx = fpixels + 1 * face_ofs;
- fpixels_py = fpixels + 2 * face_ofs;
- fpixels_ny = fpixels + 3 * face_ofs;
- fpixels_pz = fpixels + 4 * face_ofs;
- fpixels_nz = fpixels + 5 * face_ofs;
- }
- else {
- fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL;
- }
+ eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_cube_create(w, 0, fpixels, tex_format, data_format, err_out);
+}
- return GPU_texture_cube_create(w,
- 0,
- fpixels_px,
- fpixels_py,
- fpixels_pz,
- fpixels_nx,
- fpixels_ny,
- fpixels_nz,
- tex_format,
- GPU_DATA_FLOAT,
- err_out);
+GPUTexture *GPU_texture_create_cube_array(
+ int w, int d, eGPUTextureFormat tex_format, const float *fpixels, char err_out[256])
+{
+ BLI_assert(w > 0 && d > 0);
+ eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_cube_create(w, d, fpixels, tex_format, data_format, err_out);
}
GPUTexture *GPU_texture_create_from_vertbuf(GPUVertBuf *vert)
@@ -1297,6 +1292,7 @@ void GPU_texture_add_mipmap(GPUTexture *tex,
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY_ARB:
glTexImage3D(tex->target,
miplvl,
internalformat,
@@ -1385,29 +1381,13 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl
gpu_validate_data_format(tex->format, gpu_data_format);
- size_t buf_size = gpu_texture_memory_footprint_compute(tex);
size_t samples_count = max_ii(1, tex->samples);
-
samples_count *= size[0];
samples_count *= max_ii(1, size[1]);
samples_count *= max_ii(1, size[2]);
- samples_count *= (GPU_texture_cube(tex)) ? 6 : 1;
+ samples_count *= (GPU_texture_cube(tex) && !GPU_texture_array(tex)) ? 6 : 1;
- switch (gpu_data_format) {
- case GPU_DATA_FLOAT:
- buf_size = sizeof(float) * samples_count * tex->components;
- break;
- case GPU_DATA_INT:
- case GPU_DATA_UNSIGNED_INT:
- buf_size = sizeof(int) * samples_count * tex->components;
- break;
- case GPU_DATA_UNSIGNED_INT_24_8:
- case GPU_DATA_10_11_11_REV:
- buf_size = sizeof(int) * samples_count;
- break;
- case GPU_DATA_UNSIGNED_BYTE:
- break;
- }
+ size_t buf_size = samples_count * gpu_get_data_format_bytesize(tex->components, gpu_data_format);
/* AMD Pro driver have a bug that write 8 bytes past buffer size
* if the texture is big. (see T66573) */
@@ -1418,7 +1398,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl
glBindTexture(tex->target, tex->bindcode);
- if (GPU_texture_cube(tex)) {
+ if (GPU_texture_cube(tex) && !GPU_texture_array(tex)) {
int cube_face_size = buf_size / 6;
for (int i = 0; i < 6; i++) {
glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
@@ -1648,6 +1628,17 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
}
}
+void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels)
+{
+ WARN_NOT_BOUND(tex);
+
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, (channels >= 2) ? GL_GREEN : GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, (channels >= 3) ? GL_BLUE : GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE);
+}
+
static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter)
{
switch (filter) {
@@ -1752,6 +1743,11 @@ int GPU_texture_samples(const GPUTexture *tex)
return tex->samples;
}
+bool GPU_texture_array(const GPUTexture *tex)
+{
+ return (tex->format_flag & GPU_FORMAT_ARRAY) != 0;
+}
+
bool GPU_texture_depth(const GPUTexture *tex)
{
return (tex->format_flag & GPU_FORMAT_DEPTH) != 0;
@@ -1817,8 +1813,12 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
size[1] = max_ii(1, tex->h / div);
}
- if (tex->target == GL_TEXTURE_2D_ARRAY) {
+ if (GPU_texture_array(tex)) {
size[2] = tex->d;
+ /* Return the number of face layers. */
+ if (GPU_texture_cube(tex)) {
+ size[2] *= 6;
+ }
}
else if (tex->d > 0) {
size[2] = max_ii(1, tex->d / div);
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
index aa1d437c307..9e1527a9e7f 100644
--- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -1,7 +1,8 @@
-/* Need to be included after common_view_lib.glsl for resource_id. */
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
#ifndef GPU_OBINFOS_UBO
-#define GPU_OBINFOS_UBO
+# define GPU_OBINFOS_UBO
struct ObjectInfos {
vec4 drw_OrcoTexCoFactors[2];
vec4 drw_ObjectColor;
@@ -13,7 +14,7 @@ layout(std140) uniform infoBlock
/* DRW_RESOURCE_CHUNK_LEN = 512 */
ObjectInfos drw_infos[512];
};
-#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
-#define ObjectInfo (drw_infos[resource_id].drw_Infos)
-#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
+# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+# define ObjectInfo (drw_infos[resource_id].drw_Infos)
+# define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
index 501aeb6f34e..a80cd3cb329 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
@@ -1,18 +1,21 @@
-void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+
+/* Uniforms to convert smoke grid values into standard range. */
+uniform vec3 volumeColor = vec3(1.0);
+uniform vec2 volumeTemperature = vec2(0.0);
+
+/* Generic volume attribute. */
+void node_attribute_volume(sampler3D tex, out vec3 outvec)
{
#if defined(MESH_SHADER) && defined(VOLUMETRICS)
vec3 cos = volumeObjectLocalCoord;
#else
vec3 cos = vec3(0.0);
#endif
- outvec = texture(tex, cos).aaa;
- outcol = vec4(outvec, 1.0);
- outf = avg(outvec);
+ outvec = texture(tex, cos).rgb;
}
-uniform vec3 volumeColor = vec3(1.0);
-
-void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+/* Special color attribute for smoke. */
+void node_attribute_volume_color(sampler3D tex, out vec3 outvec)
{
#if defined(MESH_SHADER) && defined(VOLUMETRICS)
vec3 cos = volumeObjectLocalCoord;
@@ -20,69 +23,31 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
vec3 cos = vec3(0.0);
#endif
- vec4 value = texture(tex, cos).rgba;
/* Density is premultiplied for interpolation, divide it out here. */
+ vec4 value = texture(tex, cos).rgba;
if (value.a > 1e-8) {
value.rgb /= value.a;
}
outvec = value.rgb * volumeColor;
- outcol = vec4(outvec, 1.0);
- outf = avg(outvec);
}
-void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+/* Special temperature attribute for smoke. */
+void node_attribute_volume_temperature(sampler3D tex, out float outf)
{
#if defined(MESH_SHADER) && defined(VOLUMETRICS)
vec3 cos = volumeObjectLocalCoord;
#else
vec3 cos = vec3(0.0);
#endif
- 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(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_volume_info(sampler3D densitySampler,
- sampler3D flameSampler,
- vec2 temperature,
- out vec4 outColor,
- out float outDensity,
- out float outFlame,
- out float outTemprature)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 p = volumeObjectLocalCoord;
-#else
- vec3 p = vec3(0.0);
-#endif
-
- vec4 density = texture(densitySampler, p);
- outDensity = density.a;
-
- /* Density is premultiplied for interpolation, divide it out here. */
- if (density.a > 1e-8) {
- density.rgb /= density.a;
+ float value = texture(tex, cos).r;
+ if (volumeTemperature.x < volumeTemperature.y) {
+ outf = (value > 0.01) ?
+ volumeTemperature.x + value * (volumeTemperature.y - volumeTemperature.x) :
+ 0.0;
+ }
+ else {
+ outf = value;
}
- outColor = vec4(density.rgb * volumeColor, 1.0);
-
- float flame = texture(flameSampler, p).r;
- outFlame = flame;
-
- outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
}
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
index a8ed2c5f2a5..a958a445a3d 100644
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
@@ -164,7 +164,7 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap
}
}
}
- printf(" (Total graph size: %lu objects\n", total_graph_size);
+ printf(" (Total graph size: %zu objects\n", total_graph_size);
}
void AbstractHierarchyIterator::export_graph_construct()
@@ -345,7 +345,7 @@ void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
}
else {
/* The parent object is NOT part of the duplicated collection. This means that the world
- * transform of this dupliobject can be influenced by objects that are not part of its
+ * transform of this dupli-object can be influenced by objects that are not part of its
* export graph. */
animation_check_include_parent = true;
context->export_parent = duplicator;
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
index 8bca2ddd447..c121e3b704d 100644
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
+++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
@@ -65,8 +65,8 @@ struct HierarchyContext {
/* When weak_export=true, the object will be exported only as transform, and only if is an
* ancestor of an object with weak_export=false.
*
- * In other words: when weak_export=true but this object has no children, or all decendants also
- * have weak_export=true, this object (and by recursive reasoning all its decendants) will be
+ * In other words: when weak_export=true but this object has no children, or all descendants also
+ * have weak_export=true, this object (and by recursive reasoning all its descendants) will be
* excluded from the export.
*
* The export hierarchy is kept as close to the the hierarchy in Blender as possible. As such, an
@@ -222,7 +222,7 @@ class AbstractHierarchyIterator {
*
* When this returns true, only a transform writer is created and marked as
* 'weak export'. In this case, the transform writer will be removed before
- * exporting starts, unless a decendant of this object is to be exported.
+ * exporting starts, unless a descendant of this object is to be exported.
* Dupli-object generated from this object will also be skipped.
*
* See HierarchyContext::weak_export.
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index 74005afaf31..cbf51fc15b3 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -58,7 +58,7 @@ bool USDGenericMeshWriter::is_supported(const HierarchyContext *context) const
int base_flag;
if (is_dupli) {
- /* Construct the object's base flags from its dupliparent, just like is done in
+ /* Construct the object's base flags from its dupli-parent, just like is done in
* deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing
* this here, instead of a more suitable location in AbstractHierarchyIterator, prevents
* copying the Object for every dupli. */
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 3ac93a96661..40916cbdc61 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -465,16 +465,20 @@ typedef enum ID_Type {
if ((a) && (a)->id.newid) \
(a) = (void *)(a)->id.newid
-/* id->flag (persitent). */
+/** id->flag (persitent). */
enum {
- /* Don't delete the datablock even if unused. */
+ /** Don't delete the datablock even if unused. */
LIB_FAKEUSER = 1 << 9,
- /* The datablock structure is a sub-object of a different one.
- * Direct persistent references are not allowed. */
- LIB_PRIVATE_DATA = 1 << 10,
- /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT
+ /**
+ * The data-block is a sub-data of another one.
+ * Direct persistent references are not allowed.
+ */
+ LIB_EMBEDDED_DATA = 1 << 10,
+ /**
+ * Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT
* tag set. But the current .blend file also has a weak pointer to it that
- * we want to restore if possible, and silently drop if it's missing. */
+ * we want to restore if possible, and silently drop if it's missing.
+ */
LIB_INDIRECT_WEAK_LINK = 1 << 11,
};
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 4b696e29a52..5b9340ab3d9 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -764,10 +764,6 @@ typedef enum eDopeSheet_FilterFlag {
/** show only F-Curves which are disabled/have errors - for debugging drivers */
ADS_FILTER_ONLY_ERRORS = (1 << 28),
- /* GPencil Mode */
- /** GP Mode - Only show datablocks used in the scene */
- ADS_FILTER_GP_3DONLY = (1 << 29),
-
#if 0
/** combination filters (some only used at runtime) */
ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM | ADS_FILTER_NOMAT | ADS_FILTER_NOLAM |
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index 631c1b71732..f344e860d2e 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -256,7 +256,8 @@ typedef struct FluidDomainSettings {
struct Collection *fluid_group;
struct Collection *force_group; /* UNUSED */
struct Collection *effector_group; /* Effector objects group. */
- struct GPUTexture *tex;
+ struct GPUTexture *tex_density;
+ struct GPUTexture *tex_color;
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
struct GPUTexture *tex_flame;
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
index 6ffdd60a094..d9cc549229d 100644
--- a/source/blender/makesdna/DNA_lightprobe_types.h
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -160,6 +160,10 @@ typedef struct LightCacheTexture {
typedef struct LightCache {
int flag;
+ /** Version number to know if the cache data is compatible with this version of blender. */
+ int version;
+ /** Type of data this cache contains. */
+ int type;
/* only a single cache for now */
/** Number of probes to use for rendering. */
int cube_len, grid_len;
@@ -181,6 +185,14 @@ typedef struct LightCache {
LightGridCache *grid_data;
} LightCache;
+/* Bump the version number for lightcache data structure changes. */
+#define LIGHTCACHE_STATIC_VERSION 1
+
+/* LightCache->type */
+enum {
+ LIGHTCACHE_TYPE_STATIC = 0,
+};
+
/* LightCache->flag */
enum {
LIGHTCACHE_BAKED = (1 << 0),
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 042cf7e874f..13c5a0913c6 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1255,6 +1255,19 @@ typedef struct OceanModifierData {
float foam_coverage;
float time;
+ char _pad1[4];
+
+ /* Spectrum being used. */
+ int spectrum;
+
+ /* Common JONSWAP parameters. */
+ /**
+ * This is the distance from a lee shore, called the fetch, or the distance
+ * over which the wind blows with constant velocity.
+ */
+ float fetch_jonswap;
+ float sharpen_peak_jonswap;
+
int bakestart;
int bakeend;
@@ -1287,6 +1300,13 @@ enum {
};
enum {
+ MOD_OCEAN_SPECTRUM_PHILLIPS = 0,
+ MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ = 1,
+ MOD_OCEAN_SPECTRUM_JONSWAP = 2,
+ MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE = 3,
+};
+
+enum {
MOD_OCEAN_GENERATE_FOAM = (1 << 0),
MOD_OCEAN_GENERATE_NORMALS = (1 << 1),
};
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index db3566710b4..4b6f079aa28 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -224,7 +224,7 @@
.shadow_cube_size = 512, \
.shadow_cascade_size = 1024, \
\
- .light_cache = NULL, \
+ .light_cache_data = NULL, \
.light_threshold = 0.01f, \
\
.overscan = 3.0f, \
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 3a88cd0a33b..aac976fbabd 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -242,6 +242,7 @@ typedef struct SceneRenderLayer {
#define SCE_LAY_STRAND (1 << 5)
#define SCE_LAY_FRS (1 << 6)
#define SCE_LAY_AO (1 << 7)
+#define SCE_LAY_VOLUMES (1 << 8)
/* flags between (1 << 8) and (1 << 15) are set to 1 already, for future options */
#define SCE_LAY_ALL_Z (1 << 15)
@@ -1632,7 +1633,8 @@ typedef struct SceneEEVEE {
int shadow_cube_size;
int shadow_cascade_size;
- struct LightCache *light_cache;
+ struct LightCache *light_cache DNA_DEPRECATED;
+ struct LightCache *light_cache_data;
char light_cache_info[64];
float overscan;
diff --git a/source/blender/makesdna/DNA_view3d_enums.h b/source/blender/makesdna/DNA_view3d_enums.h
index 880a157cc3d..f8c772422bb 100644
--- a/source/blender/makesdna/DNA_view3d_enums.h
+++ b/source/blender/makesdna/DNA_view3d_enums.h
@@ -44,10 +44,6 @@ typedef enum eV3DShadingColorType {
V3D_SHADING_TEXTURE_COLOR = 3,
V3D_SHADING_OBJECT_COLOR = 4,
V3D_SHADING_VERTEX_COLOR = 5,
-
- /* Is used to display the object using the error color. For example when in
- * solid texture paint mode without any textures configured */
- V3D_SHADING_ERROR_COLOR = 999,
} eV3DShadingColorType;
/** #View3DShading.background_type */
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index e0f3aff6364..b2d02600124 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4654,8 +4654,8 @@ static const char *cpp_classes =
" operator void*() { return ptr.data; }\n"
" operator bool() { return ptr.data != NULL; }\n"
"\n"
- " bool operator==(const Pointer &other) { return ptr.data == other.ptr.data; }\n"
- " bool operator!=(const Pointer &other) { return ptr.data != other.ptr.data; }\n"
+ " bool operator==(const Pointer &other) const { return ptr.data == other.ptr.data; }\n"
+ " bool operator!=(const Pointer &other) const { return ptr.data != other.ptr.data; }\n"
"\n"
" PointerRNA ptr;\n"
"};\n"
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 8dd6e6982dd..33f9b2da280 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -5832,7 +5832,7 @@ ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
*r_path = "";
}
- if ((id != NULL) && (id->flag & LIB_PRIVATE_DATA)) {
+ if ((id != NULL) && (id->flag & LIB_EMBEDDED_DATA)) {
switch (GS(id->name)) {
case ID_NT:
if (r_path) {
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 436e847b044..c85a94d9fc2 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -583,15 +583,6 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop, "Display Movie Clips", "Include visualization of movie clip related animation data");
RNA_def_property_ui_icon(prop, ICON_TRACKER, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
- /* GPencil Mode Settings */
- prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY);
- RNA_def_property_ui_text(prop,
- "Active Scene Only",
- "Only show Grease Pencil data-blocks used as part of the active scene");
- RNA_def_property_ui_icon(prop, ICON_SCENE_DATA, 0);
- RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
}
static void rna_def_action_group(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 38ba7bcb047..7bd353cd441 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -720,7 +720,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values)
manta_smoke_turbulence_get_rgba(mds->fluid, values, 0);
}
else {
- manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
+ manta_smoke_turbulence_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0);
}
}
else {
@@ -728,7 +728,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values)
manta_smoke_get_rgba(mds->fluid, values, 0);
}
else {
- manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
+ manta_smoke_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0);
}
}
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 396c5a4e854..6440b140183 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -5178,6 +5178,30 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem spectrum_items[] = {
+ {MOD_OCEAN_SPECTRUM_PHILLIPS,
+ "PHILLIPS",
+ 0,
+ "Turbulent Ocean",
+ "Use for turbulent seas with foam"},
+ {MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ,
+ "PIERSON_MOSKOWITZ",
+ 0,
+ "Established Ocean",
+ "Use for a large area, established ocean (Pierson-Moskowitz method)"},
+ {MOD_OCEAN_SPECTRUM_JONSWAP,
+ "JONSWAP",
+ 0,
+ "Established Ocean (Sharp Peaks)",
+ "Use for sharp peaks ('JONSWAP', Pierson-Moskowitz method) with peak sharpening"},
+ {MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE,
+ "TEXEL_MARSEN_ARSLOE",
+ 0,
+ "Shallow Water",
+ "Use for shallow water ('JONSWAP', 'TMA' - Texel-Marsen-Arsloe method)"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "OceanModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Ocean Modifier", "Simulate an ocean surface");
RNA_def_struct_sdna(srna, "OceanModifierData");
@@ -5324,6 +5348,29 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, -1);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "spectrum", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "spectrum");
+ RNA_def_property_enum_items(prop, spectrum_items);
+ RNA_def_property_ui_text(prop, "Spectrum", "Spectrum to use");
+ RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
+
+ prop = RNA_def_property(srna, "fetch_jonswap", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "fetch_jonswap");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_text(
+ prop,
+ "Fetch",
+ "This is the distance from a lee shore, "
+ "called the fetch, or the distance over which the wind blows with constant velocity. "
+ "Used by 'JONSWAP' and 'TMA' models");
+ RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
+
+ prop = RNA_def_property(srna, "sharpen_peak_jonswap", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "sharpen_peak_jonswap");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(prop, "Sharpen peak", "Peak sharpening for 'JONSWAP' and 'TMA' models");
+ RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
+
prop = RNA_def_property(srna, "random_seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 9aeaf4e83dd..3747dd53b97 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -188,9 +188,9 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr,
* not a very efficient way of getting hair key location data,
* but it's the best we've got at the present
*
- * IDEAS: include additional information in pointerRNA beforehand,
- * for example a pointer to the ParticleStstemModifierData to which the
- * hairkey belongs.
+ * IDEAS: include additional information in PointerRNA beforehand,
+ * for example a pointer to the ParticleSystemModifierData to which the
+ * hair-key belongs.
*/
for (md = ob->modifiers.first; md; md = md->next) {
@@ -199,9 +199,9 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr,
if (psmd && psmd->mesh_final && psmd->psys) {
psys = psmd->psys;
for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
- /* hairkeys are stored sequentially in memory, so we can
+ /* Hair-keys are stored sequentially in memory, so we can
* find if it's the same particle by comparing pointers,
- * without having to iterate over them all */
+ * without having to iterate over them all. */
if ((hkey >= pa->hair) && (hkey < pa->hair + pa->totkey)) {
*psmd_pt = psmd;
*pa_pt = pa;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 27d742fd33c..f974d5c563f 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -4018,6 +4018,16 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
+ prop = RNA_def_property(srna, "use_volumes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_VOLUMES);
+ RNA_def_property_ui_text(prop, "Volumes", "Render volumes in this Layer");
+ if (scene) {
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ }
+ else {
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ }
+
/* passes */
prop = RNA_def_property(srna, "use_pass_combined", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_COMBINED);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index ac0376c72af..a153c1dda1e 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -5040,8 +5040,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{2048, "SAMPLES_2048", 0, "2048 Samples", "Set audio mixing buffer size to 2048 samples"},
{4096, "SAMPLES_4096", 0, "4096 Samples", "Set audio mixing buffer size to 4096 samples"},
{8192, "SAMPLES_8192", 0, "8192 Samples", "Set audio mixing buffer size to 8192 samples"},
- {16384, "SAMPLES_16384", 0, "16384 Samples", "Set audio mixing buffer size to 16384 samples"},
- {32768, "SAMPLES_32768", 0, "32768 Samples", "Set audio mixing buffer size to 32768 samples"},
+ {16384,
+ "SAMPLES_16384",
+ 0,
+ "16384 Samples",
+ "Set audio mixing buffer size to 16384 samples"},
+ {32768,
+ "SAMPLES_32768",
+ 0,
+ "32768 Samples",
+ "Set audio mixing buffer size to 32768 samples"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 9ec4d58eb61..de08533753e 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -206,7 +206,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
Object *ob = ctx->object;
if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
- modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening");
+ modifier_setError(md, "Enable 'Auto Smooth' in Object Data Properties");
harden_normals = false;
}
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 953b1b460c8..63c1b6f1ef0 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -179,7 +179,11 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
}
else {
tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches);
- tclmd->point_cache->step = 1;
+ if (clmd->point_cache != NULL) {
+ tclmd->point_cache->step = clmd->point_cache->step;
+ tclmd->point_cache->startframe = clmd->point_cache->startframe;
+ tclmd->point_cache->endframe = clmd->point_cache->endframe;
+ }
}
tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms);
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index 3e79dd91d2b..72cbe197251 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -220,7 +220,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
}
else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
- modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings");
+ modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties");
}
else if (result->totvert > HIGH_POLY_WARNING ||
((Mesh *)(ob_source->data))->totvert > HIGH_POLY_WARNING) {
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 720ca4ffa13..78d29edfd98 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -316,7 +316,7 @@ static void deformVerts_do(HookModifierData *hmd,
* This should always be true and I don't generally like
* "paranoid" style code like this, but old files can have
* indices that are out of range because old blender did
- * not correct them on exit editmode. - zr
+ * not correct them on exit edit-mode. - zr
*/
if (hmd->force == 0.0f) {
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 572d9505e4e..ace0c1b5eaf 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -494,7 +494,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
#endif
{
- modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings");
+ modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties");
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 62a5dd45e68..fec04e9916d 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -92,6 +92,10 @@ static void initData(ModifierData *md)
omd->seed = 0;
omd->time = 1.0;
+ omd->spectrum = MOD_OCEAN_SPECTRUM_PHILLIPS;
+ omd->sharpen_peak_jonswap = 0.0f;
+ omd->fetch_jonswap = 120.0f;
+
omd->size = 1.0;
omd->repeat_x = 1;
omd->repeat_y = 1;
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 48ccd9b83ed..af6de8447ec 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -69,6 +69,8 @@ static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgr
DEG_add_forcefield_relations(
ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field");
}
+ /* We need own transformation as well. */
+ DEG_add_modifier_to_transform_relation(ctx->node, "SoftBody Modifier");
}
ModifierTypeInfo modifierType_Softbody = {
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index d9c05d8d4b4..04b503e588b 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -562,7 +562,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
#endif
{
- modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings");
+ modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
return mesh;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index 79f02f5c243..6b5d46e250b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -42,28 +42,18 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
{
NodeShaderAttribute *attr = node->storage;
- /* FIXME : if an attribute layer (like vertex color) has one of these names,
- * it will not work as expected. */
- if (strcmp(attr->name, "density") == 0) {
- return GPU_stack_link(
- mat, node, "node_attribute_volume_density", in, out, GPU_builtin(GPU_VOLUME_DENSITY));
- }
- else if (strcmp(attr->name, "color") == 0) {
- return GPU_stack_link(
- mat, node, "node_attribute_volume_color", in, out, GPU_builtin(GPU_VOLUME_DENSITY));
- }
- else if (strcmp(attr->name, "flame") == 0) {
- 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));
+ if (GPU_material_is_volume_shader(mat)) {
+ if (out[0].hasoutput) {
+ out[0].link = GPU_volume_grid(mat, attr->name);
+ }
+ if (out[1].hasoutput) {
+ out[1].link = GPU_volume_grid(mat, attr->name);
+ }
+ if (out[2].hasoutput) {
+ out[2].link = GPU_volume_grid(mat, attr->name);
+ }
+
+ return 1;
}
else {
GPUNodeLink *cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.c
index 57fa2b7e582..7ccc00f1af3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.c
@@ -28,20 +28,25 @@ static bNodeSocketTemplate sh_node_volume_info_out[] = {
};
static int node_shader_gpu_volume_info(GPUMaterial *mat,
- bNode *node,
+ bNode *UNUSED(node),
bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
+ GPUNodeStack *UNUSED(in),
GPUNodeStack *out)
{
+ if (out[0].hasoutput) {
+ out[0].link = GPU_volume_grid(mat, "color");
+ }
+ if (out[1].hasoutput) {
+ out[1].link = GPU_volume_grid(mat, "density");
+ }
+ if (out[2].hasoutput) {
+ out[2].link = GPU_volume_grid(mat, "flame");
+ }
+ if (out[3].hasoutput) {
+ out[3].link = GPU_volume_grid(mat, "temperature");
+ }
- return GPU_stack_link(mat,
- node,
- "node_volume_info",
- in,
- out,
- GPU_builtin(GPU_VOLUME_DENSITY),
- GPU_builtin(GPU_VOLUME_FLAME),
- GPU_builtin(GPU_VOLUME_TEMPERATURE));
+ return true;
}
void register_node_type_sh_volume_info(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
index dc41d6b2531..92e1b3435c8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
@@ -54,42 +54,6 @@ static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *
}
}
-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),
@@ -108,16 +72,19 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
}
bNodeSocketValueString *value = sock->default_value;
- GPUNodeLink *outcol, *outvec, *outf;
+ const char *attribute_name = value->value;
+ if (attribute_name[0] == '\0') {
+ continue;
+ }
if (STREQ(sock->name, "Density Attribute")) {
- node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &density);
+ density = GPU_volume_grid(mat, attribute_name);
}
else if (STREQ(sock->name, "Color Attribute")) {
- node_shader_gpu_volume_attribute(mat, value->value, &color, &outvec, &outf);
+ color = GPU_volume_grid(mat, attribute_name);
}
else if (use_blackbody && STREQ(sock->name, "Temperature Attribute")) {
- node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &temperature);
+ temperature = GPU_volume_grid(mat, attribute_name);
}
}
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index ff81b4a15ff..c32ef3e6624 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -923,7 +923,7 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
if (DEG_get_original_id(id) != id) {
ret = PyUnicode_FromFormat("Evaluated %s %R", BKE_idcode_to_name(GS(id->name)), tmp_str);
}
- else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) {
+ else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_EMBEDDED_DATA) == 0) {
ret = PyUnicode_FromFormat(
"bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str);
}
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 1c1a1a26e3b..6344ed39b1b 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -98,7 +98,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d
return IDWALK_RET_NOP;
}
- if (cb_flag & IDWALK_CB_PRIVATE) {
+ if (cb_flag & IDWALK_CB_EMBEDDED) {
/* We skip private pointers themselves, like root node trees, we'll 'link' their own ID
* pointers to their 'ID owner' instead. */
return IDWALK_RET_NOP;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 8728c887feb..c7556ec7516 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2498,6 +2498,164 @@ static int wm_handlers_do_keymap_with_gizmo_handler(
return action;
}
+static int wm_handlers_do_gizmo_handler(bContext *C,
+ wmWindowManager *wm,
+ wmEventHandler_Gizmo *handler,
+ wmEvent *event,
+ ListBase *handlers,
+ const bool do_debug_handler)
+{
+ int action = WM_HANDLER_CONTINUE;
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ wmGizmoMap *gzmap = handler->gizmo_map;
+ BLI_assert(gzmap != NULL);
+ wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
+
+ /* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
+ * noticeable for the node editor - where dragging on a node should move it, see: T73212. */
+ if (region->type->clip_gizmo_events_by_ui) {
+ if (UI_region_block_find_mouse_over(region, &event->x, true)) {
+ if (gz != NULL) {
+ WM_tooltip_clear(C, CTX_wm_window(C));
+ wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ }
+ return action;
+ }
+ }
+
+ if (region->gizmo_map != handler->gizmo_map) {
+ WM_gizmomap_tag_refresh(handler->gizmo_map);
+ }
+
+ wm_gizmomap_handler_context_gizmo(C, handler);
+ wm_region_mouse_co(C, event);
+
+ /* Drag events use the previous click location to highlight the gizmos,
+ * Get the highlight again in case the user dragged off the gizmo. */
+ const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG);
+ const bool is_event_modifier = ISKEYMODIFIER(event->type);
+
+ bool handle_highlight = false;
+ bool handle_keymap = false;
+
+ /* handle gizmo highlighting */
+ if (!wm_gizmomap_modal_get(gzmap) &&
+ ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
+ handle_highlight = true;
+ if (is_event_modifier || is_event_drag) {
+ handle_keymap = true;
+ }
+ }
+ else {
+ handle_keymap = true;
+ }
+
+ if (handle_highlight) {
+ struct {
+ wmGizmo *gz;
+ int part;
+ } prev = {
+ .gz = gz,
+ .part = gz ? gz->highlight_part : 0,
+ };
+ int part = -1;
+ gz = wm_gizmomap_highlight_find(gzmap, C, event, &part);
+
+ /* If no gizmos are/were active, don't clear tool-tips. */
+ if (gz || prev.gz) {
+ if ((prev.gz != gz) || (prev.part != part)) {
+ WM_tooltip_clear(C, CTX_wm_window(C));
+ }
+ }
+
+ if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
+ if (gz != NULL) {
+ if (U.flag & USER_TOOLTIPS) {
+ WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
+ }
+ }
+ }
+ }
+
+ /* Don't use from now on. */
+ bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL);
+
+ if (handle_keymap) {
+ /* Handle highlight gizmo. */
+ if (gz != NULL) {
+ bool keymap_poll = false;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
+ action |= wm_handlers_do_keymap_with_gizmo_handler(
+ C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll);
+
+#ifdef USE_GIZMO_MOUSE_PRIORITY_HACK
+ if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) {
+ if ((event->val == KM_PRESS) && ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
+
+ wmEvent event_test_click = *event;
+ event_test_click.val = KM_CLICK;
+
+ wmEvent event_test_click_drag = *event;
+ event_test_click_drag.val = KM_CLICK_DRAG;
+
+ wmEvent event_test_tweak = *event;
+ event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE);
+ event_test_tweak.val = KM_ANY;
+
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if ((kmi->flag & KMI_INACTIVE) == 0) {
+ if (wm_eventmatch(&event_test_click, kmi) ||
+ wm_eventmatch(&event_test_click_drag, kmi) ||
+ wm_eventmatch(&event_test_tweak, kmi)) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
+ is_event_handle_all = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */
+ }
+
+ /* Don't use from now on. */
+ gz = NULL;
+
+ /* Fallback to selected gizmo (when un-handled). */
+ if ((action & WM_HANDLER_BREAK) == 0) {
+ if (WM_gizmomap_is_any_selected(gzmap)) {
+ const ListBase *groups = WM_gizmomap_group_list(gzmap);
+ for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) {
+ if (wm_gizmogroup_is_any_selected(gzgroup)) {
+ wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
+ action |= wm_handlers_do_keymap_with_gizmo_handler(
+ C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL);
+ if (action & WM_HANDLER_BREAK) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (is_event_handle_all) {
+ if (action == WM_HANDLER_CONTINUE) {
+ action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL;
+ }
+ }
+
+ /* restore the area */
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+
+ return action;
+}
+
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
const bool do_debug_handler =
@@ -2609,142 +2767,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) {
wmEventHandler_Gizmo *handler = (wmEventHandler_Gizmo *)handler_base;
- ScrArea *area = CTX_wm_area(C);
- ARegion *region = CTX_wm_region(C);
- wmGizmoMap *gzmap = handler->gizmo_map;
- BLI_assert(gzmap != NULL);
- wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
-
- if (region->gizmo_map != handler->gizmo_map) {
- WM_gizmomap_tag_refresh(handler->gizmo_map);
- }
-
- wm_gizmomap_handler_context_gizmo(C, handler);
- wm_region_mouse_co(C, event);
-
- /* Drag events use the previous click location to highlight the gizmos,
- * Get the highlight again in case the user dragged off the gizmo. */
- const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG);
- const bool is_event_modifier = ISKEYMODIFIER(event->type);
-
- bool handle_highlight = false;
- bool handle_keymap = false;
-
- /* handle gizmo highlighting */
- if (!wm_gizmomap_modal_get(gzmap) &&
- ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
- handle_highlight = true;
- if (is_event_modifier || is_event_drag) {
- handle_keymap = true;
- }
- }
- else {
- handle_keymap = true;
- }
-
- if (handle_highlight) {
- struct {
- wmGizmo *gz;
- int part;
- } prev = {
- .gz = gz,
- .part = gz ? gz->highlight_part : 0,
- };
- int part = -1;
- gz = wm_gizmomap_highlight_find(gzmap, C, event, &part);
-
- /* If no gizmos are/were active, don't clear tool-tips. */
- if (gz || prev.gz) {
- if ((prev.gz != gz) || (prev.part != part)) {
- WM_tooltip_clear(C, CTX_wm_window(C));
- }
- }
-
- if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
- if (gz != NULL) {
- if (U.flag & USER_TOOLTIPS) {
- WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
- }
- }
- }
- }
-
- /* Don't use from now on. */
- bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL);
-
- if (handle_keymap) {
- /* Handle highlight gizmo. */
- if (gz != NULL) {
- bool keymap_poll = false;
- wmGizmoGroup *gzgroup = gz->parent_gzgroup;
- wmKeyMap *keymap = WM_keymap_active(wm,
- gz->keymap ? gz->keymap : gzgroup->type->keymap);
- action |= wm_handlers_do_keymap_with_gizmo_handler(
- C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll);
-
-#ifdef USE_GIZMO_MOUSE_PRIORITY_HACK
- if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) {
- if ((event->val == KM_PRESS) &&
- ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
-
- wmEvent event_test_click = *event;
- event_test_click.val = KM_CLICK;
-
- wmEvent event_test_click_drag = *event;
- event_test_click_drag.val = KM_CLICK_DRAG;
-
- wmEvent event_test_tweak = *event;
- event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE);
- event_test_tweak.val = KM_ANY;
-
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
- if ((kmi->flag & KMI_INACTIVE) == 0) {
- if (wm_eventmatch(&event_test_click, kmi) ||
- wm_eventmatch(&event_test_click_drag, kmi) ||
- wm_eventmatch(&event_test_tweak, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
- if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
- is_event_handle_all = true;
- break;
- }
- }
- }
- }
- }
- }
-#endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */
- }
-
- /* Don't use from now on. */
- gz = NULL;
-
- /* Fallback to selected gizmo (when un-handled). */
- if ((action & WM_HANDLER_BREAK) == 0) {
- if (WM_gizmomap_is_any_selected(gzmap)) {
- const ListBase *groups = WM_gizmomap_group_list(gzmap);
- for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) {
- if (wm_gizmogroup_is_any_selected(gzgroup)) {
- wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
- action |= wm_handlers_do_keymap_with_gizmo_handler(
- C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL);
- if (action & WM_HANDLER_BREAK) {
- break;
- }
- }
- }
- }
- }
- }
-
- if (is_event_handle_all) {
- if (action == WM_HANDLER_CONTINUE) {
- action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL;
- }
- }
-
- /* restore the area */
- CTX_wm_area_set(C, area);
- CTX_wm_region_set(C, region);
+ action |= wm_handlers_do_gizmo_handler(C, wm, handler, event, handlers, do_debug_handler);
}
else if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
@@ -2915,6 +2938,21 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
}
}
}
+ else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) {
+ /* Modifiers which can trigger click event's,
+ * however we don't want this if the mouse wheel has been used, see T74607. */
+ if (wm_action_not_handled(action)) {
+ /* pass */
+ }
+ else {
+ wmWindow *win = CTX_wm_window(C);
+ if (win) {
+ if (ISKEYMODIFIER(win->eventstate->prevtype)) {
+ win->eventstate->check_click = 0;
+ }
+ }
+ }
+ }
return action;
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 16f2f822338..aab2acaac76 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3340,7 +3340,7 @@ static int previews_id_ensure_callback(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_PRIVATE) {
+ if (cb_flag & IDWALK_CB_EMBEDDED) {
return IDWALK_RET_NOP;
}
diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py
index a7130136d0a..0d9fd37b0d7 100755
--- a/tests/python/eevee_render_tests.py
+++ b/tests/python/eevee_render_tests.py
@@ -35,6 +35,13 @@ def setup():
# mat.use_screen_refraction = True
mat.use_sss_translucency = True
+ # Workaround for crash with Mantaflow (T73921).
+ use_light_cache_bake = True
+ for ob in bpy.data.objects:
+ for mod in ob.modifiers:
+ if mod.type == 'FLUID':
+ use_light_cache_bake = False
+
cubemap = None
grid = None
# Does not work in edit mode
@@ -79,7 +86,8 @@ def setup():
eevee.gi_visibility_resolution = '16'
eevee.gi_irradiance_smoothing = 0
- bpy.ops.scene.light_cache_bake()
+ if use_light_cache_bake:
+ bpy.ops.scene.light_cache_bake()
# When run from inside Blender, render and exit.