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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_files/cmake/macros.cmake21
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--extern/cuew/src/cuew.c2
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc139
-rw-r--r--release/datafiles/userdef/userdef_default.c2
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py52
-rw-r--r--release/scripts/startup/bl_operators/userpref.py5
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py1053
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py1
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py10
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py3
-rw-r--r--release/scripts/startup/nodeitems_builtins.py32
-rw-r--r--source/blender/blenfont/intern/blf_font.c2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_image.h29
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h5
-rw-r--r--source/blender/blenkernel/BKE_paint.h19
-rw-r--r--source/blender/blenkernel/BKE_persistent_data_handle.hh22
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h4
-rw-r--r--source/blender/blenkernel/BKE_simulation.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c2
-rw-r--r--source/blender/blenkernel/intern/curve.c211
-rw-r--r--source/blender/blenkernel/intern/curve_bevel.c272
-rw-r--r--source/blender/blenkernel/intern/curveprofile.c8
-rw-r--r--source/blender/blenkernel/intern/customdata.c12
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c364
-rw-r--r--source/blender/blenkernel/intern/font.c2
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c7
-rw-r--r--source/blender/blenkernel/intern/image.c25
-rw-r--r--source/blender/blenkernel/intern/image_gpu.c777
-rw-r--r--source/blender/blenkernel/intern/lib_query.c3
-rw-r--r--source/blender/blenkernel/intern/material.c3
-rw-r--r--source/blender/blenkernel/intern/movieclip.c81
-rw-r--r--source/blender/blenkernel/intern/node.c22
-rw-r--r--source/blender/blenkernel/intern/object.c17
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c2
-rw-r--r--source/blender/blenkernel/intern/paint.c1
-rw-r--r--source/blender/blenkernel/intern/sequencer.c58
-rw-r--r--source/blender/blenkernel/intern/simulation.cc19
-rw-r--r--source/blender/blenlib/BLI_float3.hh11
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh16
-rw-r--r--source/blender/blenlib/BLI_multi_value_map.hh134
-rw-r--r--source/blender/blenlib/BLI_rand.hh38
-rw-r--r--source/blender/blenlib/BLI_resource_collector.hh6
-rw-r--r--source/blender/blenlib/BLI_span.hh71
-rw-r--r--source/blender/blenlib/BLI_utildefines.h37
-rw-r--r--source/blender/blenlib/BLI_vector.hh2
-rw-r--r--source/blender/blenlib/BLI_vector_adaptor.hh105
-rw-r--r--source/blender/blenlib/CMakeLists.txt27
-rw-r--r--source/blender/blenlib/tests/BLI_array_test.cc (renamed from tests/gtests/blenlib/BLI_array_test.cc)10
-rw-r--r--source/blender/blenlib/tests/BLI_disjoint_set_test.cc (renamed from tests/gtests/blenlib/BLI_disjoint_set_test.cc)4
-rw-r--r--source/blender/blenlib/tests/BLI_edgehash_test.cc (renamed from tests/gtests/blenlib/BLI_edgehash_test.cc)8
-rw-r--r--source/blender/blenlib/tests/BLI_index_mask_test.cc (renamed from tests/gtests/blenlib/BLI_index_mask_test.cc)4
-rw-r--r--source/blender/blenlib/tests/BLI_index_range_test.cc (renamed from tests/gtests/blenlib/BLI_index_range_test.cc)4
-rw-r--r--source/blender/blenlib/tests/BLI_linear_allocator_test.cc (renamed from tests/gtests/blenlib/BLI_linear_allocator_test.cc)4
-rw-r--r--source/blender/blenlib/tests/BLI_map_test.cc (renamed from tests/gtests/blenlib/BLI_map_test.cc)10
-rw-r--r--source/blender/blenlib/tests/BLI_math_base_safe_test.cc (renamed from tests/gtests/blenlib/BLI_math_base_safe_test.cc)0
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc (renamed from tests/gtests/blenlib/BLI_memory_utils_test.cc)6
-rw-r--r--source/blender/blenlib/tests/BLI_multi_value_map_test.cc109
-rw-r--r--source/blender/blenlib/tests/BLI_set_test.cc (renamed from tests/gtests/blenlib/BLI_set_test.cc)25
-rw-r--r--source/blender/blenlib/tests/BLI_span_test.cc (renamed from tests/gtests/blenlib/BLI_span_test.cc)17
-rw-r--r--source/blender/blenlib/tests/BLI_stack_cxx_test.cc (renamed from tests/gtests/blenlib/BLI_stack_cxx_test.cc)8
-rw-r--r--source/blender/blenlib/tests/BLI_string_ref_test.cc (renamed from tests/gtests/blenlib/BLI_string_ref_test.cc)4
-rw-r--r--source/blender/blenlib/tests/BLI_vector_set_test.cc (renamed from tests/gtests/blenlib/BLI_vector_set_test.cc)8
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc (renamed from tests/gtests/blenlib/BLI_vector_test.cc)16
-rw-r--r--source/blender/blenloader/intern/readfile.c14
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c2
-rw-r--r--source/blender/blenloader/intern/writefile.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c2
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cpp18
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.h4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc77
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc1
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc5
-rw-r--r--source/blender/draw/CMakeLists.txt17
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c36
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c38
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c156
-rw-r--r--source/blender/draw/engines/eevee/eevee_lut_gen.c28
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c119
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c16
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c36
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c19
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h17
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c10
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c24
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c465
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c25
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c38
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c111
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/background_vert.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl877
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl11
-rw-r--r--source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_lib.glsl181
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl (renamed from source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl)42
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl65
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl51
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl12
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl38
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl29
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl57
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl20
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl95
-rw-r--r--source/blender/draw/engines/eevee/shaders/lookdev_world_frag.glsl (renamed from source/blender/draw/engines/eevee/shaders/default_world_frag.glsl)43
-rw-r--r--source/blender/draw/engines/eevee/shaders/ltc_lib.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl11
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl43
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl12
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl36
-rw-r--r--source/blender/draw/engines/eevee/shaders/ssr_lib.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_frag.glsl89
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_geom.glsl46
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl43
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl (renamed from source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl)33
-rw-r--r--source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl22
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c8
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c8
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c4
-rw-r--r--source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl13
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_vert.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl28
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl10
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c6
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.c4
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c13
-rw-r--r--source/blender/draw/intern/DRW_render.h17
-rw-r--r--source/blender/draw/intern/draw_cache_impl_pointcloud.c7
-rw-r--r--source/blender/draw/intern/draw_common.h18
-rw-r--r--source/blender/draw/intern/draw_fluid.c (renamed from source/blender/gpu/intern/gpu_draw_smoke.c)40
-rw-r--r--source/blender/draw/intern/draw_manager_data.c20
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c10
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c12
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c2
-rw-r--r--source/blender/draw/intern/draw_view.c3
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl22
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl107
-rw-r--r--source/blender/editors/curve/editfont.c28
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c1
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c148
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c29
-rw-r--r--source/blender/editors/include/BIF_glutil.h30
-rw-r--r--source/blender/editors/include/ED_buttons.h4
-rw-r--r--source/blender/editors/include/ED_numinput.h8
-rw-r--r--source/blender/editors/include/UI_interface.h6
-rw-r--r--source/blender/editors/interface/interface.c53
-rw-r--r--source/blender/editors/interface/interface_context_menu.c2
-rw-r--r--source/blender/editors/interface/interface_draw.c14
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c6
-rw-r--r--source/blender/editors/interface/interface_icons.c14
-rw-r--r--source/blender/editors/interface/interface_intern.h16
-rw-r--r--source/blender/editors/interface/interface_layout.c10
-rw-r--r--source/blender/editors/interface/interface_query.c2
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c10
-rw-r--r--source/blender/editors/interface/interface_widgets.c16
-rw-r--r--source/blender/editors/mask/mask_draw.c3
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c4
-rw-r--r--source/blender/editors/mesh/editmesh_select.c4
-rw-r--r--source/blender/editors/object/object_bake.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c4
-rw-r--r--source/blender/editors/object/object_remesh.c1
-rw-r--r--source/blender/editors/render/render_opengl.c3
-rw-r--r--source/blender/editors/render/render_preview.c15
-rw-r--r--source/blender/editors/screen/glutil.c133
-rw-r--r--source/blender/editors/screen/screen_context.c1
-rw-r--r--source/blender/editors/screen/screen_draw.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c11
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c174
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c132
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c44
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c95
-rw-r--r--source/blender/editors/space_clip/clip_draw.c6
-rw-r--r--source/blender/editors/space_clip/space_clip.c1
-rw-r--r--source/blender/editors/space_file/file_draw.c5
-rw-r--r--source/blender/editors/space_image/image_draw.c34
-rw-r--r--source/blender/editors/space_image/image_ops.c5
-rw-r--r--source/blender/editors/space_image/image_undo.c7
-rw-r--r--source/blender/editors/space_node/drawnode.c9
-rw-r--r--source/blender/editors/space_node/node_draw.c5
-rw-r--r--source/blender/editors/space_node/node_edit.c4
-rw-r--r--source/blender/editors/space_node/node_relationships.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c121
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c1
-rw-r--r--source/blender/editors/transform/transform.h1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c6
-rw-r--r--source/blender/editors/transform/transform_snap.c30
-rw-r--r--source/blender/editors/util/numinput.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h1
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c436
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Id.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Operators.cpp8
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp8
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp3
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp3
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp6
-rw-r--r--source/blender/functions/CMakeLists.txt17
-rw-r--r--source/blender/functions/FN_array_spans.hh2
-rw-r--r--source/blender/functions/FN_attributes_ref.hh6
-rw-r--r--source/blender/functions/FN_cpp_type.hh16
-rw-r--r--source/blender/functions/FN_multi_function_params.hh46
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh7
-rw-r--r--source/blender/functions/FN_spans.hh68
-rw-r--r--source/blender/functions/intern/attributes_ref.cc11
-rw-r--r--source/blender/functions/intern/multi_function_builder.cc4
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc20
-rw-r--r--source/blender/functions/intern/multi_function_network_optimization.cc15
-rw-r--r--source/blender/functions/tests/FN_array_spans_test.cc (renamed from tests/gtests/functions/FN_array_spans_test.cc)4
-rw-r--r--source/blender/functions/tests/FN_attributes_ref_test.cc (renamed from tests/gtests/functions/FN_attributes_ref_test.cc)12
-rw-r--r--source/blender/functions/tests/FN_cpp_type_test.cc (renamed from tests/gtests/functions/FN_cpp_type_test.cc)12
-rw-r--r--source/blender/functions/tests/FN_generic_vector_array_test.cc (renamed from tests/gtests/functions/FN_generic_vector_array_test.cc)4
-rw-r--r--source/blender/functions/tests/FN_multi_function_network_test.cc (renamed from tests/gtests/functions/FN_multi_function_network_test.cc)4
-rw-r--r--source/blender/functions/tests/FN_multi_function_test.cc (renamed from tests/gtests/functions/FN_multi_function_test.cc)4
-rw-r--r--source/blender/functions/tests/FN_spans_test.cc (renamed from tests/gtests/functions/FN_spans_test.cc)12
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c8
-rw-r--r--source/blender/gpu/CMakeLists.txt36
-rw-r--r--source/blender/gpu/GPU_batch.h5
-rw-r--r--source/blender/gpu/GPU_debug.h2
-rw-r--r--source/blender/gpu/GPU_draw.h95
-rw-r--r--source/blender/gpu/GPU_extensions.h2
-rw-r--r--source/blender/gpu/GPU_framebuffer.h20
-rw-r--r--source/blender/gpu/GPU_immediate.h4
-rw-r--r--source/blender/gpu/GPU_material.h11
-rw-r--r--source/blender/gpu/GPU_platform.h11
-rw-r--r--source/blender/gpu/GPU_shader.h2
-rw-r--r--source/blender/gpu/GPU_state.h1
-rw-r--r--source/blender/gpu/GPU_texture.h27
-rw-r--r--source/blender/gpu/GPU_uniformbuffer.h3
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h6
-rw-r--r--source/blender/gpu/GPU_vertex_format.h10
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding.cc (renamed from source/blender/gpu/intern/gpu_attr_binding.c)0
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding_private.h9
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc (renamed from source/blender/gpu/intern/gpu_batch.c)74
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c512
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h8
-rw-r--r--source/blender/gpu/intern/gpu_context.cc (renamed from source/blender/gpu/intern/gpu_context.cpp)0
-rw-r--r--source/blender/gpu/intern/gpu_debug.cc (renamed from source/blender/gpu/intern/gpu_debug.c)0
-rw-r--r--source/blender/gpu/intern/gpu_draw.c1469
-rw-r--r--source/blender/gpu/intern/gpu_element.cc (renamed from source/blender/gpu/intern/gpu_element.c)24
-rw-r--r--source/blender/gpu/intern/gpu_extensions.cc (renamed from source/blender/gpu/intern/gpu_extensions.c)16
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc (renamed from source/blender/gpu/intern/gpu_framebuffer.c)89
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc (renamed from source/blender/gpu/intern/gpu_immediate.c)47
-rw-r--r--source/blender/gpu/intern/gpu_material.c8
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h1
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc (renamed from source/blender/gpu/intern/gpu_platform.c)0
-rw-r--r--source/blender/gpu/intern/gpu_primitive.c29
-rw-r--r--source/blender/gpu/intern/gpu_primitive_private.h9
-rw-r--r--source/blender/gpu/intern/gpu_private.h8
-rw-r--r--source/blender/gpu/intern/gpu_select.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc839
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c (renamed from source/blender/gpu/intern/gpu_shader.c)727
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.h11
-rw-r--r--source/blender/gpu/intern/gpu_state.cc (renamed from source/blender/gpu/intern/gpu_state.c)72
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc (renamed from source/blender/gpu/intern/gpu_texture.c)370
-rw-r--r--source/blender/gpu/intern/gpu_uniformbuffer.cc (renamed from source/blender/gpu/intern/gpu_uniformbuffer.c)308
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc (renamed from source/blender/gpu/intern/gpu_vertex_buffer.c)25
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc (renamed from source/blender/gpu/intern/gpu_vertex_format.c)52
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format_private.h9
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl87
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl2
-rw-r--r--source/blender/imbuf/CMakeLists.txt2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h25
-rw-r--r--source/blender/imbuf/intern/util_gpu.c261
-rw-r--r--source/blender/makesdna/DNA_brush_types.h14
-rw-r--r--source/blender/makesdna/DNA_curve_types.h9
-rw-r--r--source/blender/makesdna/DNA_curveprofile_types.h2
-rw-r--r--source/blender/makesdna/DNA_image_types.h18
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h4
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h36
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h2
-rw-r--r--source/blender/makesdna/intern/dna_utils.c4
-rw-r--r--source/blender/makesdna/intern/makesdna.c15
-rw-r--r--source/blender/makesrna/intern/rna_brush.c23
-rw-r--r--source/blender/makesrna/intern/rna_curve.c4
-rw-r--r--source/blender/makesrna/intern/rna_image.c7
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c15
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c15
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_space.c97
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c10
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc7
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh10
-rw-r--r--source/blender/nodes/NOD_node_tree_dependencies.hh79
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh11
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc2
-rw-r--r--source/blender/nodes/intern/node_socket.cc6
-rw-r--r--source/blender/nodes/intern/node_tree_dependencies.cc57
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc (renamed from source/blender/nodes/shader/nodes/node_shader_clamp.c)25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wireframe.c1
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc2
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc3
-rw-r--r--source/blender/python/BPY_extern.h8
-rw-r--r--source/blender/python/generic/py_capi_utils.c42
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c7
-rw-r--r--source/blender/python/intern/bpy_app_translations.c8
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c39
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h2
-rw-r--r--source/blender/python/intern/bpy_driver.c19
-rw-r--r--source/blender/python/intern/bpy_interface.c49
-rw-r--r--source/blender/simulation/CMakeLists.txt4
-rw-r--r--source/blender/simulation/SIM_simulation_update.hh4
-rw-r--r--source/blender/simulation/intern/particle_allocator.cc11
-rw-r--r--source/blender/simulation/intern/particle_allocator.hh5
-rw-r--r--source/blender/simulation/intern/particle_function.cc28
-rw-r--r--source/blender/simulation/intern/particle_function.hh15
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.cc352
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.hh49
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.cc762
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.hh2
-rw-r--r--source/blender/simulation/intern/simulation_solver.cc231
-rw-r--r--source/blender/simulation/intern/simulation_solver.hh247
-rw-r--r--source/blender/simulation/intern/simulation_solver_influences.cc53
-rw-r--r--source/blender/simulation/intern/simulation_solver_influences.hh194
-rw-r--r--source/blender/simulation/intern/simulation_update.cc233
-rw-r--r--source/blender/simulation/intern/time_interval.hh40
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c1
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c7
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c6
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c3
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c14
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c9
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c5
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c1
-rw-r--r--source/blender/windowmanager/wm_draw.h2
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c4
-rw-r--r--tests/gtests/CMakeLists.txt1
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt15
-rw-r--r--tests/gtests/functions/CMakeLists.txt45
-rw-r--r--tests/gtests/runner/CMakeLists.txt19
423 files changed, 9467 insertions, 8796 deletions
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 708efc3d2f7..af9fb92e3ad 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -169,6 +169,26 @@ function(blender_include_dirs_sys
include_directories(SYSTEM ${_ALL_INCS})
endfunction()
+# Set include paths for header files included with "*.h" syntax.
+# This enables auto-complete suggestions for user header files on Xcode.
+# Build process is not affected since the include paths are the same
+# as in HEADER_SEARCH_PATHS.
+function(blender_user_header_search_paths
+ name
+ includes
+ )
+
+ if(XCODE)
+ set(_ALL_INCS "")
+ foreach(_INC ${includes})
+ get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
+ # _ALL_INCS is a space-separated string of file paths in quotes.
+ set(_ALL_INCS "${_ALL_INCS} \"${_ABS_INC}\"")
+ endforeach()
+ set_target_properties(${name} PROPERTIES XCODE_ATTRIBUTE_USER_HEADER_SEARCH_PATHS "${_ALL_INCS}")
+ endif()
+endfunction()
+
function(blender_source_group
name
sources
@@ -317,6 +337,7 @@ function(blender_add_lib__impl
# works fine without having the includes
# listed is helpful for IDE's (QtCreator/MSVC)
blender_source_group("${name}" "${sources}")
+ blender_user_header_search_paths("${name}" "${includes}")
list_assert_duplicates("${sources}")
list_assert_duplicates("${includes}")
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 1e430823b10..6e4a087fa36 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "V2.90"
+PROJECT_NUMBER = "V2.91"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c
index f477ec48a18..7a1b0018a24 100644
--- a/extern/cuew/src/cuew.c
+++ b/extern/cuew/src/cuew.c
@@ -879,7 +879,7 @@ int cuewCompilerVersion(void) {
}
/* get --version output */
- strncat(command, "\"", 1);
+ strcat(command, "\"");
strncat(command, path, sizeof(command) - 1);
strncat(command, "\" --version", sizeof(command) - strlen(path) - 1);
pipe = popen(command, "r");
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index 43416f734c5..ab81227ff1a 100644
--- a/intern/opencolorio/ocio_impl_glsl.cc
+++ b/intern/opencolorio/ocio_impl_glsl.cc
@@ -47,6 +47,7 @@
extern "C" {
#include "GPU_immediate.h"
+#include "GPU_shader.h"
}
using namespace OCIO_NAMESPACE;
@@ -94,18 +95,15 @@ struct OCIO_GLSLCurveMappingParameters {
struct OCIO_GLSLShader {
/** Cache IDs */
std::string cacheId;
- /** TODO(fclem): Remove. IMM shader interface. */
- struct GPUShaderInterface *interface;
- /** OpenGL Shader objects handles. */
- GLuint frag;
- GLuint vert;
- GLuint program;
+
+ struct GPUShader *shader;
/** Uniform locations. */
GLint dither_loc;
GLint overlay_loc;
GLint overlay_tex_loc;
GLint predivide_loc;
GLint curve_mapping_loc;
+ GLint ubo_bind;
/** Error checking. */
bool valid;
};
@@ -152,56 +150,6 @@ static OCIO_GLSLDrawState *allocateOpenGLState(void)
/** \name Shader
* \{ */
-static GLuint compileShaderText(GLenum shader_type, const char *text)
-{
- GLuint shader;
- GLint stat;
-
- shader = glCreateShader(shader_type);
- glShaderSource(shader, 1, (const GLchar **)&text, NULL);
- glCompileShader(shader);
- glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
-
- if (!stat) {
- GLchar log[1000];
- GLsizei len;
- glGetShaderInfoLog(shader, 1000, &len, log);
- fprintf(stderr, "Shader compile error:\n%s\n", log);
- return 0;
- }
-
- return shader;
-}
-
-static GLuint linkShaders(GLuint frag, GLuint vert)
-{
- if (!frag || !vert) {
- return 0;
- }
-
- GLuint program = glCreateProgram();
-
- glAttachShader(program, frag);
- glAttachShader(program, vert);
-
- glLinkProgram(program);
-
- /* check link */
- {
- GLint stat;
- glGetProgramiv(program, GL_LINK_STATUS, &stat);
- if (!stat) {
- GLchar log[1000];
- GLsizei len;
- glGetProgramInfoLog(program, 1000, &len, log);
- fprintf(stderr, "Shader link error:\n%s\n", log);
- return 0;
- }
- }
-
- return program;
-}
-
static void updateGLSLShader(OCIO_GLSLShader *shader,
ConstProcessorRcPtr *processor_scene_to_ui,
ConstProcessorRcPtr *processpr_ui_to_display,
@@ -213,28 +161,14 @@ static void updateGLSLShader(OCIO_GLSLShader *shader,
}
/* Delete any previous shader. */
- glDeleteProgram(shader->program);
- glDeleteShader(shader->frag);
- glDeleteShader(shader->vert);
-
- if (shader->interface) {
- GPU_shaderinterface_discard(shader->interface);
+ if (shader->shader) {
+ GPU_shader_free(shader->shader);
}
- {
- /* Vertex shader */
- std::ostringstream osv;
-
- osv << "#version 330\n";
- osv << datatoc_gpu_shader_display_transform_vertex_glsl;
-
- shader->vert = compileShaderText(GL_VERTEX_SHADER, osv.str().c_str());
- }
+ std::ostringstream os;
{
/* Fragment shader */
- std::ostringstream os;
- os << "#version 330\n";
/* Work around OpenColorIO not supporting latest GLSL yet. */
os << "#define texture2D texture\n";
os << "#define texture3D texture\n";
@@ -246,41 +180,36 @@ static void updateGLSLShader(OCIO_GLSLShader *shader,
os << (*processpr_ui_to_display)->getGpuShaderText(*shader_desc) << "\n";
os << datatoc_gpu_shader_display_transform_glsl;
-
- shader->frag = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
}
- /* shader_Program */
- if (shader->frag && shader->vert) {
- shader->program = linkShaders(shader->frag, shader->vert);
- }
+ shader->shader = GPU_shader_create(datatoc_gpu_shader_display_transform_vertex_glsl,
+ os.str().c_str(),
+ NULL,
+ NULL,
+ NULL,
+ __func__);
- if (shader->program) {
- shader->dither_loc = glGetUniformLocation(shader->program, "dither");
- shader->overlay_tex_loc = glGetUniformLocation(shader->program, "overlay_texture");
- shader->overlay_loc = glGetUniformLocation(shader->program, "overlay");
- shader->predivide_loc = glGetUniformLocation(shader->program, "predivide");
- shader->curve_mapping_loc = glGetUniformLocation(shader->program, "curve_mapping");
+ if (shader->shader) {
+ shader->dither_loc = GPU_shader_get_uniform(shader->shader, "dither");
+ shader->overlay_tex_loc = GPU_shader_get_uniform(shader->shader, "overlay_texture");
+ shader->overlay_loc = GPU_shader_get_uniform(shader->shader, "overlay");
+ shader->predivide_loc = GPU_shader_get_uniform(shader->shader, "predivide");
+ shader->curve_mapping_loc = GPU_shader_get_uniform(shader->shader, "curve_mapping");
+ shader->ubo_bind = GPU_shader_get_uniform_block_binding(shader->shader,
+ "OCIO_GLSLCurveMappingParameters");
- glUseProgram(shader->program);
-
- /* TODO(fclem) Remove this. Make caller always assume viewport space and
- * specify texco via vertex attribs. */
- shader->interface = GPU_shaderinterface_create(shader->program);
-
- /* Set UBO binding location. */
- GLuint index = glGetUniformBlockIndex(shader->program, "OCIO_GLSLCurveMappingParameters");
- glUniformBlockBinding(shader->program, index, UBO_BIND_LOC);
+ GPU_shader_bind(shader->shader);
/* Set texture bind point uniform once. This is saved by the shader. */
- glUniform1i(glGetUniformLocation(shader->program, "image_texture"), 0);
- glUniform1i(glGetUniformLocation(shader->program, "lut3d_texture"), 2);
- glUniform1i(glGetUniformLocation(shader->program, "lut3d_display_texture"), 3);
- glUniform1i(glGetUniformLocation(shader->program, "curve_mapping_texture"), 4);
+ GPUShader *sh = shader->shader;
+ GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "image_texture"), 0);
+ GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "lut3d_texture"), 2);
+ GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "lut3d_display_texture"), 3);
+ GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "curve_mapping_texture"), 4);
}
shader->cacheId = cache_id;
- shader->valid = (shader->program != 0);
+ shader->valid = (shader->shader != NULL);
}
static void ensureGLSLShader(OCIO_GLSLShader **shader_ptr,
@@ -302,12 +231,8 @@ static void ensureGLSLShader(OCIO_GLSLShader **shader_ptr,
static void freeGLSLShader(OCIO_GLSLShader *shader)
{
- glDeleteProgram(shader->program);
- glDeleteShader(shader->frag);
- glDeleteShader(shader->vert);
-
- if (shader->interface) {
- GPU_shaderinterface_discard(shader->interface);
+ if (shader->shader) {
+ GPU_shader_free(shader->shader);
}
OBJECT_GUARDED_DELETE(shader, OCIO_GLSLShader);
@@ -674,10 +599,10 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r,
glActiveTexture(GL_TEXTURE0);
/* Bind UBO. */
- glBindBufferBase(GL_UNIFORM_BUFFER, 0, shader_curvemap->buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, shader->ubo_bind, shader_curvemap->buffer);
/* TODO(fclem) remove remains of IMM. */
- immBindProgram(shader->program, shader->interface);
+ immBindShader(shader->shader);
/* Bind Shader and set uniforms. */
// glUseProgram(shader->program);
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index fbdb226ab6d..df1be29f642 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -109,7 +109,7 @@ const UserDef U_default = {
.keyconfigstr = "blender",
.undosteps = 32,
.undomemory = 0,
- .gp_manhattendist = 1,
+ .gp_manhattandist = 1,
.gp_euclideandist = 2,
.gp_eraser = 25,
.gp_settings = 0,
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index c39a7afcff9..c927cc184a3 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -46,7 +46,6 @@ _modules = [
"userpref",
"uvcalc_follow_active",
"uvcalc_lightmap",
- "uvcalc_smart_project",
"vertexpaint_dirt",
"view3d",
"gpencil_mesh_bake",
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 311631ac65f..d0344b88be8 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -561,9 +561,61 @@ class QuickLiquid(Operator):
return {'FINISHED'}
+class QuickParticles(Operator):
+ """Use active object as particle emitter"""
+ bl_idname = "object.quick_particles"
+ bl_label = "Quick Particles"
+
+ @classmethod
+ def poll(cls, context):
+ if not context.preferences.experimental.use_new_particle_system:
+ return False
+ if context.mode != 'OBJECT':
+ return False
+ if context.active_object is None:
+ return False
+ if context.active_object.type != 'MESH':
+ return False
+ return True
+
+ def execute(self, context):
+ pointcloud = bpy.data.pointclouds.new("Particles")
+ pointcloud_object = bpy.data.objects.new("Particles", pointcloud)
+ modifier = pointcloud_object.modifiers.new("Simulation", 'SIMULATION')
+ simulation = bpy.data.simulations.new("Particle Simulation")
+ tree = simulation.node_tree
+
+ default_name = "Particles"
+ particle_simulation_node = tree.nodes.new('SimulationNodeParticleSimulation')
+ particle_simulation_node.name = default_name
+ emitter_node = tree.nodes.new('SimulationNodeParticleMeshEmitter')
+ emitter_node.location.x -= 200
+ emitter_node.location.y += 50
+ emitter_node.inputs["Object"].default_value = context.active_object
+ force_node = tree.nodes.new('SimulationNodeForce')
+ force_node.location.x -= 200
+ force_node.location.y -= 100
+ force_node.inputs["Force"].default_value = (0, 0, -1)
+
+ tree.links.new(particle_simulation_node.inputs["Emitters"], emitter_node.outputs["Emitter"])
+ tree.links.new(particle_simulation_node.inputs["Forces"], force_node.outputs["Force"])
+
+ modifier.simulation = simulation
+ modifier.data_path = default_name
+
+ for obj in context.selected_objects:
+ obj.select_set(False)
+
+ context.collection.objects.link(pointcloud_object)
+ pointcloud_object.select_set(True)
+ context.view_layer.objects.active = pointcloud_object
+ pointcloud_object.show_bounds = True
+ return {'FINISHED'}
+
classes = (
QuickExplode,
QuickFur,
QuickSmoke,
QuickLiquid,
+ QuickParticles,
)
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 2e14df1920f..e92f493960a 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -119,8 +119,11 @@ class PREFERENCES_OT_copy_prev(Operator):
# Find config folder from previous version.
import os
version = bpy.app.version
+ version_new = ((version[0] * 100) + version[1])
version_old = ((version[0] * 100) + version[1]) - 1
- while version_old % 10 > 0:
+ # Ensure we only try to copy files from a point release.
+ # The check below ensures the second numbers match.
+ while (version_new % 100) // 10 == (version_old % 100) // 10:
version_split = version_old // 100, version_old % 100
if os.path.isdir(cls._old_version_path(version_split)):
return version_split
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
deleted file mode 100644
index 1f56cbe6d57..00000000000
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ /dev/null
@@ -1,1053 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# TODO <pep8 compliant>
-
-from mathutils import (
- Matrix,
- Vector,
- geometry,
-)
-import bpy
-from bpy.types import Operator
-
-DEG_TO_RAD = 0.017453292519943295 # pi/180.0
-# see bugs:
-# - T31598 (when too small).
-# - T48086 (when too big).
-SMALL_NUM = 1e-12
-
-
-global USER_FILL_HOLES
-global USER_FILL_HOLES_QUALITY
-USER_FILL_HOLES = None
-USER_FILL_HOLES_QUALITY = None
-
-
-def pointInTri2D(v, v1, v2, v3):
- key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y
-
- # Commented because its slower to do the bounds check, we should really cache the bounds info for each face.
- '''
- # BOUNDS CHECK
- xmin= 1000000
- ymin= 1000000
-
- xmax= -1000000
- ymax= -1000000
-
- for i in (0,2,4):
- x= key[i]
- y= key[i+1]
-
- if xmax<x: xmax= x
- if ymax<y: ymax= y
- if xmin>x: xmin= x
- if ymin>y: ymin= y
-
- x= v.x
- y= v.y
-
- if x<xmin or x>xmax or y < ymin or y > ymax:
- return False
- # Done with bounds check
- '''
- try:
- mtx = dict_matrix[key]
- if not mtx:
- return False
- except:
- side1 = v2 - v1
- side2 = v3 - v1
-
- nor = side1.cross(side2)
-
- mtx = Matrix((side1, side2, nor))
-
- # Zero area 2d tri, even tho we throw away zero area faces
- # the projection UV can result in a zero area UV.
- if not mtx.determinant():
- dict_matrix[key] = None
- return False
-
- mtx.invert()
-
- dict_matrix[key] = mtx
-
- uvw = (v - v1) @ mtx
- return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1
-
-
-def boundsIsland(faces):
- minx = maxx = faces[0].uv[0][0] # Set initial bounds.
- miny = maxy = faces[0].uv[0][1]
- # print len(faces), minx, maxx, miny , maxy
- for f in faces:
- for uv in f.uv:
- x = uv.x
- y = uv.y
- if x < minx:
- minx = x
- if y < miny:
- miny = y
- if x > maxx:
- maxx = x
- if y > maxy:
- maxy = y
-
- return minx, miny, maxx, maxy
-
-
-"""
-def boundsEdgeLoop(edges):
- minx = maxx = edges[0][0] # Set initial bounds.
- miny = maxy = edges[0][1]
- # print len(faces), minx, maxx, miny , maxy
- for ed in edges:
- for pt in ed:
- x= pt[0]
- y= pt[1]
- if x<minx: x= minx
- if y<miny: y= miny
- if x>maxx: x= maxx
- if y>maxy: y= maxy
-
- return minx, miny, maxx, maxy
-"""
-
-# Turns the islands into a list of unpordered edges (Non internal)
-# Only for UV's
-# only returns outline edges for intersection tests. and unique points.
-
-
-def island2Edge(island):
-
- # Vert index edges
- edges = {}
-
- unique_points = {}
-
- for f in island:
- f_uvkey = list(map(tuple, f.uv))
-
- for vIdx in range(len(f_uvkey)):
- unique_points[f_uvkey[vIdx]] = f.uv[vIdx]
-
- if f.v[vIdx].index > f.v[vIdx - 1].index:
- i1 = vIdx - 1
- i2 = vIdx
- else:
- i1 = vIdx
- i2 = vIdx - 1
-
- try:
- edges[f_uvkey[i1], f_uvkey[i2]] *= 0 # sets any edge with more than 1 user to 0 are not returned.
- except:
- edges[f_uvkey[i1], f_uvkey[i2]] = (f.uv[i1] - f.uv[i2]).length
-
- # If 2 are the same then they will be together, but full [a,b] order is not correct.
-
- # Sort by length
- length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.items() if value != 0]
-
- length_sorted_edges.sort(key=lambda a: -a[2]) # largest first
-
- # Its okay to leave the length in there.
- # for e in length_sorted_edges:
- # e.pop(2)
-
- # return edges and unique points
- return length_sorted_edges, [v.to_3d() for v in unique_points.values()]
-
-
-def pointInIsland(pt, island):
- vec1, vec2, vec3 = Vector(), Vector(), Vector()
- for f in island:
- vec1.x, vec1.y = f.uv[0]
- vec2.x, vec2.y = f.uv[1]
- vec3.x, vec3.y = f.uv[2]
-
- if pointInTri2D(pt, vec1, vec2, vec3):
- return True
-
- if len(f.v) == 4:
- vec1.x, vec1.y = f.uv[0]
- vec2.x, vec2.y = f.uv[2]
- vec3.x, vec3.y = f.uv[3]
- if pointInTri2D(pt, vec1, vec2, vec3):
- return True
- return False
-
-
-# box is (left,bottom, right, top)
-def islandIntersectUvIsland(source, target, SourceOffset):
- # Is 1 point in the box, inside the vertLoops
- edgeLoopsSource = source[6] # Pretend this is offset
- edgeLoopsTarget = target[6]
-
- # Edge intersect test
- for ed in edgeLoopsSource:
- for seg in edgeLoopsTarget:
- i = geometry.intersect_line_line_2d(seg[0],
- seg[1],
- SourceOffset + ed[0],
- SourceOffset + ed[1],
- )
- if i:
- return 1 # LINE INTERSECTION
-
- # 1 test for source being totally inside target
- SourceOffset.resize_3d()
- for pv in source[7]:
- if pointInIsland(pv + SourceOffset, target[0]):
- return 2 # SOURCE INSIDE TARGET
-
- # 2 test for a part of the target being totally inside the source.
- for pv in target[7]:
- if pointInIsland(pv - SourceOffset, source[0]):
- return 3 # PART OF TARGET INSIDE SOURCE.
-
- return 0 # NO INTERSECTION
-
-
-def rotate_uvs(uv_points, angle):
-
- if angle != 0.0:
- mat = Matrix.Rotation(angle, 2)
- for uv in uv_points:
- uv[:] = mat @ uv
-
-
-def optiRotateUvIsland(faces):
- uv_points = [uv for f in faces for uv in f.uv]
- angle = geometry.box_fit_2d(uv_points)
-
- if angle != 0.0:
- rotate_uvs(uv_points, angle)
-
- # orient them vertically (could be an option)
- minx, miny, maxx, maxy = boundsIsland(faces)
- w, h = maxx - minx, maxy - miny
- # use epsilon so we don't randomly rotate (almost) perfect squares.
- if h + 0.00001 < w:
- from math import pi
- angle = pi / 2.0
- rotate_uvs(uv_points, angle)
-
-
-# Takes an island list and tries to find concave, hollow areas to pack smaller islands into.
-def mergeUvIslands(islandList):
- global USER_FILL_HOLES
- global USER_FILL_HOLES_QUALITY
-
- # Pack islands to bottom LHS
- # Sync with island
-
- # islandTotFaceArea = [] # A list of floats, each island area
- # islandArea = [] # a list of tuples ( area, w,h)
-
- decoratedIslandList = []
-
- islandIdx = len(islandList)
- while islandIdx:
- islandIdx -= 1
- minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx])
- w, h = maxx - minx, maxy - miny
-
- totFaceArea = 0
- offset = Vector((minx, miny))
- for f in islandList[islandIdx]:
- for uv in f.uv:
- uv -= offset
-
- totFaceArea += f.area
-
- islandBoundsArea = w * h
- efficiency = abs(islandBoundsArea - totFaceArea)
-
- # UV Edge list used for intersections as well as unique points.
- edges, uniqueEdgePoints = island2Edge(islandList[islandIdx])
-
- decoratedIslandList.append([
- islandList[islandIdx],
- totFaceArea,
- efficiency,
- islandBoundsArea,
- w,
- h,
- edges,
- uniqueEdgePoints,
- ])
-
- # Sort by island bounding box area, smallest face area first.
- # no.. chance that to most simple edge loop first.
- decoratedIslandListAreaSort = decoratedIslandList[:]
-
- decoratedIslandListAreaSort.sort(key=lambda A: A[3])
-
- # sort by efficiency, Least Efficient first.
- decoratedIslandListEfficSort = decoratedIslandList[:]
- # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2]))
-
- decoratedIslandListEfficSort.sort(key=lambda A: -A[2])
-
- # ================================================== THESE CAN BE TWEAKED.
- # This is a quality value for the number of tests.
- # from 1 to 4, generic quality value is from 1 to 100
- USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1
-
- # If 100 will test as long as there is enough free space.
- # this is rarely enough, and testing takes a while, so lower quality speeds this up.
-
- # 1 means they have the same quality
- USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY) / 100.0) * 5)
-
- # print 'USER_STEP_QUALITY', USER_STEP_QUALITY
- # print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY
-
- removedCount = 0
-
- areaIslandIdx = 0
- ctrl = Window.Qual.CTRL
- BREAK = False
- while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK:
- sourceIsland = decoratedIslandListAreaSort[areaIslandIdx]
- # Already packed?
- if not sourceIsland[0]:
- areaIslandIdx += 1
- else:
- efficIslandIdx = 0
- while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK:
-
- if Window.GetKeyQualifiers() & ctrl:
- BREAK = True
- break
-
- # Now we have 2 islands, if the efficiency of the islands lowers there's an
- # increasing likely hood that we can fit merge into the bigger UV island.
- # this ensures a tight fit.
-
- # Just use figures we have about user/unused area to see if they might fit.
-
- targetIsland = decoratedIslandListEfficSort[efficIslandIdx]
-
- if sourceIsland[0] == targetIsland[0] or\
- not targetIsland[0] or\
- not sourceIsland[0]:
- pass
- else:
-
- #~ ([island, totFaceArea, efficiency, islandArea, w,h])
- # Wasted space on target is greater then UV bounding island area.
-
- #~ if targetIsland[3] > (sourceIsland[2]) and\ #
- # ~ print USER_FREE_SPACE_TO_TEST_QUALITY
- if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\
- targetIsland[4] > sourceIsland[4] and\
- targetIsland[5] > sourceIsland[5]:
-
- # DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1])
-
- # These enough spare space lets move the box until it fits
-
- # How many times does the source fit into the target x/y
- blockTestXUnit = targetIsland[4] / sourceIsland[4]
- blockTestYUnit = targetIsland[5] / sourceIsland[5]
-
- boxLeft = 0
-
- # Distance we can move between whilst staying inside the targets bounds.
- testWidth = targetIsland[4] - sourceIsland[4]
- testHeight = targetIsland[5] - sourceIsland[5]
-
- # Increment we move each test. x/y
- xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY / 50) + 0.1)))
- yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY / 50) + 0.1)))
-
- # Make sure were not moving less then a 3rg of our width/height
- if xIncrement < sourceIsland[4] / 3:
- xIncrement = sourceIsland[4]
- if yIncrement < sourceIsland[5] / 3:
- yIncrement = sourceIsland[5]
-
- boxLeft = 0 # Start 1 back so we can jump into the loop.
- boxBottom = 0 # -yIncrement
-
- # ~ testcount= 0
-
- while boxBottom <= testHeight:
- # Should we use this? - not needed for now.
- # ~ if Window.GetKeyQualifiers() & ctrl:
- # ~ BREAK= True
- # ~ break
-
- # testcount+=1
- # print 'Testing intersect'
- Intersect = islandIntersectUvIsland(
- sourceIsland, targetIsland, Vector((boxLeft, boxBottom)))
- # print 'Done', Intersect
- if Intersect == 1: # Line intersect, don't bother with this any more
- pass
-
- if Intersect == 2: # Source inside target
- """
- We have an intersection, if we are inside the target
- then move us 1 whole width across,
- Its possible this is a bad idea since 2 skinny Angular faces
- could join without 1 whole move, but its a lot more optimal to speed this up
- since we have already tested for it.
-
- It gives about 10% speedup with minimal errors.
- """
- # Move the test along its width + SMALL_NUM
- #boxLeft += sourceIsland[4] + SMALL_NUM
- boxLeft += sourceIsland[4]
- elif Intersect == 0: # No intersection?? Place it.
- # Progress
- removedCount += 1
-# XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
-
- # Move faces into new island and offset
- targetIsland[0].extend(sourceIsland[0])
- offset = Vector((boxLeft, boxBottom))
-
- for f in sourceIsland[0]:
- for uv in f.uv:
- uv += offset
-
- del sourceIsland[0][:] # Empty
-
- # Move edge loop into new and offset.
- # targetIsland[6].extend(sourceIsland[6])
- # while sourceIsland[6]:
- targetIsland[6].extend([(
- (e[0] + offset, e[1] + offset, e[2])
- ) for e in sourceIsland[6]])
-
- del sourceIsland[6][:] # Empty
-
- # Sort by edge length, reverse so biggest are first.
-
- try:
- targetIsland[6].sort(key=lambda A: A[2])
- except:
- targetIsland[6].sort(lambda B, A: cmp(A[2], B[2]))
-
- targetIsland[7].extend(sourceIsland[7])
- offset = Vector((boxLeft, boxBottom, 0.0))
- for p in sourceIsland[7]:
- p += offset
-
- del sourceIsland[7][:]
-
- # Decrement the efficiency
- targetIsland[1] += sourceIsland[1] # Increment totFaceArea
- targetIsland[2] -= sourceIsland[1] # Decrement efficiency
- # IF we ever used these again, should set to 0, eg
- sourceIsland[2] = 0 # No area if anyone wants to know
-
- break
-
- # INCREMENT NEXT LOCATION
- if boxLeft > testWidth:
- boxBottom += yIncrement
- boxLeft = 0.0
- else:
- boxLeft += xIncrement
- # print testcount
-
- efficIslandIdx += 1
- areaIslandIdx += 1
-
- # Remove empty islands
- i = len(islandList)
- while i:
- i -= 1
- if not islandList[i]:
- del islandList[i] # Can increment islands removed here.
-
-# Takes groups of faces. assumes face groups are UV groups.
-
-
-def getUvIslands(faceGroups, me):
-
- # Get seams so we don't cross over seams
- edge_seams = {} # should be a set
- for ed in me.edges:
- if ed.use_seam:
- edge_seams[ed.key] = None # dummy var- use sets!
- # Done finding seams
-
- islandList = []
-
-# XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups))
- # print '\tSplitting %d projection groups into UV islands:' % len(faceGroups),
- # Find grouped faces
-
- faceGroupIdx = len(faceGroups)
-
- while faceGroupIdx:
- faceGroupIdx -= 1
- faces = faceGroups[faceGroupIdx]
-
- if not faces:
- continue
-
- # Build edge dict
- edge_users = {}
-
- for i, f in enumerate(faces):
- for ed_key in f.edge_keys:
- if ed_key in edge_seams: # DELIMIT SEAMS! ;)
- edge_users[ed_key] = [] # so as not to raise an error
- else:
- try:
- edge_users[ed_key].append(i)
- except:
- edge_users[ed_key] = [i]
-
- # Modes
- # 0 - face not yet touched.
- # 1 - added to island list, and need to search
- # 2 - touched and searched - don't touch again.
- face_modes = [0] * len(faces) # initialize zero - untested.
-
- face_modes[0] = 1 # start the search with face 1
-
- newIsland = []
-
- newIsland.append(faces[0])
-
- ok = True
- while ok:
-
- ok = True
- while ok:
- ok = False
- for i in range(len(faces)):
- if face_modes[i] == 1: # search
- for ed_key in faces[i].edge_keys:
- for ii in edge_users[ed_key]:
- if i != ii and face_modes[ii] == 0:
- face_modes[ii] = ok = 1 # mark as searched
- newIsland.append(faces[ii])
-
- # mark as searched, don't look again.
- face_modes[i] = 2
-
- islandList.append(newIsland)
-
- ok = False
- for i in range(len(faces)):
- if face_modes[i] == 0:
- newIsland = []
- newIsland.append(faces[i])
-
- face_modes[i] = ok = 1
- break
- # if not ok will stop looping
-
-# XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
-
- for island in islandList:
- optiRotateUvIsland(island)
-
- return islandList
-
-
-def packIslands(islandList):
- if USER_FILL_HOLES:
- # XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
- mergeUvIslands(islandList) # Modify in place
-
- # Now we have UV islands, we need to pack them.
-
- # Make a synchronized list with the islands
- # so we can box pack the islands.
- packBoxes = []
-
- # Keep a list of X/Y offset so we can save time by writing the
- # uv's and packed data in one pass.
- islandOffsetList = []
-
- islandIdx = 0
-
- while islandIdx < len(islandList):
- minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx])
-
- w, h = maxx - minx, maxy - miny
-
- if USER_ISLAND_MARGIN:
- minx -= USER_ISLAND_MARGIN * w / 2
- miny -= USER_ISLAND_MARGIN * h / 2
- maxx += USER_ISLAND_MARGIN * w / 2
- maxy += USER_ISLAND_MARGIN * h / 2
-
- # recalc width and height
- w, h = maxx - minx, maxy - miny
-
- if w < SMALL_NUM:
- w = SMALL_NUM
- if h < SMALL_NUM:
- h = SMALL_NUM
-
- """Save the offset to be applied later,
- we could apply to the UVs now and align them to the bottom left hand area
- of the UV coords like the box packer imagines they are
- but, its quicker just to remember their offset and
- apply the packing and offset in 1 pass """
- islandOffsetList.append((minx, miny))
-
- # Add to boxList. use the island idx for the BOX id.
- packBoxes.append([0, 0, w, h])
- islandIdx += 1
-
- # Now we have a list of boxes to pack that syncs
- # with the islands.
-
- # print '\tPacking UV Islands...'
-# XXX Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) )
-
- # time1 = time.time()
- packWidth, packHeight = geometry.box_pack_2d(packBoxes)
-
- # print 'Box Packing Time:', time.time() - time1
-
- # if len(packedLs) != len(islandList):
- # raise ValueError("Packed boxes differs from original length")
-
- # print '\tWriting Packed Data to faces'
-# XXX Window.DrawProgressBar(0.8, "Writing Packed Data to faces")
-
- # Sort by ID, so there in sync again
- islandIdx = len(islandList)
- # Having these here avoids divide by 0
- if islandIdx:
-
- if USER_STRETCH_ASPECT:
- # Maximize to uv area?? Will write a normalize function.
- xfactor = 1.0 / packWidth
- yfactor = 1.0 / packHeight
- else:
- # Keep proportions.
- xfactor = yfactor = 1.0 / max(packWidth, packHeight)
-
- while islandIdx:
- islandIdx -= 1
- # Write the packed values to the UV's
-
- xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0]
- yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1]
-
- for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box
- for uv in f.uv:
- uv.x = (uv.x + xoffset) * xfactor
- uv.y = (uv.y + yoffset) * yfactor
-
-
-def VectoQuat(vec):
- vec = vec.normalized()
- return vec.to_track_quat('Z', 'X' if abs(vec.x) > 0.5 else 'Y').inverted()
-
-
-class thickface:
- __slost__ = "v", "uv", "no", "area", "edge_keys"
-
- def __init__(self, face, uv_layer, mesh_verts):
- self.v = [mesh_verts[i] for i in face.vertices]
- self.uv = [uv_layer[i].uv for i in face.loop_indices]
-
- self.no = face.normal.copy()
- self.area = face.area
- self.edge_keys = face.edge_keys
-
-
-def main_consts():
- from math import radians
-
- global ROTMAT_2D_POS_90D
- global ROTMAT_2D_POS_45D
- global RotMatStepRotation
-
- ROTMAT_2D_POS_90D = Matrix.Rotation(radians(90.0), 2)
- ROTMAT_2D_POS_45D = Matrix.Rotation(radians(45.0), 2)
-
- RotMatStepRotation = []
- rot_angle = 22.5 # 45.0/2
- while rot_angle > 0.1:
- RotMatStepRotation.append([
- Matrix.Rotation(radians(+rot_angle), 2),
- Matrix.Rotation(radians(-rot_angle), 2),
- ])
-
- rot_angle = rot_angle / 2.0
-
-
-global ob
-ob = None
-
-
-def main(context,
- island_margin,
- projection_limit,
- user_area_weight,
- use_aspect,
- stretch_to_bounds,
- ):
- global USER_FILL_HOLES
- global USER_FILL_HOLES_QUALITY
- global USER_STRETCH_ASPECT
- global USER_ISLAND_MARGIN
-
- from math import cos
- import time
-
- global dict_matrix
- dict_matrix = {}
-
- # Constants:
- # Takes a list of faces that make up a UV island and rotate
- # until they optimally fit inside a square.
- global ROTMAT_2D_POS_90D
- global ROTMAT_2D_POS_45D
- global RotMatStepRotation
- main_consts()
-
- # Create the variables.
- USER_PROJECTION_LIMIT = projection_limit
- USER_ONLY_SELECTED_FACES = True
- USER_SHARE_SPACE = 1 # Only for hole filling.
- USER_STRETCH_ASPECT = stretch_to_bounds
- USER_ISLAND_MARGIN = island_margin # Only for hole filling.
- USER_FILL_HOLES = 0
- USER_FILL_HOLES_QUALITY = 50 # Only for hole filling.
- USER_VIEW_INIT = 0 # Only for hole filling.
-
- is_editmode = (context.mode == 'EDIT_MESH')
- if is_editmode:
- obList = context.objects_in_mode_unique_data
- else:
- obList = [
- ob for ob in context.selected_editable_objects
- if ob.type == 'MESH' and ob.data.library is None
- ]
-
- if not is_editmode:
- USER_ONLY_SELECTED_FACES = False
-
- if not obList:
- raise Exception("error, no selected mesh objects")
-
- # Convert from being button types
- USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD)
- USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD)
-
- # Toggle Edit mode
- if is_editmode:
- bpy.ops.object.mode_set(mode='OBJECT')
- # Assume face select mode! an annoying hack to toggle face select mode because Mesh doesn't like faceSelectMode.
-
- if USER_SHARE_SPACE:
- # Sort by data name so we get consistent results
- obList.sort(key=lambda ob: ob.data.name)
- collected_islandList = []
-
- time1 = time.time()
-
- # Tag as False so we don't operate on the same mesh twice.
- for me in bpy.data.meshes:
- me.tag = False
-
- for ob in obList:
- me = ob.data
-
- if me.tag or me.library:
- continue
-
- # Tag as used
- me.tag = True
-
- if not me.uv_layers: # Mesh has no UV Coords, don't bother.
- me.uv_layers.new()
-
- uv_layer = me.uv_layers.active.data
- me_verts = list(me.vertices)
-
- if USER_ONLY_SELECTED_FACES:
- meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select]
- else:
- meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)]
-
- # =======
- # Generate a projection list from face normals, this is meant to be smart :)
-
- # make a list of face props that are in sync with meshFaces
- # Make a Face List that is sorted by area.
- # meshFaces = []
-
- # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first.
- meshFaces.sort(key=lambda a: -a.area)
-
- # remove all zero area faces
- while meshFaces and meshFaces[-1].area <= SMALL_NUM:
- # Set their UV's to 0,0
- for uv in meshFaces[-1].uv:
- uv.zero()
- meshFaces.pop()
-
- if not meshFaces:
- continue
-
- # Smallest first is slightly more efficient,
- # but if the user cancels early then its better we work on the larger data.
-
- # Generate Projection Vecs
- # 0d is 1.0
- # 180 IS -0.59846
-
- # Initialize projectVecs
- if USER_VIEW_INIT:
- # Generate Projection
-
- # We add to this along the way
- projectVecs = [Vector(Window.GetViewVector()) @ ob.matrix_world.inverted().to_3x3()]
- else:
- projectVecs = []
-
- newProjectVec = meshFaces[0].no
- newProjectMeshFaces = [] # Popping stuffs it up.
-
- # Pretend that the most unique angle is ages away to start the loop off
- mostUniqueAngle = -1.0
-
- # This is popped
- tempMeshFaces = meshFaces[:]
-
- # This while only gathers projection vecs, faces are assigned later on.
- while 1:
- # If there's none there then start with the largest face
-
- # add all the faces that are close.
- for fIdx in range(len(tempMeshFaces) - 1, -1, -1):
- # Use half the angle limit so we don't overweight faces towards this
- # normal and hog all the faces.
- if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED:
- newProjectMeshFaces.append(tempMeshFaces.pop(fIdx))
-
- # Add the average of all these faces normals as a projectionVec
- averageVec = Vector((0.0, 0.0, 0.0))
- if user_area_weight == 0.0:
- for fprop in newProjectMeshFaces:
- averageVec += fprop.no
- elif user_area_weight == 1.0:
- for fprop in newProjectMeshFaces:
- averageVec += fprop.no * fprop.area
- else:
- for fprop in newProjectMeshFaces:
- averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight))
-
- if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
- projectVecs.append(averageVec.normalized())
-
- # Get the next vec!
- # Pick the face that's most different to all existing angles :)
- mostUniqueAngle = 1.0 # 1.0 is 0d. no difference.
- mostUniqueIndex = 0 # dummy
-
- for fIdx in range(len(tempMeshFaces) - 1, -1, -1):
- angleDifference = -1.0 # 180d difference.
-
- # Get the closest vec angle we are to.
- for p in projectVecs:
- temp_angle_diff = p.dot(tempMeshFaces[fIdx].no)
-
- if angleDifference < temp_angle_diff:
- angleDifference = temp_angle_diff
-
- if angleDifference < mostUniqueAngle:
- # We have a new most different angle
- mostUniqueIndex = fIdx
- mostUniqueAngle = angleDifference
-
- if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED:
- # print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces)
- # Now weight the vector to all its faces, will give a more direct projection
- # if the face its self was not representative of the normal from surrounding faces.
-
- newProjectVec = tempMeshFaces[mostUniqueIndex].no
- newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)]
-
- else:
- if len(projectVecs) >= 1: # Must have at least 2 projections
- break
-
- # If there are only zero area faces then its possible
- # there are no projectionVecs
- if not len(projectVecs):
- Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.')
- return
-
- faceProjectionGroupList = [[] for i in range(len(projectVecs))]
-
- # MAP and Arrange # We know there are 3 or 4 faces here
-
- for fIdx in range(len(meshFaces) - 1, -1, -1):
- fvec = meshFaces[fIdx].no
- i = len(projectVecs)
-
- # Initialize first
- bestAng = fvec.dot(projectVecs[0])
- bestAngIdx = 0
-
- # Cycle through the remaining, first already done
- while i - 1:
- i -= 1
-
- newAng = fvec.dot(projectVecs[i])
- if newAng > bestAng: # Reverse logic for dotvecs
- bestAng = newAng
- bestAngIdx = i
-
- # Store the area for later use.
- faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx])
-
- # Cull faceProjectionGroupList,
-
- # Now faceProjectionGroupList is full of faces that face match the project Vecs list
- for i in range(len(projectVecs)):
- # Account for projectVecs having no faces.
- if not faceProjectionGroupList[i]:
- continue
-
- # Make a projection matrix from a unit length vector.
- MatQuat = VectoQuat(projectVecs[i])
-
- # Get the faces UV's from the projected vertex.
- for f in faceProjectionGroupList[i]:
- f_uv = f.uv
- for j, v in enumerate(f.v):
- f_uv[j][:] = (MatQuat @ v.co).xy
-
- if USER_SHARE_SPACE:
- # Should we collect and pack later?
- islandList = getUvIslands(faceProjectionGroupList, me)
- collected_islandList.extend(islandList)
-
- else:
- # Should we pack the islands for this 1 object?
- islandList = getUvIslands(faceProjectionGroupList, me)
- packIslands(islandList)
-
- # update the mesh here if we need to.
-
- # We want to pack all in 1 go, so pack now
- if USER_SHARE_SPACE:
- packIslands(collected_islandList)
-
- print("Smart Projection time: %.2f" % (time.time() - time1))
-
- # aspect correction is only done in edit mode - and only smart unwrap supports currently
- if is_editmode:
- bpy.ops.object.mode_set(mode='EDIT')
-
- if use_aspect:
- import bmesh
- aspect = context.scene.uvedit_aspect(context.active_object)
- if aspect[0] > aspect[1]:
- aspect[0] = aspect[1] / aspect[0]
- aspect[1] = 1.0
- else:
- aspect[1] = aspect[0] / aspect[1]
- aspect[0] = 1.0
-
- bm = bmesh.from_edit_mesh(me)
-
- uv_act = bm.loops.layers.uv.active
-
- faces = [f for f in bm.faces if f.select]
-
- for f in faces:
- for l in f.loops:
- l[uv_act].uv[0] *= aspect[0]
- l[uv_act].uv[1] *= aspect[1]
-
- dict_matrix.clear()
-
-
-from bpy.props import FloatProperty, BoolProperty
-
-
-class SmartProject(Operator):
- """This script projection unwraps the selected faces of a mesh """ \
- """(it operates on all selected mesh objects, and can be used """ \
- """to unwrap selected faces, or all faces)"""
- bl_idname = "uv.smart_project"
- bl_label = "Smart UV Project"
- bl_options = {'REGISTER', 'UNDO'}
-
- angle_limit: FloatProperty(
- name="Angle Limit",
- description="Lower for more projection groups, higher for less distortion",
- min=1.0, max=89.0,
- default=66.0,
- )
- island_margin: FloatProperty(
- name="Island Margin",
- description="Margin to reduce bleed from adjacent islands",
- min=0.0, max=1.0,
- default=0.0,
- )
- user_area_weight: FloatProperty(
- name="Area Weight",
- description="Weight projections vector by faces with larger areas",
- min=0.0, max=1.0,
- default=0.0,
- )
- use_aspect: BoolProperty(
- name="Correct Aspect",
- description="Map UVs taking image aspect ratio into account",
- default=True,
- )
- stretch_to_bounds: BoolProperty(
- name="Stretch to UV Bounds",
- description="Stretch the final output to texture bounds",
- default=True,
- )
-
- @classmethod
- def poll(cls, context):
- return context.active_object is not None
-
- def execute(self, context):
- main(context,
- self.island_margin,
- self.angle_limit,
- self.user_area_weight,
- self.use_aspect,
- self.stretch_to_bounds,
- )
- return {'FINISHED'}
-
- def invoke(self, context, _event):
- wm = context.window_manager
- return wm.invoke_props_dialog(self)
-
-
-classes = (
- SmartProject,
-)
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 4d6ddb55f24..f16528103ff 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -405,6 +405,7 @@ class GPENCIL_MT_cleanup(Menu):
layout = self.layout
layout.operator("gpencil.frame_clean_loose", text="Delete Loose Points")
+ layout.operator("gpencil.frame_clean_duplicate", text="Delete Duplicated Frames")
if ob.mode != 'PAINT_GPENCIL':
layout.operator("gpencil.stroke_merge_by_distance", text="Merge by Distance")
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 6dde1e715bb..8cadad7e0d7 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -662,6 +662,7 @@ def brush_settings(layout, context, brush, popover=False):
layout.separator()
layout.prop(brush, "cloth_mass")
layout.prop(brush, "cloth_damping")
+ layout.prop(brush, "cloth_constraint_softbody_strength")
layout.separator()
elif sculpt_tool == 'SCRAPE':
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index e4cecf3378f..83b3a27154a 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -2385,9 +2385,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
'OBJECT': [
*_tools_default,
- # Disable for 2.90 release.
- # None,
- # _tools_view3d_add,
+ None,
+ _tools_view3d_add,
],
'POSE': [
*_tools_default,
@@ -2415,9 +2414,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
],
'EDIT_MESH': [
*_tools_default,
- # Disable for 2.90 release.
- # None,
- # _tools_view3d_add,
+ None,
+ _tools_view3d_add,
None,
(
_defs_edit_mesh.extrude,
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 8880d8c5378..0a1be2dc698 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2751,6 +2751,8 @@ class VIEW3D_MT_object_quick_effects(Menu):
layout.operator("object.quick_explode")
layout.operator("object.quick_smoke")
layout.operator("object.quick_liquid")
+ if _context.preferences.experimental.use_new_particle_system:
+ layout.operator("object.quick_particles")
class VIEW3D_MT_object_showhide(Menu):
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 6e31808d27d..25dc4663500 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1393,6 +1393,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
col = layout.column(align=True)
if brush is not None:
+ col.prop(gp_settings, "brush_draw_mode")
+ col.separator()
+
if brush.gpencil_tool != 'FILL':
col.prop(gp_settings, "input_samples")
col.separator()
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 60eb0194a9a..7321f4f6345 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -475,6 +475,12 @@ texture_node_categories = [
]),
]
+def not_implemented_node(idname):
+ NodeType = getattr(bpy.types, idname)
+ name = NodeType.bl_rna.name
+ label = f"{name} (mockup)"
+ return NodeItem(idname, label=label)
+
simulation_node_categories = [
# Simulation Nodes
SimulationNodeCategory("SIM_OUTPUT", "Output", items=[
@@ -489,12 +495,12 @@ simulation_node_categories = [
]),
SimulationNodeCategory("SIM_EMITTERS", "Emitters", items=[
NodeItem("SimulationNodeParticleMeshEmitter"),
- NodeItem("SimulationNodeEmitParticles"),
+ not_implemented_node("SimulationNodeEmitParticles"),
]),
SimulationNodeCategory("SIM_EVENTS", "Events", items=[
NodeItem("SimulationNodeParticleBirthEvent"),
NodeItem("SimulationNodeParticleTimeStepEvent"),
- NodeItem("SimulationNodeParticleMeshCollisionEvent"),
+ not_implemented_node("SimulationNodeParticleMeshCollisionEvent"),
]),
SimulationNodeCategory("SIM_FORCES", "Forces", items=[
NodeItem("SimulationNodeForce"),
@@ -502,18 +508,18 @@ simulation_node_categories = [
SimulationNodeCategory("SIM_EXECUTE", "Execute", items=[
NodeItem("SimulationNodeSetParticleAttribute"),
NodeItem("SimulationNodeExecuteCondition"),
- NodeItem("SimulationNodeMultiExecute"),
+ not_implemented_node("SimulationNodeMultiExecute"),
]),
SimulationNodeCategory("SIM_NOISE", "Noise", items=[
- NodeItem("ShaderNodeTexNoise"),
- NodeItem("ShaderNodeTexWhiteNoise"),
+ not_implemented_node("ShaderNodeTexNoise"),
+ not_implemented_node("ShaderNodeTexWhiteNoise"),
]),
SimulationNodeCategory("SIM_COLOR", "Color", items=[
- NodeItem("ShaderNodeMixRGB"),
- NodeItem("ShaderNodeInvert"),
- NodeItem("ShaderNodeHueSaturation"),
- NodeItem("ShaderNodeGamma"),
- NodeItem("ShaderNodeBrightContrast"),
+ not_implemented_node("ShaderNodeMixRGB"),
+ not_implemented_node("ShaderNodeInvert"),
+ not_implemented_node("ShaderNodeHueSaturation"),
+ not_implemented_node("ShaderNodeGamma"),
+ not_implemented_node("ShaderNodeBrightContrast"),
]),
SimulationNodeCategory("SIM_CONVERTER", "Converter", items=[
NodeItem("ShaderNodeMapRange"),
@@ -525,11 +531,11 @@ simulation_node_categories = [
NodeItem("ShaderNodeCombineRGB"),
NodeItem("ShaderNodeSeparateXYZ"),
NodeItem("ShaderNodeCombineXYZ"),
- NodeItem("ShaderNodeSeparateHSV"),
- NodeItem("ShaderNodeCombineHSV"),
+ not_implemented_node("ShaderNodeSeparateHSV"),
+ not_implemented_node("ShaderNodeCombineHSV"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeFloatCompare"),
- NodeItem("FunctionNodeSwitch"),
+ not_implemented_node("FunctionNodeSwitch"),
NodeItem("FunctionNodeCombineStrings"),
]),
SimulationNodeCategory("SIM_GROUP", "Group", items=node_group_items),
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 50a8223a84c..ff31878a929 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -194,6 +194,8 @@ static GPUTexture *blf_batch_cache_texture_load(void)
int offset_x = bitmap_len_landed % tex_width;
int offset_y = bitmap_len_landed / tex_width;
+ GPU_texture_bind(gc->texture, 0);
+
/* TODO(germano): Update more than one row in a single call. */
while (remain) {
int remain_row = tex_width - offset_x;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 77d2a973c50..800a3a426b7 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -32,15 +32,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 290
+#define BLENDER_VERSION 291
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 7
+#define BLENDER_FILE_SUBVERSION 0
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 1e5573ab014..c5221baf7d7 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -55,6 +55,7 @@ void BKE_image_free_packedfiles(struct Image *image);
void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
void BKE_image_free_buffers_ex(struct Image *image, bool do_lock);
+void BKE_image_free_gputextures(struct Image *ima);
/* call from library */
void BKE_image_free(struct Image *image);
@@ -274,6 +275,10 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
/* does all images with type MOVIE or SEQUENCE */
void BKE_image_all_free_anim_ibufs(struct Main *bmain, int except_frame);
+void BKE_image_free_all_gputextures(struct Main *bmain);
+void BKE_image_free_anim_gputextures(struct Main *bmain);
+void BKE_image_free_old_gputextures(struct Main *bmain);
+
bool BKE_image_memorypack(struct Image *ima);
void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
void BKE_image_packfiles_from_mem(struct ReportList *reports,
@@ -362,6 +367,30 @@ bool BKE_image_has_loaded_ibuf(struct Image *image);
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
+/* Not to be use directly. */
+struct GPUTexture *BKE_image_create_gpu_texture_from_ibuf(struct Image *image, struct ImBuf *ibuf);
+
+/* Get the GPUTexture for a given `Image`.
+ *
+ * `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
+ * available. It is also required when requesting the GPUTexture for a render result. */
+struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image,
+ struct ImageUser *iuser,
+ struct ImBuf *ibuf);
+struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image,
+ struct ImageUser *iuser,
+ struct ImBuf *ibuf);
+struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image,
+ struct ImageUser *iuser,
+ struct ImBuf *ibuf);
+
+void BKE_image_update_gputexture(
+ struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
+void BKE_image_paint_set_mipmap(struct Main *bmain, bool mipmap);
+
+/* Delayed free of OpenGL buffers by main thread */
+void BKE_image_free_unused_gpu_textures(void);
+
struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name);
bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int slot);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index dbd6eb15bf2..bba01dd84d2 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -113,6 +113,11 @@ bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip,
struct MovieClipUser *user,
struct ImBuf *ibuf);
+struct GPUTexture *BKE_movieclip_get_gpu_texture(struct MovieClip *clip,
+ struct MovieClipUser *cuser);
+
+void BKE_movieclip_free_gputexture(struct MovieClip *clip);
+
/* Dependency graph evaluation. */
void BKE_movieclip_eval_update(struct Depsgraph *depsgraph,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 1c02aece06f..382919147f8 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -260,10 +260,20 @@ typedef struct SculptPoseIKChain {
/* Cloth Brush */
typedef struct SculptClothLengthConstraint {
- int v1;
- int v2;
+ /* Elements that are affected by the constraint. */
+ /* Element a should always be a mesh vertex with the index stored in elem_index_a as it is always
+ * deformed. Element b could be another vertex of the same mesh or any other position (arbitrary
+ * point, position for a previous state). In that case, elem_index_a and elem_index_b should be
+ * the same to avoid affecting two different vertices when solving the constraints.
+ * *elem_position points to the position which is owned by the element. */
+ int elem_index_a;
+ float *elem_position_a;
+
+ int elem_index_b;
+ float *elem_position_b;
float length;
+ float strength;
} SculptClothLengthConstraint;
typedef struct SculptClothSimulation {
@@ -273,6 +283,11 @@ typedef struct SculptClothSimulation {
int capacity_length_constraints;
float *length_constraint_tweak;
+ /* Position anchors for deformation brushes. These positions are modified by the brush and the
+ * final positions of the simulated vertices are updated with constraints that use these points
+ * as targets. */
+ float (*deformation_pos)[3];
+
float mass;
float damping;
diff --git a/source/blender/blenkernel/BKE_persistent_data_handle.hh b/source/blender/blenkernel/BKE_persistent_data_handle.hh
index 721132560e3..884e4c00766 100644
--- a/source/blender/blenkernel/BKE_persistent_data_handle.hh
+++ b/source/blender/blenkernel/BKE_persistent_data_handle.hh
@@ -85,45 +85,45 @@ class PersistentObjectHandle : public PersistentIDHandle {
class PersistentDataHandleMap {
private:
- Map<int32_t, const ID *> id_by_handle_;
- Map<const ID *, int32_t> handle_by_id_;
+ Map<int32_t, ID *> id_by_handle_;
+ Map<ID *, int32_t> handle_by_id_;
public:
- void add(int32_t handle, const ID &id)
+ void add(int32_t handle, ID &id)
{
BLI_assert(handle >= 0);
handle_by_id_.add(&id, handle);
id_by_handle_.add(handle, &id);
}
- PersistentIDHandle lookup(const ID *id) const
+ PersistentIDHandle lookup(ID *id) const
{
const int handle = handle_by_id_.lookup_default(id, -1);
return PersistentIDHandle(handle);
}
- PersistentObjectHandle lookup(const Object *object) const
+ PersistentObjectHandle lookup(Object *object) const
{
- const int handle = handle_by_id_.lookup_default((const ID *)object, -1);
+ const int handle = handle_by_id_.lookup_default((ID *)object, -1);
return PersistentObjectHandle(handle);
}
- const ID *lookup(const PersistentIDHandle &handle) const
+ ID *lookup(const PersistentIDHandle &handle) const
{
- const ID *id = id_by_handle_.lookup_default(handle.handle_, nullptr);
+ ID *id = id_by_handle_.lookup_default(handle.handle_, nullptr);
return id;
}
- const Object *lookup(const PersistentObjectHandle &handle) const
+ Object *lookup(const PersistentObjectHandle &handle) const
{
- const ID *id = this->lookup((const PersistentIDHandle &)handle);
+ ID *id = this->lookup((const PersistentIDHandle &)handle);
if (id == nullptr) {
return nullptr;
}
if (GS(id->name) != ID_OB) {
return nullptr;
}
- return (const Object *)id;
+ return (Object *)id;
}
};
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index c32abbb41c6..2873a13d1f7 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -625,6 +625,10 @@ void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb,
void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int cfra);
bool BKE_sequencer_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
bool BKE_sequencer_render_loop_check(struct Sequence *seq_main, struct Sequence *seq);
+void BKE_sequencer_flag_for_removal(struct Scene *scene,
+ struct ListBase *seqbase,
+ struct Sequence *seq);
+void BKE_sequencer_remove_flagged_sequences(struct Scene *scene, struct ListBase *seqbase);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h
index 5aa71b6381d..6cbe77e8de3 100644
--- a/source/blender/blenkernel/BKE_simulation.h
+++ b/source/blender/blenkernel/BKE_simulation.h
@@ -32,6 +32,7 @@ void *BKE_simulation_add(struct Main *bmain, const char *name);
void BKE_simulation_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Simulation *simulation);
+void BKE_simulation_update_dependencies(struct Simulation *simulation, struct Main *bmain);
SimulationState *BKE_simulation_state_add(Simulation *simulation,
const char *type,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index d702da55ea8..ada341ff570 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -100,6 +100,7 @@ set(SRC
intern/context.c
intern/crazyspace.c
intern/curve.c
+ intern/curve_bevel.c
intern/curve_decimate.c
intern/curve_deform.c
intern/curveprofile.c
@@ -134,6 +135,7 @@ set(SRC
intern/idtype.c
intern/image.c
intern/image_gen.c
+ intern/image_gpu.c
intern/image_save.c
intern/ipo.c
intern/kelvinlet.c
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index e035d5cbb68..8d8301362b3 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -32,8 +32,6 @@
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
-#include "GPU_glew.h"
-
/***/
int BKE_ccg_gridsize(int level)
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 2e1d2fd7f95..acc3c52c08c 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -223,7 +223,7 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->vfont->id.us += 4;
cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
BLI_strncpy(cu->str, "Text", 12);
- cu->len = cu->len_wchar = cu->pos = 4;
+ cu->len = cu->len_char32 = cu->pos = 4;
cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
cu->totbox = cu->actbox = 1;
cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
@@ -1726,205 +1726,6 @@ static void forward_diff_bezier_cotangent(const float p0[3],
}
}
-/* ***************** BEVEL ****************** */
-
-void BKE_curve_bevel_make(Object *ob, ListBase *disp)
-{
- DispList *dl, *dlnew;
- Curve *bevcu, *cu;
- float *fp, facx, facy, angle, dangle;
- int nr, a;
-
- cu = ob->data;
- BLI_listbase_clear(disp);
-
- /* if a font object is being edited, then do nothing */
- // XXX if ( ob == obedit && ob->type == OB_FONT ) return;
-
- if (cu->bevobj) {
- if (cu->bevobj->type != OB_CURVE) {
- return;
- }
-
- bevcu = cu->bevobj->data;
- if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
- ListBase bevdisp = {NULL, NULL};
- facx = cu->bevobj->scale[0];
- facy = cu->bevobj->scale[1];
-
- if (cu->bevobj->runtime.curve_cache) {
- dl = cu->bevobj->runtime.curve_cache->disp.first;
- }
- else {
- BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
- dl = NULL;
- }
-
- while (dl) {
- if (ELEM(dl->type, DL_POLY, DL_SEGM)) {
- dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1");
- *dlnew = *dl;
- dlnew->verts = MEM_malloc_arrayN(
- dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1");
- memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr);
-
- if (dlnew->type == DL_SEGM) {
- dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE);
- }
-
- BLI_addtail(disp, dlnew);
- fp = dlnew->verts;
- nr = dlnew->parts * dlnew->nr;
- while (nr--) {
- fp[2] = fp[1] * facy;
- fp[1] = -fp[0] * facx;
- fp[0] = 0.0;
- fp += 3;
- }
- }
- dl = dl->next;
- }
-
- BKE_displist_free(&bevdisp);
- }
- }
- else if (cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
- /* pass */
- }
- else if (cu->ext2 == 0.0f) {
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve2");
- dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
- dl->nr = 2;
-
- fp = dl->verts;
- fp[0] = fp[1] = 0.0;
- fp[2] = -cu->ext1;
- fp[3] = fp[4] = 0.0;
- fp[5] = cu->ext1;
- }
- else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 && cu->ext1 == 0.0f) {
- /* We make a full round bevel in that case. */
-
- nr = 4 + 2 * cu->bevresol;
-
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
- BLI_addtail(disp, dl);
- dl->type = DL_POLY;
- dl->parts = 1;
- dl->flag = DL_BACK_CURVE;
- dl->nr = nr;
-
- /* a circle */
- fp = dl->verts;
- dangle = (2.0f * (float)M_PI / (nr));
- angle = -(nr - 1) * dangle;
-
- for (a = 0; a < nr; a++) {
- fp[0] = 0.0;
- fp[1] = (cosf(angle) * (cu->ext2));
- fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1;
- angle += dangle;
- fp += 3;
- }
- }
- else {
- /* The general case for nonzero extrusion or an incomplete loop. */
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve");
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- /* The full loop. */
- nr = 4 * cu->bevresol + 6;
- dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
- }
- else if ((cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) {
- /* Half the loop. */
- nr = 2 * (cu->bevresol + 1) + ((cu->ext1 == 0.0f) ? 1 : 2);
- dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
- }
- else {
- /* One quarter of the loop (just front or back). */
- nr = (cu->ext1 == 0.0f) ? cu->bevresol + 2 : cu->bevresol + 3;
- dl->flag = (cu->flag & CU_FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE;
- }
-
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve");
- BLI_addtail(disp, dl);
- /* Use a different type depending on whether the loop is complete or not. */
- dl->type = ((cu->flag & (CU_FRONT | CU_BACK)) == 0) ? DL_POLY : DL_SEGM;
- dl->parts = 1;
- dl->nr = nr;
-
- fp = dl->verts;
- dangle = (float)M_PI_2 / (cu->bevresol + 1);
- angle = 0.0;
-
- /* Build the back section. */
- if (cu->flag & CU_BACK || !(cu->flag & CU_FRONT)) {
- angle = (float)M_PI_2 * 3.0f;
- for (a = 0; a < cu->bevresol + 2; a++) {
- fp[0] = 0.0;
- fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
- angle += dangle;
- fp += 3;
- }
- if ((cu->ext1 != 0.0f) && !(cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) {
- /* Add the extrusion if we're only building the back. */
- fp[0] = 0.0;
- fp[1] = cu->ext2;
- fp[2] = cu->ext1;
- }
- }
-
- /* Build the front section. */
- if (cu->flag & CU_FRONT || !(cu->flag & CU_BACK)) {
- if ((cu->ext1 != 0.0f) && !(cu->flag & CU_BACK) && (cu->flag & CU_FRONT)) {
- /* Add the extrusion if we're only building the back. */
- fp[0] = 0.0;
- fp[1] = cu->ext2;
- fp[2] = -cu->ext1;
- fp += 3;
- }
- /* Don't duplicate the last back vertex. */
- angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0;
- int front_len = (cu->ext1 == 0.0f && ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT))) ?
- cu->bevresol + 1 :
- cu->bevresol + 2;
- for (a = 0; a < front_len; a++) {
- fp[0] = 0.0;
- fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
- angle += dangle;
- fp += 3;
- }
- }
-
- /* Build the other half only if we're building the full loop. */
- if (!(cu->flag & (CU_FRONT | CU_BACK))) {
- for (a = 0; a < cu->bevresol + 1; a++) {
- fp[0] = 0.0;
- fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
- angle += dangle;
- fp += 3;
- }
-
- angle = (float)M_PI;
- for (a = 0; a < cu->bevresol + 1; a++) {
- fp[0] = 0.0;
- fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
- angle += dangle;
- fp += 3;
- }
- }
- }
-}
-
static int cu_isectLL(const float v1[3],
const float v2[3],
const float v3[3],
@@ -5438,7 +5239,7 @@ void BKE_curve_material_index_remove(Curve *cu, int index)
if (curvetype == OB_FONT) {
struct CharInfo *info = cu->strinfo;
int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ for (i = cu->len_char32 - 1; i >= 0; i--, info++) {
if (info->mat_nr && info->mat_nr >= index) {
info->mat_nr--;
}
@@ -5462,7 +5263,7 @@ bool BKE_curve_material_index_used(Curve *cu, int index)
if (curvetype == OB_FONT) {
struct CharInfo *info = cu->strinfo;
int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ for (i = cu->len_char32 - 1; i >= 0; i--, info++) {
if (info->mat_nr == index) {
return true;
}
@@ -5488,7 +5289,7 @@ void BKE_curve_material_index_clear(Curve *cu)
if (curvetype == OB_FONT) {
struct CharInfo *info = cu->strinfo;
int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ for (i = cu->len_char32 - 1; i >= 0; i--, info++) {
info->mat_nr = 0;
}
}
@@ -5510,7 +5311,7 @@ bool BKE_curve_material_index_validate(Curve *cu)
CharInfo *info = cu->strinfo;
const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */
int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ for (i = cu->len_char32 - 1; i >= 0; i--, info++) {
if (info->mat_nr > max_idx) {
info->mat_nr = 0;
is_valid = false;
@@ -5558,7 +5359,7 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
}
else {
strinfo = cu->strinfo;
- charinfo_len = cu->len_wchar;
+ charinfo_len = cu->len_char32;
}
for (i = 0; i <= charinfo_len; i++) {
diff --git a/source/blender/blenkernel/intern/curve_bevel.c b/source/blender/blenkernel/intern/curve_bevel.c
new file mode 100644
index 00000000000..7f23f0215cc
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_bevel.c
@@ -0,0 +1,272 @@
+/*
+ * 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
+ *
+ * Handle curve object data bevel options,
+ * both extruding
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+
+typedef enum CurveBevelFillType {
+ BACK = 0,
+ FRONT,
+ HALF,
+ FULL,
+} CurveBevelFillType;
+
+static CurveBevelFillType curve_bevel_get_fill_type(const Curve *curve)
+{
+ if (!(curve->flag & (CU_FRONT | CU_BACK))) {
+ return FULL;
+ }
+ if ((curve->flag & CU_FRONT) && (curve->flag & CU_BACK)) {
+ return HALF;
+ }
+
+ return (curve->flag & CU_FRONT) ? FRONT : BACK;
+}
+
+static void curve_bevel_make_extrude_and_fill(Curve *cu,
+ ListBase *disp,
+ const bool use_extrude,
+ const CurveBevelFillType fill_type)
+{
+ DispList *dl = MEM_callocN(sizeof(DispList), __func__);
+
+ int nr;
+ if (fill_type == FULL) {
+ /* The full loop. */
+ nr = 4 * cu->bevresol + 6;
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ }
+ else if (fill_type == HALF) {
+ /* Half the loop. */
+ nr = 2 * (cu->bevresol + 1) + (use_extrude ? 2 : 1);
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ }
+ else {
+ /* One quarter of the loop (just front or back). */
+ nr = use_extrude ? cu->bevresol + 3 : cu->bevresol + 2;
+ dl->flag = (fill_type == FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE;
+ }
+
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), __func__);
+ BLI_addtail(disp, dl);
+ /* Use a different type depending on whether the loop is complete or not. */
+ dl->type = (fill_type == FULL) ? DL_POLY : DL_SEGM;
+ dl->parts = 1;
+ dl->nr = nr;
+
+ float *fp = dl->verts;
+ const float dangle = (float)M_PI_2 / (cu->bevresol + 1);
+ float angle = 0.0f;
+
+ /* Build the back section. */
+ if (ELEM(fill_type, BACK, HALF, FULL)) {
+ angle = (float)M_PI_2 * 3.0f;
+ for (int i = 0; i < cu->bevresol + 2; i++) {
+ fp[0] = 0.0f;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+ if (use_extrude && fill_type == BACK) {
+ /* Add the extrusion if we're only building the back. */
+ fp[0] = 0.0f;
+ fp[1] = cu->ext2;
+ fp[2] = cu->ext1;
+ }
+ }
+
+ /* Build the front section. */
+ if (ELEM(fill_type, FRONT, HALF, FULL)) {
+ if (use_extrude && fill_type == FRONT) {
+ /* Add the extrusion if we're only building the front. */
+ fp[0] = 0.0f;
+ fp[1] = cu->ext2;
+ fp[2] = -cu->ext1;
+ fp += 3;
+ }
+ /* Don't duplicate the last back vertex. */
+ angle = (!use_extrude && ELEM(fill_type, HALF, FULL)) ? dangle : 0;
+ int front_len = (!use_extrude && ELEM(fill_type, HALF, FULL)) ? cu->bevresol + 1 :
+ cu->bevresol + 2;
+ for (int i = 0; i < front_len; i++) {
+ fp[0] = 0.0f;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+ }
+
+ /* Build the other half only if we're building the full loop. */
+ if (fill_type == FULL) {
+ for (int i = 0; i < cu->bevresol + 1; i++) {
+ fp[0] = 0.0f;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+
+ angle = (float)M_PI;
+ for (int i = 0; i < cu->bevresol + 1; i++) {
+ fp[0] = 0.0f;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+ }
+}
+
+static void curve_bevel_make_full_circle(Curve *cu, ListBase *disp)
+{
+ const int nr = 4 + 2 * cu->bevresol;
+
+ DispList *dl = MEM_callocN(sizeof(DispList), __func__);
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), __func__);
+ BLI_addtail(disp, dl);
+ dl->type = DL_POLY;
+ dl->parts = 1;
+ dl->flag = DL_BACK_CURVE;
+ dl->nr = nr;
+
+ float *fp = dl->verts;
+ const float dangle = (2.0f * (float)M_PI / (nr));
+ float angle = -(nr - 1) * dangle;
+
+ for (int i = 0; i < nr; i++) {
+ fp[0] = 0.0;
+ fp[1] = (cosf(angle) * (cu->ext2));
+ fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+}
+
+static void curve_bevel_make_only_extrude(Curve *cu, ListBase *disp)
+{
+ DispList *dl = MEM_callocN(sizeof(DispList), __func__);
+ dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), __func__);
+ BLI_addtail(disp, dl);
+ dl->type = DL_SEGM;
+ dl->parts = 1;
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ dl->nr = 2;
+
+ float *fp = dl->verts;
+ fp[0] = fp[1] = 0.0;
+ fp[2] = -cu->ext1;
+ fp[3] = fp[4] = 0.0;
+ fp[5] = cu->ext1;
+}
+
+static void curve_bevel_make_from_object(Curve *cu, ListBase *disp)
+{
+ if (cu->bevobj->type != OB_CURVE) {
+ return;
+ }
+
+ Curve *bevcu = cu->bevobj->data;
+ if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
+ ListBase bevdisp = {NULL, NULL};
+ float facx = cu->bevobj->scale[0];
+ float facy = cu->bevobj->scale[1];
+
+ DispList *dl;
+ if (cu->bevobj->runtime.curve_cache) {
+ dl = cu->bevobj->runtime.curve_cache->disp.first;
+ }
+ else {
+ BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
+ dl = NULL;
+ }
+
+ while (dl) {
+ if (ELEM(dl->type, DL_POLY, DL_SEGM)) {
+ DispList *dlnew = MEM_mallocN(sizeof(DispList), __func__);
+ *dlnew = *dl;
+ dlnew->verts = MEM_malloc_arrayN(dl->parts * dl->nr, 3 * sizeof(float), __func__);
+ memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr);
+
+ if (dlnew->type == DL_SEGM) {
+ dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE);
+ }
+
+ BLI_addtail(disp, dlnew);
+ float *fp = dlnew->verts;
+ int nr = dlnew->parts * dlnew->nr;
+ while (nr--) {
+ fp[2] = fp[1] * facy;
+ fp[1] = -fp[0] * facx;
+ fp[0] = 0.0;
+ fp += 3;
+ }
+ }
+ dl = dl->next;
+ }
+
+ BKE_displist_free(&bevdisp);
+ }
+}
+
+void BKE_curve_bevel_make(Object *ob, ListBase *disp)
+{
+ Curve *curve = ob->data;
+
+ const bool use_extrude = curve->ext1 != 0.0f;
+ const bool use_bevel = curve->ext2 != 0.0f;
+
+ BLI_listbase_clear(disp);
+
+ if (curve->bevobj) {
+ curve_bevel_make_from_object(curve, disp);
+ }
+ else if (!(use_extrude || use_bevel)) {
+ /* Pass. */
+ }
+ else if (use_extrude && !use_bevel) {
+ curve_bevel_make_only_extrude(curve, disp);
+ }
+ else {
+ CurveBevelFillType fill_type = curve_bevel_get_fill_type(curve);
+
+ if (!use_extrude && fill_type == FULL) {
+ curve_bevel_make_full_circle(curve, disp);
+ }
+ else {
+ /* The general case for nonzero extrusion or an incomplete loop. */
+ curve_bevel_make_extrude_and_fill(curve, disp, use_extrude, fill_type);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.c
index 6919d4fa10f..8577990dc03 100644
--- a/source/blender/blenkernel/intern/curveprofile.c
+++ b/source/blender/blenkernel/intern/curveprofile.c
@@ -886,7 +886,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
*/
static void curveprofile_make_table(CurveProfile *profile)
{
- int n_samples = PROF_N_TABLE(profile->path_len);
+ int n_samples = PROF_TABLE_LEN(profile->path_len);
CurveProfilePoint *new_table = MEM_callocN(sizeof(CurveProfilePoint) * (n_samples + 1),
"high-res table");
@@ -1059,7 +1059,7 @@ void BKE_curveprofile_initialize(CurveProfile *profile, short segments_len)
*/
static float curveprofile_distance_to_next_table_point(const CurveProfile *profile, int i)
{
- BLI_assert(i < PROF_N_TABLE(profile->path_len));
+ BLI_assert(i < PROF_TABLE_LEN(profile->path_len));
return len_v2v2(&profile->table[i].x, &profile->table[i + 1].x);
}
@@ -1072,7 +1072,7 @@ static float curveprofile_distance_to_next_table_point(const CurveProfile *profi
float BKE_curveprofile_total_length(const CurveProfile *profile)
{
float total_length = 0;
- for (int i = 0; i < PROF_N_TABLE(profile->path_len) - 1; i++) {
+ for (int i = 0; i < PROF_TABLE_LEN(profile->path_len) - 1; i++) {
total_length += len_v2v2(&profile->table[i].x, &profile->table[i + 1].x);
}
return total_length;
@@ -1160,7 +1160,7 @@ void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile,
float length_travelled = 0.0f;
while (length_travelled < requested_length) {
/* Check if we reached the last point before the final one. */
- if (i == PROF_N_TABLE(profile->path_len) - 2) {
+ if (i == PROF_TABLE_LEN(profile->path_len) - 2) {
break;
}
float new_length = curveprofile_distance_to_next_table_point(profile, i);
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 22d4af6fa39..7bf11d86a63 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -2643,11 +2643,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
}
if (alloctype == CD_DUPLICATE && layerdata) {
- if (typeInfo->copy) {
- typeInfo->copy(layerdata, newlayerdata, totelem);
- }
- else {
- memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size);
+ if (totelem > 0) {
+ if (typeInfo->copy) {
+ typeInfo->copy(layerdata, newlayerdata, totelem);
+ }
+ else {
+ memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size);
+ }
}
}
else if (alloctype == CD_DEFAULT) {
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 10d804f437e..87cb77930f5 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -21,12 +21,6 @@
* \ingroup bke
*/
-// #include <float.h>
-// #include <math.h>
-// #include <stddef.h>
-// #include <stdio.h>
-// #include <string.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
@@ -66,17 +60,19 @@ static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
static CLG_LogRef LOG = {"bke.fcurve"};
-/* Driver Variables --------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Driver Variables
+ * \{ */
/* TypeInfo for Driver Variables (dvti) */
typedef struct DriverVarTypeInfo {
- /* evaluation callback */
+ /* Evaluation callback. */
float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
- /* allocation of target slots */
- int num_targets; /* number of target slots required */
- const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
- short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+ /* Allocation of target slots. */
+ int num_targets; /* Number of target slots required. */
+ const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots. */
+ short target_flags[MAX_DRIVER_TARGETS]; /* Flags defining the requirements for each slot. */
} DriverVarTypeInfo;
/* Macro to begin definitions */
@@ -85,7 +81,11 @@ typedef struct DriverVarTypeInfo {
/* Macro to end definitions */
#define END_DVAR_TYPEDEF }
-/* ......... */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Target Utilities
+ * \{ */
static ID *dtar_id_ensure_proxy_from(ID *id)
{
@@ -107,14 +107,14 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
int index = -1;
float value = 0.0f;
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, driver, dtar)) {
return 0.0f;
}
id = dtar_id_ensure_proxy_from(dtar->id);
- /* error check for missing pointer... */
+ /* Error check for missing pointer. */
if (id == NULL) {
if (G.debug & G_DEBUG) {
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
@@ -125,12 +125,12 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
return 0.0f;
}
- /* get RNA-pointer for the ID-block given in target */
+ /* Get RNA-pointer for the ID-block given in target. */
RNA_id_pointer_create(id, &id_ptr);
- /* get property to read from, and get value as appropriate */
+ /* Get property to read from, and get value as appropriate. */
if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* path couldn't be resolved */
+ /* Path couldn't be resolved. */
if (G.debug & G_DEBUG) {
CLOG_ERROR(&LOG,
"Driver Evaluation Error: cannot resolve target for %s -> %s",
@@ -144,9 +144,9 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
}
if (RNA_property_array_check(prop)) {
- /* array */
+ /* Array. */
if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
- /* out of bounds */
+ /* Out of bounds. */
if (G.debug & G_DEBUG) {
CLOG_ERROR(&LOG,
"Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
@@ -175,7 +175,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
}
}
else {
- /* not an array */
+ /* Not an array. */
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
value = (float)RNA_property_boolean_get(&ptr, prop);
@@ -194,7 +194,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
}
}
- /* if we're still here, we should be ok... */
+ /* If we're still here, we should be ok. */
dtar->flag &= ~DTAR_FLAG_INVALID;
return value;
}
@@ -214,14 +214,14 @@ bool driver_get_variable_property(ChannelDriver *driver,
ID *id;
int index = -1;
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, driver, dtar)) {
return false;
}
id = dtar_id_ensure_proxy_from(dtar->id);
- /* error check for missing pointer... */
+ /* Error check for missing pointer. */
if (id == NULL) {
if (G.debug & G_DEBUG) {
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
@@ -232,19 +232,19 @@ bool driver_get_variable_property(ChannelDriver *driver,
return false;
}
- /* get RNA-pointer for the ID-block given in target */
+ /* Get RNA-pointer for the ID-block given in target. */
RNA_id_pointer_create(id, &id_ptr);
- /* get property to read from, and get value as appropriate */
+ /* Get property to read from, and get value as appropriate. */
if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
ptr = PointerRNA_NULL;
- prop = NULL; /* ok */
+ prop = NULL; /* OK. */
}
else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* ok */
+ /* OK. */
}
else {
- /* path couldn't be resolved */
+ /* Path couldn't be resolved. */
if (G.debug & G_DEBUG) {
CLOG_ERROR(&LOG,
"Driver Evaluation Error: cannot resolve target for %s -> %s",
@@ -265,7 +265,7 @@ bool driver_get_variable_property(ChannelDriver *driver,
*r_prop = prop;
*r_index = index;
- /* if we're still here, we should be ok... */
+ /* If we're still here, we should be ok. */
dtar->flag &= ~DTAR_FLAG_INVALID;
return true;
}
@@ -277,14 +277,14 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- /* check if this target has valid data */
+ /* Check if this target has valid data. */
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
+ /* Invalid target, so will not have enough targets. */
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
}
else {
- /* target seems to be OK now... */
+ /* Target seems to be OK now. */
dtar->flag &= ~DTAR_FLAG_INVALID;
valid_targets++;
}
@@ -294,21 +294,25 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
return valid_targets;
}
-/* ......... */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Variable Utilities
+ * \{ */
-/* evaluate 'single prop' driver variable */
+/* Evaluate 'single prop' driver variable. */
static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
{
- /* just evaluate the first target slot */
+ /* Just evaluate the first target slot. */
return dtar_get_prop_val(driver, &dvar->targets[0]);
}
-/* evaluate 'rotation difference' driver variable */
+/* Evaluate 'rotation difference' driver variable. */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
short valid_targets = driver_check_valid_targets(driver, dvar);
- /* make sure we have enough valid targets to use - all or nothing for now... */
+ /* Make sure we have enough valid targets to use - all or nothing for now. */
if (driver_check_valid_targets(driver, dvar) != 2) {
if (G.debug & G_DEBUG) {
CLOG_WARN(&LOG,
@@ -324,31 +328,31 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
/* NOTE: for now, these are all just worldspace */
for (int i = 0; i < 2; i++) {
- /* get pointer to loc values to store in */
+ /* Get pointer to loc values to store in. */
DriverTarget *dtar = &dvar->targets[i];
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
bPoseChannel *pchan;
- /* after the checks above, the targets should be valid here... */
+ /* After the checks above, the targets should be valid here. */
BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
- /* try to get posechannel */
+ /* Try to get pose-channel. */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
- /* check if object or bone */
+ /* Check if object or bone. */
if (pchan) {
- /* bone */
+ /* Bone. */
mat[i] = pchan->pose_mat;
}
else {
- /* object */
+ /* Object. */
mat[i] = ob->obmat;
}
}
float q1[4], q2[4], quat[4], angle;
- /* use the final posed locations */
+ /* Use the final posed locations. */
mat4_to_quat(q1, mat[0]);
mat4_to_quat(q2, mat[1]);
@@ -360,15 +364,18 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
}
-/* evaluate 'location difference' driver variable */
-/* TODO: this needs to take into account space conversions... */
+/**
+ * Evaluate 'location difference' driver variable.
+ *
+ * TODO: this needs to take into account space conversions.
+ */
static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
float loc1[3] = {0.0f, 0.0f, 0.0f};
float loc2[3] = {0.0f, 0.0f, 0.0f};
short valid_targets = driver_check_valid_targets(driver, dvar);
- /* make sure we have enough valid targets to use - all or nothing for now... */
+ /* Make sure we have enough valid targets to use - all or nothing for now. */
if (valid_targets < dvar->num_targets) {
if (G.debug & G_DEBUG) {
CLOG_WARN(&LOG,
@@ -381,72 +388,72 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
/* SECOND PASS: get two location values */
- /* NOTE: for now, these are all just worldspace */
+ /* NOTE: for now, these are all just world-space */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- /* get pointer to loc values to store in */
+ /* Get pointer to loc values to store in. */
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
bPoseChannel *pchan;
float tmp_loc[3];
- /* after the checks above, the targets should be valid here... */
+ /* After the checks above, the targets should be valid here. */
BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
- /* try to get posechannel */
+ /* Try to get pose-channel. */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
- /* check if object or bone */
+ /* Check if object or bone. */
if (pchan) {
- /* bone */
+ /* Bone. */
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
float mat[4][4];
- /* extract transform just like how the constraints do it! */
+ /* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat);
BKE_constraint_mat_convertspace(
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
- /* ... and from that, we get our transform */
+ /* ... and from that, we get our transform. */
copy_v3_v3(tmp_loc, mat[3]);
}
else {
- /* transform space (use transform values directly) */
+ /* Transform space (use transform values directly). */
copy_v3_v3(tmp_loc, pchan->loc);
}
}
else {
- /* convert to worldspace */
+ /* Convert to worldspace. */
copy_v3_v3(tmp_loc, pchan->pose_head);
mul_m4_v3(ob->obmat, tmp_loc);
}
}
else {
- /* object */
+ /* Object. */
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* XXX: this should practically be the same as transform space... */
+ /* XXX: this should practically be the same as transform space. */
float mat[4][4];
- /* extract transform just like how the constraints do it! */
+ /* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
- /* ... and from that, we get our transform */
+ /* ... and from that, we get our transform. */
copy_v3_v3(tmp_loc, mat[3]);
}
else {
- /* transform space (use transform values directly) */
+ /* Transform space (use transform values directly). */
copy_v3_v3(tmp_loc, ob->loc);
}
}
else {
- /* worldspace */
+ /* World-space. */
copy_v3_v3(tmp_loc, ob->obmat[3]);
}
}
- /* copy the location to the right place */
+ /* Copy the location to the right place. */
if (tarIndex) {
copy_v3_v3(loc2, tmp_loc);
}
@@ -456,13 +463,14 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
DRIVER_TARGETS_LOOPER_END;
- /* if we're still here, there should now be two targets to use,
- * so just take the length of the vector between these points
- */
+ /* If we're still here, there should now be two targets to use,
+ * so just take the length of the vector between these points. */
return len_v3v3(loc1, loc2);
}
-/* evaluate 'transform channel' driver variable */
+/**
+ * Evaluate 'transform channel' driver variable.
+ */
static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
{
DriverTarget *dtar = &dvar->targets[0];
@@ -473,15 +481,15 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
bool use_eulers = false;
short rot_order = ROT_MODE_EUL;
- /* check if this target has valid data */
+ /* Check if this target has valid data. */
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
+ /* Invalid target, so will not have enough targets. */
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
else {
- /* target should be valid now */
+ /* Target should be valid now. */
dtar->flag &= ~DTAR_FLAG_INVALID;
}
@@ -495,7 +503,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
* but #DTAR_FLAG_LOCAL_CONSTS is for all the common "corrective-shapes-for-limbs" situations.
*/
if (pchan) {
- /* bone */
+ /* Bone. */
if (pchan->rotmode > 0) {
copy_v3_v3(oldEul, pchan->eul);
rot_order = pchan->rotmode;
@@ -504,16 +512,15 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
+ /* Just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat);
BKE_constraint_mat_convertspace(
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
}
else {
- /* specially calculate local matrix, since chan_mat is not valid
+ /* Specially calculate local matrix, since chan_mat is not valid
* since it stores delta transform of pose_mat so that deforms work
- * so it cannot be used here for "transform" space
- */
+ * so it cannot be used here for "transform" space. */
BKE_pchan_to_mat4(pchan, mat);
}
}
@@ -523,7 +530,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
}
}
else {
- /* object */
+ /* Object. */
if (ob->rotmode > 0) {
copy_v3_v3(oldEul, ob->rot);
rot_order = ob->rotmode;
@@ -532,25 +539,25 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
+ /* Just like how the constraints do it! */
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
}
else {
- /* transforms to matrix */
+ /* Transforms to matrix. */
BKE_object_to_mat4(ob, mat);
}
}
else {
- /* worldspace matrix - just the good-old one */
+ /* World-space matrix - just the good-old one. */
copy_m4_m4(mat, ob->obmat);
}
}
- /* check which transform */
+ /* Check which transform. */
if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
- /* not valid channel */
+ /* Not valid channel. */
return 0.0f;
}
else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
@@ -567,7 +574,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
}
else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
- /* extract rotation as eulers (if needed)
+ /* Extract rotation as eulers (if needed)
* - definitely if rotation order isn't eulers already
* - if eulers, then we have 2 options:
* a) decompose transform matrix as required, then try to make eulers from
@@ -596,7 +603,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
return quat[channel];
}
else {
- /* extract location and choose right axis */
+ /* Extract location and choose right axis. */
return mat[3][dtar->transChan];
}
}
@@ -666,41 +673,45 @@ void BKE_driver_target_matrix_to_rot_channels(
}
}
-/* ......... */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Variable Type Info
+ * \{ */
/* Table of Driver Variable Type Info Data */
static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
- 1, /* number of targets used */
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* Eval callback. */
+ 1, /* Number of targets used. */
{"Property"}, /* UI names for targets */
- {0} /* flags */
+ {0} /* Flags. */
END_DVAR_TYPEDEF,
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
- 2, /* number of targets used */
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* Eval callback. */
+ 2, /* Number of targets used. */
{"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
- DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
END_DVAR_TYPEDEF,
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
- 2, /* number of targets used */
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* Eval callback. */
+ 2, /* Number of targets used. */
{"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
- DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
END_DVAR_TYPEDEF,
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
- 1, /* number of targets used */
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* Eval callback. */
+ 1, /* Number of targets used. */
{"Object/Bone"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
END_DVAR_TYPEDEF,
};
/* Get driver variable typeinfo */
static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
{
- /* check if valid type */
+ /* Check if valid type. */
if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
return &dvar_types[type];
}
@@ -709,40 +720,44 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
}
}
-/* Driver API --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver API
+ * \{ */
/* Perform actual freeing driver variable and remove it from the given list */
void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
- /* sanity checks */
+ /* Sanity checks. */
if (dvar == NULL) {
return;
}
- /* free target vars
+ /* Free target vars:
* - need to go over all of them, not just up to the ones that are used
* currently, since there may be some lingering RNA paths from
* previous users needing freeing
*/
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
- /* free RNA path if applicable */
+ /* Free RNA path if applicable. */
if (dtar->rna_path) {
MEM_freeN(dtar->rna_path);
}
}
DRIVER_TARGETS_LOOPER_END;
- /* remove the variable from the driver */
+ /* Remove the variable from the driver. */
BLI_freelinkN(variables, dvar);
}
/* Free the driver variable and do extra updates */
void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
{
- /* remove and free the driver variable */
+ /* Remove and free the driver variable. */
driver_free_variable(&driver->variables, dvar);
- /* since driver variables are cached, the expression needs re-compiling too */
+ /* Since driver variables are cached, the expression needs re-compiling too. */
BKE_driver_invalidate_expression(driver, false, true);
}
@@ -753,9 +768,9 @@ void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
BLI_duplicatelist(dst_vars, src_vars);
LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) {
- /* need to go over all targets so that we don't leave any dangling paths */
+ /* Need to go over all targets so that we don't leave any dangling paths. */
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
- /* make a copy of target's rna path if available */
+ /* Make a copy of target's rna path if available. */
if (dtar->rna_path) {
dtar->rna_path = MEM_dupallocN(dtar->rna_path);
}
@@ -769,25 +784,24 @@ void driver_change_variable_type(DriverVar *dvar, int type)
{
const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, dvar, dvti)) {
return;
}
- /* set the new settings */
+ /* Set the new settings. */
dvar->type = type;
dvar->num_targets = dvti->num_targets;
- /* make changes to the targets based on the defines for these types
- * NOTE: only need to make sure the ones we're using here are valid...
- */
+ /* Make changes to the targets based on the defines for these types.
+ * NOTE: only need to make sure the ones we're using here are valid. */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
short flags = dvti->target_flags[tarIndex];
- /* store the flags */
+ /* Store the flags. */
dtar->flag = flags;
- /* object ID types only, or idtype not yet initialized */
+ /* Object ID types only, or idtype not yet initialized. */
if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
dtar->idtype = ID_OB;
}
@@ -804,12 +818,12 @@ void driver_variable_name_validate(DriverVar *dvar)
'?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
};
- /* sanity checks */
+ /* Sanity checks. */
if (dvar == NULL) {
return;
}
- /* clear all invalid-name flags */
+ /* Clear all invalid-name flags. */
dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
/* 0) Zero-length identifiers are not allowed */
@@ -870,16 +884,16 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
- /* sanity checks */
+ /* Sanity checks. */
if (driver == NULL) {
return NULL;
}
- /* make a new variable */
+ /* Make a new variable. */
dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
BLI_addtail(&driver->variables, dvar);
- /* give the variable a 'unique' name */
+ /* Give the variable a 'unique' name. */
strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
BLI_uniquename(&driver->variables,
dvar,
@@ -888,13 +902,13 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
offsetof(DriverVar, name),
sizeof(dvar->name));
- /* set the default type to 'single prop' */
+ /* Set the default type to 'single prop'. */
driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
- /* since driver variables are cached, the expression needs re-compiling too */
+ /* Since driver variables are cached, the expression needs re-compiling too. */
BKE_driver_invalidate_expression(driver, false, true);
- /* return the target */
+ /* Return the target. */
return dvar;
}
@@ -904,20 +918,20 @@ void fcurve_free_driver(FCurve *fcu)
ChannelDriver *driver;
DriverVar *dvar, *dvarn;
- /* sanity checks */
+ /* Sanity checks. */
if (ELEM(NULL, fcu, fcu->driver)) {
return;
}
driver = fcu->driver;
- /* free driver targets */
+ /* Free driver targets. */
for (dvar = driver->variables.first; dvar; dvar = dvarn) {
dvarn = dvar->next;
driver_free_variable_ex(driver, dvar);
}
#ifdef WITH_PYTHON
- /* free compiled driver expression */
+ /* Free compiled driver expression. */
if (driver->expr_comp) {
BPY_DECREF(driver->expr_comp);
}
@@ -936,27 +950,31 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
ChannelDriver *ndriver;
- /* sanity checks */
+ /* Sanity checks. */
if (driver == NULL) {
return NULL;
}
- /* copy all data */
+ /* Copy all data. */
ndriver = MEM_dupallocN(driver);
ndriver->expr_comp = NULL;
ndriver->expr_simple = NULL;
- /* copy variables */
+ /* Copy variables. */
- /* to get rid of refs to non-copied data (that's still used on original) */
+ /* To get rid of refs to non-copied data (that's still used on original). */
BLI_listbase_clear(&ndriver->variables);
driver_variables_copy(&ndriver->variables, &driver->variables);
- /* return the new driver */
+ /* Return the new driver. */
return ndriver;
}
-/* Driver Expression Evaluation --------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Expression Evaluation
+ * \{ */
/* Index constants for the expression parameter array. */
enum {
@@ -1026,7 +1044,7 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver,
return true;
default:
- /* arriving here means a bug, not user error */
+ /* Arriving here means a bug, not user error. */
CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
return false;
}
@@ -1135,22 +1153,25 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver,
#endif
}
-/* Driver Evaluation -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Evaluation
+ * \{ */
/* Evaluate a Driver Variable to get a value that contributes to the final */
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
{
const DriverVarTypeInfo *dvti;
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, driver, dvar)) {
return 0.0f;
}
- /* call the relevant callbacks to get the variable value
+ /* Call the relevant callbacks to get the variable value
* using the variable type info, storing the obtained value
- * in dvar->curval so that drivers can be debugged
- */
+ * in `dvar->curval` so that drivers can be debugged. */
dvti = get_dvar_typeinfo(dvar->type);
if (dvti && dvti->get_value) {
@@ -1167,25 +1188,25 @@ static void evaluate_driver_sum(ChannelDriver *driver)
{
DriverVar *dvar;
- /* check how many variables there are first (i.e. just one?) */
+ /* Check how many variables there are first (i.e. just one?). */
if (BLI_listbase_is_single(&driver->variables)) {
- /* just one target, so just use that */
+ /* Just one target, so just use that. */
dvar = driver->variables.first;
driver->curval = driver_get_variable_value(driver, dvar);
return;
}
- /* more than one target, so average the values of the targets */
+ /* More than one target, so average the values of the targets. */
float value = 0.0f;
int tot = 0;
- /* loop through targets, adding (hopefully we don't get any overflow!) */
+ /* Loop through targets, adding (hopefully we don't get any overflow!). */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
value += driver_get_variable_value(driver, dvar);
tot++;
}
- /* perform operations on the total if appropriate */
+ /* Perform operations on the total if appropriate. */
if (driver->type == DRIVER_TYPE_AVERAGE) {
driver->curval = tot ? (value / (float)tot) : 0.0f;
}
@@ -1199,34 +1220,34 @@ static void evaluate_driver_min_max(ChannelDriver *driver)
DriverVar *dvar;
float value = 0.0f;
- /* loop through the variables, getting the values and comparing them to existing ones */
+ /* Loop through the variables, getting the values and comparing them to existing ones. */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* get value */
+ /* Get value. */
float tmp_val = driver_get_variable_value(driver, dvar);
- /* store this value if appropriate */
+ /* Store this value if appropriate. */
if (dvar->prev) {
- /* check if greater/smaller than the baseline */
+ /* Check if greater/smaller than the baseline. */
if (driver->type == DRIVER_TYPE_MAX) {
- /* max? */
+ /* Max? */
if (tmp_val > value) {
value = tmp_val;
}
}
else {
- /* min? */
+ /* Min? */
if (tmp_val < value) {
value = tmp_val;
}
}
}
else {
- /* first item - make this the baseline for comparisons */
+ /* First item - make this the baseline for comparisons. */
value = tmp_val;
}
}
- /* store value in driver */
+ /* Store value in driver. */
driver->curval = value;
}
@@ -1235,62 +1256,63 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
ChannelDriver *driver_orig,
const AnimationEvalContext *anim_eval_context)
{
- /* check for empty or invalid expression */
+ /* Check for empty or invalid expression. */
if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
driver->curval = 0.0f;
}
else if (!driver_try_evaluate_simple_expr(
driver, driver_orig, &driver->curval, anim_eval_context->eval_time)) {
#ifdef WITH_PYTHON
- /* this evaluates the expression using Python, and returns its result:
- * - on errors it reports, then returns 0.0f
- */
+ /* This evaluates the expression using Python, and returns its result:
+ * - on errors it reports, then returns 0.0f. */
BLI_mutex_lock(&python_driver_lock);
driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, anim_eval_context);
BLI_mutex_unlock(&python_driver_lock);
-#else /* WITH_PYTHON*/
+#else /* WITH_PYTHON */
UNUSED_VARS(anim_rna, anim_eval_context);
-#endif /* WITH_PYTHON*/
+#endif /* WITH_PYTHON */
}
}
-/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
- * - "evaltime" is the frame at which F-Curve is being evaluated
- * - has to return a float value
- * - driver_orig is where we cache Python expressions, in case of COW
+/**
+ * Evaluate an Channel-Driver to get a 'time' value to use
+ * instead of `anim_eval_context->eval_time`.
+ *
+ * - `anim_eval_context->eval_time` is the frame at which F-Curve is being evaluated.
+ * - Has to return a float value.
+ * - \a driver_orig is where we cache Python expressions, in case of COW
*/
float evaluate_driver(PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
const AnimationEvalContext *anim_eval_context)
{
- /* check if driver can be evaluated */
+ /* Check if driver can be evaluated. */
if (driver_orig->flag & DRIVER_FLAG_INVALID) {
return 0.0f;
}
switch (driver->type) {
- case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
- case DRIVER_TYPE_SUM: /* sum values of driver targets */
+ case DRIVER_TYPE_AVERAGE: /* Average values of driver targets. */
+ case DRIVER_TYPE_SUM: /* Sum values of driver targets. */
evaluate_driver_sum(driver);
break;
- case DRIVER_TYPE_MIN: /* smallest value */
- case DRIVER_TYPE_MAX: /* largest value */
+ case DRIVER_TYPE_MIN: /* Smallest value. */
+ case DRIVER_TYPE_MAX: /* Largest value. */
evaluate_driver_min_max(driver);
break;
- case DRIVER_TYPE_PYTHON: /* expression */
+ case DRIVER_TYPE_PYTHON: /* Expression. */
evaluate_driver_python(anim_rna, driver, driver_orig, anim_eval_context);
break;
default:
- /* special 'hack' - just use stored value
+ /* Special 'hack' - just use stored value
* This is currently used as the mechanism which allows animated settings to be able
- * to be changed via the UI.
- */
+ * to be changed via the UI. */
break;
}
- /* return value for driver */
+ /* Return value for driver. */
return driver->curval;
}
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index dfa5ff6975f..958acf0589b 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -797,7 +797,7 @@ static bool vfont_to_curve(Object *ob,
}
else {
char32_t *mem_tmp;
- slen = cu->len_wchar;
+ slen = cu->len_char32;
/* Create unicode string */
mem_tmp = MEM_malloc_arrayN((slen + 1), sizeof(*mem_tmp), "convertedmem");
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index 5b7753428f7..53bfd3aa8ff 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -2599,10 +2599,9 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
bGPDspoint *pt = &gps->points[0];
- color[0] *= BLI_hash_int_01(BLI_hash_int_2d(gps->totpoints, pt->x));
- color[1] *= BLI_hash_int_01(BLI_hash_int_2d(gps->totpoints, pt->y));
- color[2] *= BLI_hash_int_01(BLI_hash_int_2d(gps->totpoints, pt->z));
-
+ color[0] *= BLI_hash_int_01(BLI_hash_int_2d(gps->totpoints / 5, pt->x + pt->z));
+ color[1] *= BLI_hash_int_01(BLI_hash_int_2d(gps->totpoints + pt->x, pt->y * pt->z + pt->x));
+ color[2] *= BLI_hash_int_01(BLI_hash_int_2d(gps->totpoints - pt->x, pt->z * pt->x + pt->y));
for (int i = 0; i < gps->totpoints; i++) {
pt = &gps->points[i];
copy_v4_v4(pt->vert_color, color);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 9365ee040c2..fa0be9ea441 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -57,6 +57,7 @@
#include "DNA_packedFile_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
@@ -89,7 +90,6 @@
#include "RE_pipeline.h"
-#include "GPU_draw.h"
#include "GPU_texture.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -392,7 +392,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
ima->rr = NULL;
}
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
tile->ok = IMA_OK;
@@ -3240,6 +3240,12 @@ static void image_walk_id_all_users(
if (scene->nodetree && scene->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(scene->nodetree, &scene->id, customdata, callback);
}
+ break;
+ }
+ case ID_SIM: {
+ Simulation *simulation = (Simulation *)id;
+ image_walk_ntree_all_users(simulation->nodetree, &simulation->id, customdata, callback);
+ break;
}
default:
break;
@@ -3344,8 +3350,7 @@ static void image_free_tile(Image *ima, ImageTile *tile)
for (int i = 0; i < TEXTARGET_COUNT; i++) {
/* Only two textures depends on all tiles, so if this is a secondary tile we can keep the other
* two. */
- if (tile != ima->tiles.first &&
- !(ELEM(i, TEXTARGET_TEXTURE_2D_ARRAY, TEXTARGET_TEXTURE_TILE_MAPPING))) {
+ if (tile != ima->tiles.first && !(ELEM(i, TEXTARGET_2D_ARRAY, TEXTARGET_TILE_MAPPING))) {
continue;
}
@@ -3622,13 +3627,13 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
for (int eye = 0; eye < 2; eye++) {
/* Reallocate GPU tile array. */
- if (ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][eye] != NULL) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][eye]);
- ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][eye] = NULL;
+ if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
+ ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL;
}
- if (ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][eye] != NULL) {
- GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][eye]);
- ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][eye] = NULL;
+ if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
+ ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c
new file mode 100644
index 00000000000..e3ed7cdc8de
--- /dev/null
+++ b/source/blender/blenkernel/intern/image_gpu.c
@@ -0,0 +1,777 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_boxpack_2d.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+
+#include "DNA_image_types.h"
+#include "DNA_userdef_types.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+
+#include "GPU_extensions.h"
+#include "GPU_state.h"
+#include "GPU_texture.h"
+
+#include "PIL_time.h"
+
+/* Prototypes. */
+static void gpu_free_unused_buffers(void);
+static void image_free_gpu(Image *ima, const bool immediate);
+
+/* -------------------------------------------------------------------- */
+/** \name UDIM gpu texture
+ * \{ */
+
+static bool is_over_resolution_limit(int w, int h)
+{
+ return (w > GPU_texture_size_with_limit(w) || h > GPU_texture_size_with_limit(h));
+}
+
+static int smaller_power_of_2_limit(int num)
+{
+ return power_of_2_min_i(GPU_texture_size_with_limit(num));
+}
+
+static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
+{
+ GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
+
+ if (tilearray == NULL) {
+ return 0;
+ }
+
+ float array_w = GPU_texture_width(tilearray);
+ float array_h = GPU_texture_height(tilearray);
+
+ ImageTile *last_tile = (ImageTile *)ima->tiles.last;
+ /* Tiles are sorted by number. */
+ int max_tile = last_tile->tile_number - 1001;
+
+ /* create image */
+ int width = max_tile + 1;
+ float *data = (float *)MEM_callocN(width * 8 * sizeof(float), __func__);
+ for (int i = 0; i < width; i++) {
+ data[4 * i] = -1.0f;
+ }
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ int i = tile->tile_number - 1001;
+ data[4 * i] = tile->runtime.tilearray_layer;
+
+ float *tile_info = &data[4 * width + 4 * i];
+ tile_info[0] = tile->runtime.tilearray_offset[0] / array_w;
+ tile_info[1] = tile->runtime.tilearray_offset[1] / array_h;
+ tile_info[2] = tile->runtime.tilearray_size[0] / array_w;
+ tile_info[3] = tile->runtime.tilearray_size[1] / array_h;
+ }
+
+ GPUTexture *tex = GPU_texture_create_1d_array(width, 2, GPU_RGBA32F, data, NULL);
+ GPU_texture_mipmap_mode(tex, false, false);
+
+ MEM_freeN(data);
+
+ return tex;
+}
+
+typedef struct PackTile {
+ FixedSizeBoxPack boxpack;
+ ImageTile *tile;
+ float pack_score;
+} PackTile;
+
+static int compare_packtile(const void *a, const void *b)
+{
+ const PackTile *tile_a = (const PackTile *)a;
+ const PackTile *tile_b = (const PackTile *)b;
+
+ return tile_a->pack_score < tile_b->pack_score;
+}
+
+static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
+{
+ int arraywidth = 0, arrayheight = 0;
+ ListBase boxes = {NULL};
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+
+ if (ibuf) {
+ PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__);
+ packtile->tile = tile;
+ packtile->boxpack.w = ibuf->x;
+ packtile->boxpack.h = ibuf->y;
+
+ if (is_over_resolution_limit(packtile->boxpack.w, packtile->boxpack.h)) {
+ packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
+ packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
+ }
+ arraywidth = max_ii(arraywidth, packtile->boxpack.w);
+ arrayheight = max_ii(arrayheight, packtile->boxpack.h);
+
+ /* We sort the tiles by decreasing size, with an additional penalty term
+ * for high aspect ratios. This improves packing efficiency. */
+ float w = packtile->boxpack.w, h = packtile->boxpack.h;
+ packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h;
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ BLI_addtail(&boxes, packtile);
+ }
+ }
+
+ BLI_assert(arraywidth > 0 && arrayheight > 0);
+
+ BLI_listbase_sort(&boxes, compare_packtile);
+ int arraylayers = 0;
+ /* Keep adding layers until all tiles are packed. */
+ while (boxes.first != NULL) {
+ ListBase packed = {NULL};
+ BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
+ BLI_assert(packed.first != NULL);
+
+ LISTBASE_FOREACH (PackTile *, packtile, &packed) {
+ ImageTile *tile = packtile->tile;
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int *tilesize = tile->runtime.tilearray_size;
+
+ tileoffset[0] = packtile->boxpack.x;
+ tileoffset[1] = packtile->boxpack.y;
+ tilesize[0] = packtile->boxpack.w;
+ tilesize[1] = packtile->boxpack.h;
+ tile->runtime.tilearray_layer = arraylayers;
+ }
+
+ BLI_freelistN(&packed);
+ arraylayers++;
+ }
+
+ const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
+ /* Create Texture without content. */
+ GPUTexture *tex = IMB_touch_gpu_texture(
+ main_ibuf, arraywidth, arrayheight, arraylayers, use_high_bitdepth);
+
+ GPU_texture_bind(tex, 0);
+
+ /* Upload each tile one by one. */
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ int tilelayer = tile->runtime.tilearray_layer;
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int *tilesize = tile->runtime.tilearray_size;
+
+ if (tilesize[0] == 0 || tilesize[1] == 0) {
+ continue;
+ }
+
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+
+ if (ibuf) {
+ const bool store_premultiplied = ibuf->rect_float ? (ima->alpha_mode != IMA_ALPHA_STRAIGHT) :
+ (ima->alpha_mode == IMA_ALPHA_PREMUL);
+ IMB_update_gpu_texture_sub(tex,
+ ibuf,
+ UNPACK2(tileoffset),
+ tilelayer,
+ UNPACK2(tilesize),
+ use_high_bitdepth,
+ store_premultiplied);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+
+ if (GPU_mipmap_enabled()) {
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_mipmap_mode(tex, true, true);
+ if (ima) {
+ ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
+ }
+ }
+ else {
+ GPU_texture_mipmap_mode(tex, false, true);
+ }
+
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Regular gpu texture
+ * \{ */
+
+static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
+ eGPUTextureTarget textarget,
+ const int multiview_eye)
+{
+ const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
+ BLI_assert(in_range);
+
+ if (in_range) {
+ return &(ima->gputexture[textarget][multiview_eye]);
+ }
+ return NULL;
+}
+
+static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
+{
+ switch (textarget) {
+ case TEXTARGET_2D_ARRAY:
+ return GPU_texture_create_error(2, true);
+ case TEXTARGET_TILE_MAPPING:
+ return GPU_texture_create_error(1, true);
+ case TEXTARGET_2D:
+ default:
+ return GPU_texture_create_error(2, false);
+ }
+}
+
+static GPUTexture *image_get_gpu_texture(Image *ima,
+ ImageUser *iuser,
+ ImBuf *ibuf,
+ eGPUTextureTarget textarget)
+{
+ if (ima == NULL) {
+ return NULL;
+ }
+
+ /* Free any unused GPU textures, since we know we are in a thread with OpenGL
+ * context and might as well ensure we have as much space free as possible. */
+ gpu_free_unused_buffers();
+
+ /* currently, gpu refresh tagging is used by ima sequences */
+ if (ima->gpuflag & IMA_GPU_REFRESH) {
+ image_free_gpu(ima, true);
+ ima->gpuflag &= ~IMA_GPU_REFRESH;
+ }
+
+ /* Tag as in active use for garbage collector. */
+ BKE_image_tag_time(ima);
+
+ /* Test if we already have a texture. */
+ GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, iuser ? iuser->multiview_eye : 0);
+ if (*tex) {
+ return *tex;
+ }
+
+ /* Check if we have a valid image. If not, we return a dummy
+ * texture with zero bind-code so we don't keep trying. */
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ if (tile == NULL || tile->ok == 0) {
+ *tex = image_gpu_texture_error_create(textarget);
+ return *tex;
+ }
+
+ /* check if we have a valid image buffer */
+ ImBuf *ibuf_intern = ibuf;
+ if (ibuf_intern == NULL) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf_intern == NULL) {
+ *tex = image_gpu_texture_error_create(textarget);
+ return *tex;
+ }
+ }
+
+ if (textarget == TEXTARGET_2D_ARRAY) {
+ *tex = gpu_texture_create_tile_array(ima, ibuf_intern);
+ }
+ else if (textarget == TEXTARGET_TILE_MAPPING) {
+ *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
+ }
+ else {
+ const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
+ const bool store_premultiplied = ibuf_intern->rect_float ?
+ (ima ? (ima->alpha_mode != IMA_ALPHA_STRAIGHT) : false) :
+ (ima ? (ima->alpha_mode == IMA_ALPHA_PREMUL) : true);
+
+ *tex = IMB_create_gpu_texture(ibuf_intern, use_high_bitdepth, store_premultiplied);
+
+ if (GPU_mipmap_enabled()) {
+ GPU_texture_bind(*tex, 0);
+ GPU_texture_generate_mipmap(*tex);
+ GPU_texture_unbind(*tex);
+ if (ima) {
+ ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
+ }
+ GPU_texture_mipmap_mode(*tex, true, true);
+ }
+ else {
+ GPU_texture_mipmap_mode(*tex, false, true);
+ }
+ }
+
+ /* if `ibuf` was given, we don't own the `ibuf_intern` */
+ if (ibuf == NULL) {
+ BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ }
+
+ GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
+
+ return *tex;
+}
+
+GPUTexture *BKE_image_get_gpu_texture(Image *image, ImageUser *iuser, ImBuf *ibuf)
+{
+ return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D);
+}
+
+GPUTexture *BKE_image_get_gpu_tiles(Image *image, ImageUser *iuser, ImBuf *ibuf)
+{
+ return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D_ARRAY);
+}
+
+GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibuf)
+{
+ return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_TILE_MAPPING);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delayed GPU texture free
+ *
+ * Image datablocks can be deleted by any thread, but there may not be any active OpenGL context.
+ * In that case we push them into a queue and free the buffers later.
+ * \{ */
+
+static LinkNode *gpu_texture_free_queue = NULL;
+static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
+
+static void gpu_free_unused_buffers(void)
+{
+ if (gpu_texture_free_queue == NULL) {
+ return;
+ }
+
+ BLI_mutex_lock(&gpu_texture_queue_mutex);
+
+ if (gpu_texture_free_queue != NULL) {
+ GPUTexture *tex;
+ while ((tex = (GPUTexture *)BLI_linklist_pop(&gpu_texture_free_queue))) {
+ GPU_texture_free(tex);
+ }
+ gpu_texture_free_queue = NULL;
+ }
+
+ BLI_mutex_unlock(&gpu_texture_queue_mutex);
+}
+
+void BKE_image_free_unused_gpu_textures()
+{
+ if (BLI_thread_is_main()) {
+ gpu_free_unused_buffers();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Deletion
+ * \{ */
+
+static void image_free_gpu(Image *ima, const bool immediate)
+{
+ for (int eye = 0; eye < 2; eye++) {
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (ima->gputexture[i][eye] != NULL) {
+ if (immediate) {
+ GPU_texture_free(ima->gputexture[i][eye]);
+ }
+ else {
+ BLI_mutex_lock(&gpu_texture_queue_mutex);
+ BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
+ BLI_mutex_unlock(&gpu_texture_queue_mutex);
+ }
+
+ ima->gputexture[i][eye] = NULL;
+ }
+ }
+ }
+
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+}
+
+void BKE_image_free_gputextures(Image *ima)
+{
+ image_free_gpu(ima, BLI_thread_is_main());
+}
+
+void BKE_image_free_all_gputextures(Main *bmain)
+{
+ if (bmain) {
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ BKE_image_free_gputextures(ima);
+ }
+ }
+}
+
+/* same as above but only free animated images */
+void BKE_image_free_anim_gputextures(Main *bmain)
+{
+ if (bmain) {
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (BKE_image_is_animated(ima)) {
+ BKE_image_free_gputextures(ima);
+ }
+ }
+ }
+}
+
+void BKE_image_free_old_gputextures(Main *bmain)
+{
+ static int lasttime = 0;
+ int ctime = (int)PIL_check_seconds_timer();
+
+ /*
+ * Run garbage collector once for every collecting period of time
+ * if textimeout is 0, that's the option to NOT run the collector
+ */
+ if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) {
+ return;
+ }
+
+ /* of course not! */
+ if (G.is_rendering) {
+ return;
+ }
+
+ lasttime = ctime;
+
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
+ /* If it's in GL memory, deallocate and set time tag to current time
+ * This gives textures a "second chance" to be used before dying. */
+ if (BKE_image_has_opengl_texture(ima)) {
+ BKE_image_free_gputextures(ima);
+ ima->lastused = ctime;
+ }
+ /* Otherwise, just kill the buffers */
+ else {
+ BKE_image_free_buffers(ima);
+ }
+ }
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Update
+ * \{ */
+
+static ImBuf *update_do_scale(uchar *rect,
+ float *rect_float,
+ int *x,
+ int *y,
+ int *w,
+ int *h,
+ int limit_w,
+ int limit_h,
+ int full_w,
+ int full_h)
+{
+ /* Partial update with scaling. */
+ float xratio = limit_w / (float)full_w;
+ float yratio = limit_h / (float)full_h;
+
+ int part_w = *w, part_h = *h;
+
+ /* Find sub coordinates in scaled image. Take ceiling because we will be
+ * losing 1 pixel due to rounding errors in x,y. */
+ *x *= xratio;
+ *y *= yratio;
+ *w = (int)ceil(xratio * (*w));
+ *h = (int)ceil(yratio * (*h));
+
+ /* ...but take back if we are over the limit! */
+ if (*x + *w > limit_w) {
+ (*w)--;
+ }
+ if (*y + *h > limit_h) {
+ (*h)--;
+ }
+
+ /* Scale pixels. */
+ ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, part_w, part_h, 4);
+ IMB_scaleImBuf(ibuf, *w, *h);
+
+ return ibuf;
+}
+
+static void gpu_texture_update_scaled(GPUTexture *tex,
+ uchar *rect,
+ float *rect_float,
+ int full_w,
+ int full_h,
+ int x,
+ int y,
+ int layer,
+ const int *tile_offset,
+ const int *tile_size,
+ int w,
+ int h)
+{
+ ImBuf *ibuf;
+ if (layer > -1) {
+ ibuf = update_do_scale(
+ rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h);
+
+ /* Shift to account for tile packing. */
+ x += tile_offset[0];
+ y += tile_offset[1];
+ }
+ else {
+ /* Partial update with scaling. */
+ int limit_w = smaller_power_of_2_limit(full_w);
+ int limit_h = smaller_power_of_2_limit(full_h);
+
+ ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
+ }
+
+ void *data = (ibuf->rect_float) ? (void *)(ibuf->rect_float) : (void *)(ibuf->rect);
+ eGPUDataFormat data_format = (ibuf->rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
+
+ GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
+
+ IMB_freeImBuf(ibuf);
+}
+
+static void gpu_texture_update_unscaled(GPUTexture *tex,
+ uchar *rect,
+ float *rect_float,
+ int x,
+ int y,
+ int layer,
+ const int tile_offset[2],
+ int w,
+ int h,
+ int tex_stride,
+ int tex_offset)
+{
+ if (layer > -1) {
+ /* Shift to account for tile packing. */
+ x += tile_offset[0];
+ y += tile_offset[1];
+ }
+
+ void *data = (rect_float) ? (void *)(rect_float + tex_offset) : (void *)(rect + tex_offset);
+ eGPUDataFormat data_format = (rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
+
+ /* Partial update without scaling. Stride and offset are used to copy only a
+ * subset of a possible larger buffer than what we are updating. */
+ GPU_unpack_row_length_set(tex_stride);
+
+ GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
+ /* Restore default. */
+ GPU_unpack_row_length_set(0);
+}
+
+static void gpu_texture_update_from_ibuf(
+ GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
+{
+ bool scaled;
+ if (tile != NULL) {
+ int *tilesize = tile->runtime.tilearray_size;
+ scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
+ }
+ else {
+ scaled = is_over_resolution_limit(ibuf->x, ibuf->y);
+ }
+
+ if (scaled) {
+ /* Extra padding to account for bleed from neighboring pixels. */
+ const int padding = 4;
+ const int xmax = min_ii(x + w + padding, ibuf->x);
+ const int ymax = min_ii(y + h + padding, ibuf->y);
+ x = max_ii(x - padding, 0);
+ y = max_ii(y - padding, 0);
+ w = xmax - x;
+ h = ymax - y;
+ }
+
+ /* Get texture data pointers. */
+ float *rect_float = ibuf->rect_float;
+ uchar *rect = (uchar *)ibuf->rect;
+ int tex_stride = ibuf->x;
+ int tex_offset = ibuf->channels * (y * ibuf->x + x);
+
+ if (rect_float == NULL) {
+ /* Byte pixels. */
+ if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
+ ibuf->rect_colorspace);
+
+ rect = (uchar *)MEM_mallocN(sizeof(uchar) * 4 * w * h, __func__);
+ if (rect == NULL) {
+ return;
+ }
+
+ tex_stride = w;
+ tex_offset = 0;
+
+ /* Convert to scene linear with sRGB compression, and premultiplied for
+ * correct texture interpolation. */
+ const bool store_premultiplied = (ima->alpha_mode == IMA_ALPHA_PREMUL);
+ IMB_colormanagement_imbuf_to_byte_texture(
+ rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied);
+ }
+ }
+ else {
+ /* Float pixels. */
+ const bool store_premultiplied = (ima->alpha_mode != IMA_ALPHA_STRAIGHT);
+
+ if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ rect_float = (float *)MEM_mallocN(sizeof(float) * 4 * w * h, __func__);
+ if (rect_float == NULL) {
+ return;
+ }
+
+ tex_stride = w;
+ tex_offset = 0;
+
+ IMB_colormanagement_imbuf_to_float_texture(
+ rect_float, x, y, w, h, ibuf, store_premultiplied);
+ }
+ }
+
+ GPU_texture_bind(tex, 0);
+
+ if (scaled) {
+ /* Slower update where we first have to scale the input pixels. */
+ if (tile != NULL) {
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int *tilesize = tile->runtime.tilearray_size;
+ int tilelayer = tile->runtime.tilearray_layer;
+ gpu_texture_update_scaled(
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
+ }
+ else {
+ gpu_texture_update_scaled(
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, NULL, NULL, w, h);
+ }
+ }
+ else {
+ /* Fast update at same resolution. */
+ if (tile != NULL) {
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int tilelayer = tile->runtime.tilearray_layer;
+ gpu_texture_update_unscaled(
+ tex, rect, rect_float, x, y, tilelayer, tileoffset, w, h, tex_stride, tex_offset);
+ }
+ else {
+ gpu_texture_update_unscaled(
+ tex, rect, rect_float, x, y, -1, NULL, w, h, tex_stride, tex_offset);
+ }
+ }
+
+ /* Free buffers if needed. */
+ if (rect && rect != (uchar *)ibuf->rect) {
+ MEM_freeN(rect);
+ }
+ if (rect_float && rect_float != ibuf->rect_float) {
+ MEM_freeN(rect_float);
+ }
+
+ if (GPU_mipmap_enabled()) {
+ GPU_texture_generate_mipmap(tex);
+ }
+ else {
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+ }
+
+ GPU_texture_unbind(tex);
+}
+
+/* Partial update of texture for texture painting. This is often much
+ * quicker than fully updating the texture for high resolution images. */
+void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
+{
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+
+ if ((ibuf == NULL) || (w == 0) || (h == 0)) {
+ /* Full reload of texture. */
+ BKE_image_free_gputextures(ima);
+ }
+
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
+ /* Check if we need to update the main gputexture. */
+ if (tex != NULL && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
+ }
+
+ /* Check if we need to update the array gputexture. */
+ tex = ima->gputexture[TEXTARGET_2D_ARRAY][0];
+ if (tex != NULL) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+}
+
+/* these two functions are called on entering and exiting texture paint mode,
+ * temporary disabling/enabling mipmapping on all images for quick texture
+ * updates with glTexSubImage2D. images that didn't change don't have to be
+ * re-uploaded to OpenGL */
+void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
+{
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (BKE_image_has_opengl_texture(ima)) {
+ if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
+ for (int eye = 0; eye < 2; eye++) {
+ for (int a = 0; a < TEXTARGET_COUNT; a++) {
+ if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
+ GPUTexture *tex = ima->gputexture[a][eye];
+ if (tex != NULL) {
+ GPU_texture_mipmap_mode(tex, mipmap, true);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BKE_image_free_gputextures(ima);
+ }
+ }
+ else {
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 00a42b12e07..0f81d45c10f 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -412,6 +412,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return ELEM(id_type_used, ID_MA);
case ID_VO:
return ELEM(id_type_used, ID_MA);
+ case ID_SIM:
+ return ELEM(id_type_used, ID_OB, ID_IM);
case ID_IM:
case ID_VF:
case ID_TXT:
@@ -422,7 +424,6 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_PAL:
case ID_PC:
case ID_CF:
- case ID_SIM:
/* Those types never use/reference other IDs... */
return false;
case ID_IP:
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 34835fd1e35..aa72493e472 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -959,14 +959,13 @@ void BKE_object_material_array_assign(Main *bmain,
const bool to_object_only)
{
int actcol_orig = ob->actcol;
- short i;
while ((ob->totcol > totcol) && BKE_object_material_slot_remove(bmain, ob)) {
/* pass */
}
/* now we have the right number of slots */
- for (i = 0; i < totcol; i++) {
+ for (int i = 0; i < totcol; i++) {
if (to_object_only && ob->matbits[i] == 0) {
/* If we only assign to object, and that slot uses obdata material, do nothing. */
continue;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 4a65c6ff5e7..5b4dbc66cc2 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1866,3 +1866,84 @@ void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip
DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
movieclip_selection_sync(clip, (MovieClip *)clip->id.orig_id);
}
+
+/* -------------------------------------------------------------------- */
+/** \name GPU textures
+ * \{ */
+
+static GPUTexture **movieclip_get_gputexture_ptr(MovieClip *clip,
+ MovieClipUser *cuser,
+ eGPUTextureTarget textarget)
+{
+ LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) {
+ if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
+ if (tex == NULL) {
+ tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture),
+ __func__);
+
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ tex->gputexture[i] = NULL;
+ }
+
+ memcpy(&tex->user, cuser, sizeof(MovieClipUser));
+ BLI_addtail(&clip->runtime.gputextures, tex);
+ }
+
+ return &tex->gputexture[textarget];
+ }
+ }
+ return NULL;
+}
+
+GPUTexture *BKE_movieclip_get_gpu_texture(MovieClip *clip, MovieClipUser *cuser)
+{
+ if (clip == NULL) {
+ return NULL;
+ }
+
+ GPUTexture **tex = movieclip_get_gputexture_ptr(clip, cuser, TEXTARGET_2D);
+ if (*tex) {
+ return *tex;
+ }
+
+ /* check if we have a valid image buffer */
+ ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
+ if (ibuf == NULL) {
+ *tex = GPU_texture_create_error(2, false);
+ return *tex;
+ }
+
+ /* This only means RGBA16F instead of RGBA32F. */
+ const bool high_bitdepth = false;
+ const bool store_premultiplied = ibuf->rect_float ? false : true;
+ *tex = IMB_create_gpu_texture(ibuf, high_bitdepth, store_premultiplied);
+
+ /* Do not generate mips for movieclips... too slow. */
+ GPU_texture_mipmap_mode(*tex, false, true);
+
+ IMB_freeImBuf(ibuf);
+
+ return *tex;
+}
+
+void BKE_movieclip_free_gputexture(struct MovieClip *clip)
+{
+ /* number of gpu textures to keep around as cache
+ * We don't want to keep too many GPU textures for
+ * movie clips around, as they can be large.*/
+ const int MOVIECLIP_NUM_GPUTEXTURES = 1;
+
+ while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
+ MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead(
+ &clip->runtime.gputextures);
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ /* free glsl image binding */
+ if (tex->gputexture[i]) {
+ GPU_texture_free(tex->gputexture[i]);
+ tex->gputexture[i] = NULL;
+ }
+ }
+ MEM_freeN(tex);
+ }
+}
+/** \} */ \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 20d65e52b09..8d7cb90fb71 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -61,6 +61,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_simulation.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
@@ -845,12 +846,12 @@ static void socket_id_user_increment(bNodeSocket *sock)
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
- id_us_plus(&default_value->value->id);
+ id_us_plus((ID *)default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
- id_us_plus(&default_value->value->id);
+ id_us_plus((ID *)default_value->value);
break;
}
case SOCK_FLOAT:
@@ -2493,6 +2494,7 @@ ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree)
&bmain->textures,
&bmain->scenes,
&bmain->linestyles,
+ &bmain->simulations,
NULL};
for (int i = 0; lists[i] != NULL; i++) {
@@ -3637,6 +3639,16 @@ void ntreeUpdateAllUsers(Main *main, ID *ngroup)
FOREACH_NODETREE_END;
}
+static void ntreeUpdateSimulationDependencies(Main *main, bNodeTree *simulation_ntree)
+{
+ FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
+ if (GS(owner_id->name) == ID_SIM && ntree == simulation_ntree) {
+ BKE_simulation_update_dependencies((Simulation *)owner_id, main);
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
{
bNode *node;
@@ -3679,7 +3691,6 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
ntreeInterfaceTypeUpdate(ntree);
}
- /* XXX hack, should be done by depsgraph!! */
if (bmain) {
ntreeUpdateAllUsers(bmain, &ntree->id);
}
@@ -3695,6 +3706,11 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
ntree_validate_links(ntree);
}
+ if (bmain != NULL && ntree->typeinfo == ntreeType_Simulation &&
+ (ntree->id.flag & LIB_EMBEDDED_DATA)) {
+ ntreeUpdateSimulationDependencies(bmain, ntree);
+ }
+
/* clear update flags */
for (node = ntree->nodes.first; node; node = node->next) {
node->update = 0;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index b7fd6a50e6d..f77c79a2be7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -2409,7 +2409,7 @@ static bool ob_parcurve(Object *ob, Object *par, float mat[4][4])
/* ctime is now a proper var setting of Curve which gets set by Animato like any other var
* that's animated, but this will only work if it actually is animated.
*
- * We divide the curvetime calculated in the previous step by the length of the path,
+ * We divide the curve-time calculated in the previous step by the length of the path,
* to get a time factor, which then gets clamped to lie within 0.0 - 1.0 range.
*/
if (cu->pathlen) {
@@ -3964,15 +3964,20 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
return flag;
}
-/* Check of objects moves in time. */
-/* NOTE: This function is currently optimized for usage in combination
- * with mti->canDeform, so modifiers can quickly check if their target
- * objects moves (causing deformation motion blur) or not.
+/**
+ * Check of objects moves in time.
+ *
+ * \note This function is currently optimized for usage in combination
+ * with modifier deformation checks (#eModifierTypeType_OnlyDeform),
+ * so modifiers can quickly check if their target objects moves
+ * (causing deformation motion blur) or not.
*
* This makes it possible to give some degree of false-positives here,
* but it's currently an acceptable tradeoff between complexity and check
* speed. In combination with checks of modifier stack and real life usage
- * percentage of false-positives shouldn't be that height.
+ * percentage of false-positives shouldn't be that high.
+ *
+ * \note This function does not consider physics systems.
*/
bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
{
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index f498e147110..413acde62d5 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -523,7 +523,7 @@ static void make_duplis_font(const DupliContext *ctx)
/* Safety check even if it might fail badly when called for original object. */
const bool is_eval_curve = DEG_is_evaluated_id(&cu->id);
- /* advance matching BLI_strncpy_wchar_from_utf8 */
+ /* Advance matching BLI_str_utf8_as_utf32. */
for (a = 0; a < text_len; a++, ct++) {
/* XXX That G.main is *really* ugly, but not sure what to do here...
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index d6fbba74a89..d4edcf88389 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1691,7 +1691,6 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
BKE_mesh_update_customdata_pointers(orig_me, true);
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY);
- return;
}
void BKE_sculpt_update_object_for_edit(
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 42276b7f5c0..b16fc08a4af 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -6069,3 +6069,61 @@ bool BKE_sequencer_render_loop_check(Sequence *seq_main, Sequence *seq)
return false;
}
+
+static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
+{
+ LISTBASE_FOREACH (Sequence *, user_seq, seqbase) {
+ /* Look in metas for usage of seq. */
+ if (user_seq->type == SEQ_TYPE_META) {
+ sequencer_flag_users_for_removal(scene, &user_seq->seqbase, seq);
+ }
+
+ /* Clear seq from modifiers. */
+ SequenceModifierData *smd;
+ for (smd = user_seq->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence == seq) {
+ smd->mask_sequence = NULL;
+ }
+ }
+
+ /* Remove effects, that use seq. */
+ if ((user_seq->seq1 && user_seq->seq1 == seq) || (user_seq->seq2 && user_seq->seq2 == seq) ||
+ (user_seq->seq3 && user_seq->seq3 == seq)) {
+ user_seq->flag |= SEQ_FLAG_DELETE;
+ /* Strips can be used as mask even if not in same seqbase. */
+ sequencer_flag_users_for_removal(scene, &scene->ed->seqbase, user_seq);
+ }
+ }
+}
+
+/* Flag seq and its users (effects) for removal. */
+void BKE_sequencer_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
+{
+ if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) {
+ return;
+ }
+
+ /* Flag and remove meta children. */
+ if (seq->type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
+ BKE_sequencer_flag_for_removal(scene, &seq->seqbase, meta_child);
+ }
+ }
+
+ seq->flag |= SEQ_FLAG_DELETE;
+ sequencer_flag_users_for_removal(scene, seqbase, seq);
+}
+
+/* Remove all flagged sequences, return true if sequence is removed. */
+void BKE_sequencer_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
+{
+ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
+ if (seq->flag & SEQ_FLAG_DELETE) {
+ if (seq->type == SEQ_TYPE_META) {
+ BKE_sequencer_remove_flagged_sequences(scene, &seq->seqbase);
+ }
+ BLI_remlink(seqbase, seq);
+ BKE_sequence_free(scene, seq, true);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 95340e4e29c..c0fc8fcb464 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -112,8 +112,8 @@ static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
BKE_simulation_state_copy_data(state_src, state_dst);
}
- BLI_duplicatelist(&simulation_dst->persistent_data_handles,
- &simulation_src->persistent_data_handles);
+ BLI_listbase_clear(&simulation_dst->dependencies);
+ BLI_duplicatelist(&simulation_dst->dependencies, &simulation_src->dependencies);
}
static void simulation_free_data(ID *id)
@@ -130,7 +130,7 @@ static void simulation_free_data(ID *id)
BKE_simulation_state_remove_all(simulation);
- BLI_freelistN(&simulation->persistent_data_handles);
+ BLI_freelistN(&simulation->dependencies);
}
static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -140,9 +140,8 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree);
}
- LISTBASE_FOREACH (
- PersistentDataHandleItem *, handle_item, &simulation->persistent_data_handles) {
- BKE_LIB_FOREACHID_PROCESS_ID(data, handle_item->id, IDWALK_CB_USER);
+ LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation->dependencies) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, dependency->id, IDWALK_CB_USER);
}
}
@@ -284,6 +283,14 @@ void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *
blender::sim::update_simulation_in_depsgraph(depsgraph, scene, simulation);
}
+void BKE_simulation_update_dependencies(Simulation *simulation, Main *bmain)
+{
+ bool dependencies_changed = blender::sim::update_simulation_dependencies(simulation);
+ if (dependencies_changed) {
+ DEG_relations_tag_update(bmain);
+ }
+}
+
using StateTypeMap = blender::Map<std::string, std::unique_ptr<SimulationStateType>>;
template<typename T>
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
index b2633985ac7..a0979bc75bd 100644
--- a/source/blender/blenlib/BLI_float3.hh
+++ b/source/blender/blenlib/BLI_float3.hh
@@ -143,6 +143,17 @@ struct float3 {
return normalize_v3(*this);
}
+ /**
+ * Normalizes the vector in place.
+ */
+ void normalize()
+ {
+ normalize_v3(*this);
+ }
+
+ /**
+ * Returns a normalized vector. The original vector is not changed.
+ */
float3 normalized() const
{
float3 result;
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
index 185cffd13ac..b4f12f17cc2 100644
--- a/source/blender/blenlib/BLI_float4x4.hh
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -71,8 +71,8 @@ struct float4x4 {
float4x4 inverted() const
{
- float result[4][4];
- invert_m4_m4(result, values);
+ float4x4 result;
+ invert_m4_m4(result.values, values);
return result;
}
@@ -86,6 +86,18 @@ struct float4x4 {
return this->inverted();
}
+ float4x4 transposed() const
+ {
+ float4x4 result;
+ transpose_m4_m4(result.values, values);
+ return result;
+ }
+
+ float4x4 inverted_transposed_affine() const
+ {
+ return this->inverted_affine().transposed();
+ }
+
struct float3x3_ref {
const float4x4 &data;
diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh
new file mode 100644
index 00000000000..c20c4ef9677
--- /dev/null
+++ b/source/blender/blenlib/BLI_multi_value_map.hh
@@ -0,0 +1,134 @@
+/*
+ * 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 __BLI_MULTI_VALUE_MAP_HH__
+#define __BLI_MULTI_VALUE_MAP_HH__
+
+/** \file
+ * \ingroup bli
+ *
+ * A `blender::MultiValueMap<Key, Value>` is an unordered associative container that stores
+ * key-value pairs. It is different from `blender::Map` in that it can store multiple values for
+ * the same key. The list of values that corresponds to a specific key can contain duplicates
+ * and their order is maintained.
+ *
+ * This data structure is different from a `std::multi_map`, because multi_map can store the same
+ * key more than once and MultiValueMap can't.
+ *
+ * Currently, this class exists mainly for convenience. There are no performance benefits over
+ * using Map<Key, Vector<Value>>. In the future, a better implementation for this data structure
+ * can be developed.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+namespace blender {
+
+template<typename Key, typename Value> class MultiValueMap {
+ private:
+ using MapType = Map<Key, Vector<Value>>;
+ MapType map_;
+
+ public:
+ /**
+ * Add a new value for the given key. If the map contains the key already, the value will be
+ * appended to the list of corresponding values.
+ */
+ void add(const Key &key, const Value &value)
+ {
+ this->add_as(key, value);
+ }
+ void add(const Key &key, Value &&value)
+ {
+ this->add_as(key, std::move(value));
+ }
+ void add(Key &&key, const Value &value)
+ {
+ this->add_as(std::move(key), value);
+ }
+ void add(Key &&key, Value &&value)
+ {
+ this->add_as(std::move(key), std::move(value));
+ }
+ template<typename ForwardKey, typename ForwardValue>
+ void add_as(ForwardKey &&key, ForwardValue &&value)
+ {
+ Vector<Value> &vector = map_.lookup_or_add_default_as(std::forward<ForwardKey>(key));
+ vector.append(std::forward<ForwardValue>(value));
+ }
+
+ /**
+ * Add all given values to the key.
+ */
+ void add_multiple(const Key &key, Span<Value> values)
+ {
+ this->add_multiple_as(key, values);
+ }
+ void add_multiple(Key &&key, Span<Value> values)
+ {
+ this->add_multiple_as(std::move(key), values);
+ }
+ template<typename ForwardKey> void add_multiple_as(ForwardKey &&key, Span<Value> values)
+ {
+ Vector<Value> &vector = map_.lookup_or_add_default_as(std::forward<ForwardKey>(key));
+ vector.extend(values);
+ }
+
+ /**
+ * Get a span to all the values that are stored for the given key.
+ */
+ Span<Value> lookup(const Key &key) const
+ {
+ return this->lookup_as(key);
+ }
+ template<typename ForwardKey> Span<Value> lookup_as(const ForwardKey &key) const
+ {
+ const Vector<Value> *vector = map_.lookup_ptr_as(key);
+ if (vector != nullptr) {
+ return vector->as_span();
+ }
+ return {};
+ }
+
+ /**
+ * Note: This signature will change when the implementation changes.
+ */
+ typename MapType::ItemIterator items() const
+ {
+ return map_.items();
+ }
+
+ /**
+ * Note: This signature will change when the implementation changes.
+ */
+ typename MapType::KeyIterator keys() const
+ {
+ return map_.keys();
+ }
+
+ /**
+ * Note: This signature will change when the implementation changes.
+ */
+ typename MapType::ValueIterator values() const
+ {
+ return map_.values();
+ }
+};
+
+} // namespace blender
+
+#endif /* __BLI_MULTI_VALUE_MAP_HH__ */
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
index 612ac0bbe19..7a98ee0f2bb 100644
--- a/source/blender/blenlib/BLI_rand.hh
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -63,6 +63,15 @@ class RandomNumberGenerator {
}
/**
+ * \return Random value (0..N), but never N.
+ */
+ int32_t get_int32(int32_t max_exclusive)
+ {
+ BLI_assert(max_exclusive > 0);
+ return this->get_int32() % max_exclusive;
+ }
+
+ /**
* \return Random value (0..1), but never 1.0.
*/
double get_double()
@@ -78,6 +87,35 @@ class RandomNumberGenerator {
return (float)this->get_int32() / 0x80000000;
}
+ template<typename T> void shuffle(MutableSpan<T> values)
+ {
+ /* Cannot shuffle arrays of this size yet. */
+ BLI_assert(values.size() <= INT32_MAX);
+
+ for (int i = values.size() - 1; i >= 2; i--) {
+ int j = this->get_int32(i);
+ if (i != j) {
+ std::swap(values[i], values[j]);
+ }
+ }
+ }
+
+ /**
+ * Compute uniformly distributed barycentric coordinates.
+ */
+ float3 get_barycentric_coordinates()
+ {
+ float rand1 = this->get_float();
+ float rand2 = this->get_float();
+
+ if (rand1 + rand2 > 1.0f) {
+ rand1 = 1.0f - rand1;
+ rand2 = 1.0f - rand2;
+ }
+
+ return float3(rand1, rand2, 1.0f - rand1 - rand2);
+ }
+
float2 get_unit_float2();
float3 get_unit_float3();
float2 get_triangle_sample(float2 v1, float2 v2, float2 v3);
diff --git a/source/blender/blenlib/BLI_resource_collector.hh b/source/blender/blenlib/BLI_resource_collector.hh
index 10d610da618..e1be87d8af2 100644
--- a/source/blender/blenlib/BLI_resource_collector.hh
+++ b/source/blender/blenlib/BLI_resource_collector.hh
@@ -79,6 +79,12 @@ class ResourceCollector : NonCopyable, NonMovable {
*/
template<typename T> void add(destruct_ptr<T> resource, const char *name)
{
+ /* There is no need to keep track of such types. */
+ if (std::is_trivially_destructible_v<T>) {
+ resource.release();
+ return;
+ }
+
BLI_assert(resource.get() != nullptr);
this->add(
resource.release(),
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 2d875fe73be..81b86f647f6 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -87,7 +87,7 @@ namespace blender {
*/
template<typename T> class Span {
private:
- const T *start_ = nullptr;
+ const T *data_ = nullptr;
int64_t size_ = 0;
public:
@@ -96,13 +96,13 @@ template<typename T> class Span {
*/
Span() = default;
- Span(const T *start, int64_t size) : start_(start), size_(size)
+ Span(const T *start, int64_t size) : data_(start), size_(size)
{
BLI_assert(size >= 0);
}
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
- Span(const U *start, int64_t size) : start_((const T *)start), size_(size)
+ Span(const U *start, int64_t size) : data_((const T *)start), size_(size)
{
BLI_assert(size >= 0);
}
@@ -136,7 +136,7 @@ template<typename T> class Span {
* Span<Derived *> -> Span<Base *>
*/
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
- Span(Span<U> array) : start_((T *)array.data()), size_(array.size())
+ Span(Span<U> array) : data_((T *)array.data()), size_(array.size())
{
}
@@ -149,7 +149,7 @@ template<typename T> class Span {
BLI_assert(start >= 0);
BLI_assert(size >= 0);
BLI_assert(start + size <= this->size() || size == 0);
- return Span(start_ + start, size);
+ return Span(data_ + start, size);
}
Span slice(IndexRange range) const
@@ -207,17 +207,17 @@ template<typename T> class Span {
*/
const T *data() const
{
- return start_;
+ return data_;
}
const T *begin() const
{
- return start_;
+ return data_;
}
const T *end() const
{
- return start_ + size_;
+ return data_ + size_;
}
/**
@@ -228,7 +228,7 @@ template<typename T> class Span {
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
- return start_[index];
+ return data_[index];
}
/**
@@ -300,7 +300,7 @@ template<typename T> class Span {
const T &first() const
{
BLI_assert(size_ > 0);
- return start_[0];
+ return data_[0];
}
/**
@@ -310,7 +310,7 @@ template<typename T> class Span {
const T &last() const
{
BLI_assert(size_ > 0);
- return start_[size_ - 1];
+ return data_[size_ - 1];
}
/**
@@ -320,7 +320,7 @@ template<typename T> class Span {
T get(int64_t index, const T &fallback) const
{
if (index < size_ && index >= 0) {
- return start_[index];
+ return data_[index];
}
return fallback;
}
@@ -336,9 +336,9 @@ template<typename T> class Span {
BLI_assert(size_ < 1000);
for (int64_t i = 0; i < size_; i++) {
- const T &value = start_[i];
+ const T &value = data_[i];
for (int64_t j = i + 1; j < size_; j++) {
- if (value == start_[j]) {
+ if (value == data_[j]) {
return true;
}
}
@@ -358,7 +358,7 @@ template<typename T> class Span {
BLI_assert(size_ < 1000);
for (int64_t i = 0; i < size_; i++) {
- const T &value = start_[i];
+ const T &value = data_[i];
if (other.contains(value)) {
return true;
}
@@ -383,7 +383,7 @@ template<typename T> class Span {
int64_t first_index_try(const T &search_value) const
{
for (int64_t i = 0; i < size_; i++) {
- if (start_[i] == search_value) {
+ if (data_[i] == search_value) {
return i;
}
}
@@ -406,7 +406,7 @@ template<typename T> class Span {
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
- return Span<NewT>(reinterpret_cast<const NewT *>(start_), new_size);
+ return Span<NewT>(reinterpret_cast<const NewT *>(data_), new_size);
}
/**
@@ -439,13 +439,13 @@ template<typename T> class Span {
*/
template<typename T> class MutableSpan {
private:
- T *start_;
+ T *data_;
int64_t size_;
public:
MutableSpan() = default;
- MutableSpan(T *start, const int64_t size) : start_(start), size_(size)
+ MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
{
}
@@ -459,7 +459,7 @@ template<typename T> class MutableSpan {
operator Span<T>() const
{
- return Span<T>(start_, size_);
+ return Span<T>(data_, size_);
}
/**
@@ -475,7 +475,7 @@ template<typename T> class MutableSpan {
*/
void fill(const T &value)
{
- initialized_fill_n(start_, size_, value);
+ initialized_fill_n(data_, size_, value);
}
/**
@@ -486,7 +486,7 @@ template<typename T> class MutableSpan {
{
for (int64_t i : indices) {
BLI_assert(i < size_);
- start_[i] = value;
+ data_[i] = value;
}
}
@@ -496,23 +496,23 @@ template<typename T> class MutableSpan {
*/
T *data() const
{
- return start_;
+ return data_;
}
T *begin() const
{
- return start_;
+ return data_;
}
T *end() const
{
- return start_ + size_;
+ return data_ + size_;
}
T &operator[](const int64_t index) const
{
BLI_assert(index < this->size());
- return start_[index];
+ return data_[index];
}
/**
@@ -522,7 +522,7 @@ template<typename T> class MutableSpan {
MutableSpan slice(const int64_t start, const int64_t length) const
{
BLI_assert(start + length <= this->size());
- return MutableSpan(start_ + start, length);
+ return MutableSpan(data_ + start, length);
}
/**
@@ -571,7 +571,7 @@ template<typename T> class MutableSpan {
*/
Span<T> as_span() const
{
- return Span<T>(start_, size_);
+ return Span<T>(data_, size_);
}
/**
@@ -590,7 +590,7 @@ template<typename T> class MutableSpan {
T &last() const
{
BLI_assert(size_ > 0);
- return start_[size_ - 1];
+ return data_[size_ - 1];
}
/**
@@ -609,13 +609,24 @@ template<typename T> class MutableSpan {
}
/**
+ * Copy all values from another span into this span. This invokes undefined behavior when the
+ * destination contains uninitialized data and T is not trivially copy constructible.
+ * The size of both spans is expected to be the same.
+ */
+ void copy_from(Span<T> values)
+ {
+ BLI_assert(size_ == values.size());
+ initialized_copy_n(values.data(), size_, data_);
+ }
+
+ /**
* Returns a new span to the same underlying memory buffer. No conversions are done.
*/
template<typename NewT> MutableSpan<NewT> cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
- return MutableSpan<NewT>(reinterpret_cast<NewT *>(start_), new_size);
+ return MutableSpan<NewT>(reinterpret_cast<NewT *>(data_), new_size);
}
};
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index bc35e969e6a..2699f2498ac 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -755,6 +755,43 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
/** \} */
/* -------------------------------------------------------------------- */
+/** \name C++ Macros
+ * \{ */
+
+#ifdef __cplusplus
+
+/* Useful to port C code using enums to C++ where enums are strongly typed.
+ * To use after the enum declaration. */
+# define ENUM_OPERATORS(_enum_type) \
+ inline constexpr _enum_type operator|(_enum_type a, _enum_type b) \
+ { \
+ return a = static_cast<_enum_type>(static_cast<int>(a) | b); \
+ } \
+ inline constexpr _enum_type operator&(_enum_type a, _enum_type b) \
+ { \
+ return a = static_cast<_enum_type>(static_cast<int>(a) & b); \
+ } \
+ inline constexpr _enum_type operator~(_enum_type a) \
+ { \
+ return a = static_cast<_enum_type>(~static_cast<int>(a)); \
+ } \
+ inline _enum_type &operator|=(_enum_type &a, _enum_type b) \
+ { \
+ return a = static_cast<_enum_type>(static_cast<int>(a) | b); \
+ } \
+ inline _enum_type &operator&=(_enum_type &a, _enum_type b) \
+ { \
+ return a = static_cast<_enum_type>(static_cast<int>(a) & b); \
+ }
+
+#else
+/* Output nothing. */
+# define ENUM_OPERATORS(_type)
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Misc Macros
* \{ */
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 1bb674093bb..7eac511bf4a 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -561,7 +561,7 @@ class Vector {
/**
* Return a reference to the last element in the vector.
- * This will assert when the vector is empty.
+ * This invokes undefined behavior when the vector is empty.
*/
const T &last() const
{
diff --git a/source/blender/blenlib/BLI_vector_adaptor.hh b/source/blender/blenlib/BLI_vector_adaptor.hh
new file mode 100644
index 00000000000..cadffc0b445
--- /dev/null
+++ b/source/blender/blenlib/BLI_vector_adaptor.hh
@@ -0,0 +1,105 @@
+/*
+ * 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 __BLI_VECTOR_ADAPTOR_HH__
+#define __BLI_VECTOR_ADAPTOR_HH__
+
+/** \file
+ * \ingroup bli
+ *
+ * A `blender::VectorAdaptor` is a container with a fixed maximum size and does not own the
+ * underlying memory. When an adaptor is constructed, you have to provide it with an uninitialized
+ * array that will be filled when elements are added to the vector. The vector adaptor is not able
+ * to grow. Therefore, it is undefined behavior to add more elements than fit into the provided
+ * buffer.
+ */
+
+#include "BLI_span.hh"
+
+namespace blender {
+
+template<typename T> class VectorAdaptor {
+ private:
+ T *begin_;
+ T *end_;
+ T *capacity_end_;
+
+ public:
+ VectorAdaptor() : begin_(nullptr), end_(nullptr), capacity_end_(nullptr)
+ {
+ }
+
+ VectorAdaptor(T *data, int64_t capacity, int64_t size = 0)
+ : begin_(data), end_(data + size), capacity_end_(data + capacity)
+ {
+ }
+
+ VectorAdaptor(MutableSpan<T> span) : VectorAdaptor(span.data(), span.size(), 0)
+ {
+ }
+
+ void append(const T &value)
+ {
+ BLI_assert(end_ < capacity_end_);
+ new (end_) T(value);
+ end_++;
+ }
+
+ void append(T &&value)
+ {
+ BLI_assert(end_ < capacity_end_);
+ new (end_) T(std::move(value));
+ end_++;
+ }
+
+ void append_n_times(const T &value, int64_t n)
+ {
+ BLI_assert(end_ + n <= capacity_end_);
+ uninitialized_fill_n(end_, n, value);
+ end_ += n;
+ }
+
+ void extend(Span<T> values)
+ {
+ BLI_assert(end_ + values.size() <= capacity_end_);
+ uninitialized_copy_n(values.data(), values.size(), end_);
+ end_ += values.size();
+ }
+
+ int64_t capacity() const
+ {
+ return capacity_end_ - begin_;
+ }
+
+ int64_t size() const
+ {
+ return end_ - begin_;
+ }
+
+ bool is_empty() const
+ {
+ return begin_ == end_;
+ }
+
+ bool is_full() const
+ {
+ return end_ == capacity_end_;
+ }
+};
+
+} // namespace blender
+
+#endif /* __BLI_VECTOR_ADAPTOR_HH__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index c6e04d4147a..4997917a93f 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -267,6 +267,7 @@ set(SRC
BLI_utility_mixins.hh
BLI_uvproject.h
BLI_vector.hh
+ BLI_vector_adaptor.hh
BLI_vector_set.hh
BLI_vector_set_slots.hh
BLI_vfontdata.h
@@ -340,3 +341,29 @@ set_source_files_properties(
)
blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ tests/BLI_array_test.cc
+ tests/BLI_disjoint_set_test.cc
+ tests/BLI_edgehash_test.cc
+ tests/BLI_index_mask_test.cc
+ tests/BLI_index_range_test.cc
+ tests/BLI_linear_allocator_test.cc
+ tests/BLI_map_test.cc
+ tests/BLI_math_base_safe_test.cc
+ tests/BLI_memory_utils_test.cc
+ tests/BLI_multi_value_map_test.cc
+ tests/BLI_set_test.cc
+ tests/BLI_span_test.cc
+ tests/BLI_stack_cxx_test.cc
+ tests/BLI_string_ref_test.cc
+ tests/BLI_vector_set_test.cc
+ tests/BLI_vector_test.cc
+ )
+ set(TEST_LIB
+ bf_blenlib
+ )
+ include(GTestTesting)
+ blender_add_test_lib(bf_bli_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+endif()
diff --git a/tests/gtests/blenlib/BLI_array_test.cc b/source/blender/blenlib/tests/BLI_array_test.cc
index c01ba26ffd7..7348a6f93f3 100644
--- a/tests/gtests/blenlib/BLI_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_array_test.cc
@@ -4,7 +4,7 @@
#include "BLI_strict_flags.h"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(array, DefaultConstructor)
{
@@ -72,7 +72,7 @@ TEST(array, MoveConstructor)
Array<int> array = {5, 6, 7, 8};
Array<int> new_array(std::move(array));
- EXPECT_EQ(array.size(), 0);
+ EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(new_array.size(), 4);
EXPECT_EQ(new_array[0], 5);
EXPECT_EQ(new_array[1], 6);
@@ -101,7 +101,7 @@ TEST(array, MoveAssignment)
EXPECT_EQ(new_array.size(), 1);
new_array = std::move(array);
EXPECT_EQ(new_array.size(), 3);
- EXPECT_EQ(array.size(), 0);
+ EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(new_array[0], 1);
EXPECT_EQ(new_array[1], 2);
EXPECT_EQ(new_array[2], 3);
@@ -141,7 +141,7 @@ TEST(array, NoInitializationSizeConstructor)
using MyArray = Array<ConstructibleType>;
TypedBuffer<MyArray> buffer;
- memset(buffer, 100, sizeof(MyArray));
+ memset((void *)&buffer, 100, sizeof(MyArray));
/* Doing this to avoid some compiler optimization. */
for (int64_t i : IndexRange(sizeof(MyArray))) {
@@ -173,4 +173,4 @@ TEST(array, Fill)
EXPECT_EQ(array[4], 3);
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_disjoint_set_test.cc b/source/blender/blenlib/tests/BLI_disjoint_set_test.cc
index 22663b936d9..f30ee610b2a 100644
--- a/tests/gtests/blenlib/BLI_disjoint_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_disjoint_set_test.cc
@@ -5,7 +5,7 @@
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(disjoint_set, Test)
{
@@ -33,4 +33,4 @@ TEST(disjoint_set, Test)
EXPECT_FALSE(disjoint_set.in_same_set(0, 4));
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_edgehash_test.cc b/source/blender/blenlib/tests/BLI_edgehash_test.cc
index 23ad618825b..7106033df36 100644
--- a/tests/gtests/blenlib/BLI_edgehash_test.cc
+++ b/source/blender/blenlib/tests/BLI_edgehash_test.cc
@@ -5,10 +5,8 @@
#include <random>
#include <vector>
-extern "C" {
#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
-}
#define VALUE_1 POINTER_FROM_INT(1)
#define VALUE_2 POINTER_FROM_INT(2)
@@ -334,10 +332,12 @@ TEST(edgehash, StressTest)
/* check if the right ones have been removed */
for (int i = 0; i < shuffled.size(); i++) {
bool haskey = BLI_edgehash_haskey(eh, shuffled[i].v1, shuffled[i].v2);
- if (i < remove_until)
+ if (i < remove_until) {
ASSERT_FALSE(haskey);
- else
+ }
+ else {
ASSERT_TRUE(haskey);
+ }
}
/* reinsert all edges */
diff --git a/tests/gtests/blenlib/BLI_index_mask_test.cc b/source/blender/blenlib/tests/BLI_index_mask_test.cc
index bce467cadd9..4d6060e51c9 100644
--- a/tests/gtests/blenlib/BLI_index_mask_test.cc
+++ b/source/blender/blenlib/tests/BLI_index_mask_test.cc
@@ -3,7 +3,7 @@
#include "BLI_index_mask.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(index_mask, DefaultConstructor)
{
@@ -40,4 +40,4 @@ TEST(index_mask, RangeConstructor)
EXPECT_EQ(indices[2], 5);
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc
index 1c4d4a1a1f3..d472ded0f18 100644
--- a/tests/gtests/blenlib/BLI_index_range_test.cc
+++ b/source/blender/blenlib/tests/BLI_index_range_test.cc
@@ -5,7 +5,7 @@
#include "BLI_vector.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(index_range, DefaultConstructor)
{
@@ -140,4 +140,4 @@ TEST(index_range, AsSpan)
EXPECT_EQ(span[3], 7);
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
index 9c2dcdc7457..44b70d1f55d 100644
--- a/tests/gtests/blenlib/BLI_linear_allocator_test.cc
+++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
@@ -4,7 +4,7 @@
#include "BLI_strict_flags.h"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
static bool is_aligned(void *ptr, uint alignment)
{
@@ -115,4 +115,4 @@ TEST(linear_allocator, ConstructArrayCopy)
EXPECT_EQ(span2[2], 3);
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/source/blender/blenlib/tests/BLI_map_test.cc
index cebce218112..fe7b0f01279 100644
--- a/tests/gtests/blenlib/BLI_map_test.cc
+++ b/source/blender/blenlib/tests/BLI_map_test.cc
@@ -8,7 +8,7 @@
#include "BLI_vector.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(map, DefaultConstructor)
{
@@ -335,7 +335,7 @@ TEST(map, MoveConstructorSmall)
EXPECT_EQ(map2.size(), 2);
EXPECT_EQ(map2.lookup(1), 2.0f);
EXPECT_EQ(map2.lookup(4), 1.0f);
- EXPECT_EQ(map1.size(), 0);
+ EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(map1.lookup_ptr(4), nullptr);
}
@@ -349,7 +349,7 @@ TEST(map, MoveConstructorLarge)
EXPECT_EQ(map2.size(), 100);
EXPECT_EQ(map2.lookup(1), 1);
EXPECT_EQ(map2.lookup(4), 4);
- EXPECT_EQ(map1.size(), 0);
+ EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(map1.lookup_ptr(4), nullptr);
}
@@ -363,7 +363,7 @@ TEST(map, MoveAssignment)
EXPECT_EQ(map2.size(), 2);
EXPECT_EQ(map2.lookup(1), 2.0f);
EXPECT_EQ(map2.lookup(4), 1.0f);
- EXPECT_EQ(map1.size(), 0);
+ EXPECT_EQ(map1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(map1.lookup_ptr(4), nullptr);
}
@@ -587,4 +587,4 @@ TEST(map, Benchmark)
#endif /* Benchmark */
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_math_base_safe_test.cc b/source/blender/blenlib/tests/BLI_math_base_safe_test.cc
index 2e3e083cf92..2e3e083cf92 100644
--- a/tests/gtests/blenlib/BLI_math_base_safe_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_base_safe_test.cc
diff --git a/tests/gtests/blenlib/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
index b99db5c5eca..f3cb02b63d7 100644
--- a/tests/gtests/blenlib/BLI_memory_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
@@ -5,7 +5,7 @@
#include "BLI_strict_flags.h"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
struct MyValue {
static inline int alive = 0;
@@ -19,7 +19,7 @@ struct MyValue {
alive++;
}
- MyValue(const MyValue &other)
+ MyValue(const MyValue &UNUSED(other))
{
if (alive == 15) {
throw std::exception();
@@ -156,4 +156,4 @@ static_assert(is_convertible_pointer_v<int **, int **const>);
static_assert(is_convertible_pointer_v<int **, int *const *>);
static_assert(is_convertible_pointer_v<int **, int const *const *>);
-} // namespace blender
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_multi_value_map_test.cc b/source/blender/blenlib/tests/BLI_multi_value_map_test.cc
new file mode 100644
index 00000000000..7501fbe0d87
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_multi_value_map_test.cc
@@ -0,0 +1,109 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_multi_value_map.hh"
+#include "BLI_vector.hh"
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(multi_value_map, LookupNotExistant)
+{
+ MultiValueMap<int, int> map;
+ EXPECT_EQ(map.lookup(5).size(), 0);
+ map.add(2, 5);
+ EXPECT_EQ(map.lookup(5).size(), 0);
+}
+
+TEST(multi_value_map, LookupExistant)
+{
+ MultiValueMap<int, int> map;
+ map.add(2, 4);
+ map.add(2, 5);
+ map.add(3, 6);
+
+ EXPECT_EQ(map.lookup(2).size(), 2);
+ EXPECT_EQ(map.lookup(2)[0], 4);
+ EXPECT_EQ(map.lookup(2)[1], 5);
+
+ EXPECT_EQ(map.lookup(3).size(), 1);
+ EXPECT_EQ(map.lookup(3)[0], 6);
+}
+
+TEST(multi_value_map, AddMultiple)
+{
+ MultiValueMap<int, int> map;
+ map.add_multiple(2, {4, 5, 6});
+ map.add_multiple(2, {1, 2});
+ map.add_multiple(5, {7, 5, 3});
+
+ EXPECT_EQ(map.lookup(2).size(), 5);
+ EXPECT_EQ(map.lookup(2)[0], 4);
+ EXPECT_EQ(map.lookup(2)[1], 5);
+ EXPECT_EQ(map.lookup(2)[2], 6);
+ EXPECT_EQ(map.lookup(2)[3], 1);
+ EXPECT_EQ(map.lookup(2)[4], 2);
+
+ EXPECT_EQ(map.lookup(5).size(), 3);
+ EXPECT_EQ(map.lookup(5)[0], 7);
+ EXPECT_EQ(map.lookup(5)[1], 5);
+ EXPECT_EQ(map.lookup(5)[2], 3);
+}
+
+TEST(multi_value_map, Keys)
+{
+ MultiValueMap<int, int> map;
+ map.add(5, 7);
+ map.add(5, 7);
+ map.add_multiple(2, {6, 7, 8});
+
+ Vector<int> keys;
+ for (int key : map.keys()) {
+ keys.append(key);
+ }
+
+ EXPECT_EQ(keys.size(), 2);
+ EXPECT_TRUE(keys.contains(5));
+ EXPECT_TRUE(keys.contains(2));
+}
+
+TEST(multi_value_map, Values)
+{
+ MultiValueMap<int, int> map;
+ map.add(3, 5);
+ map.add_multiple(3, {1, 2});
+ map.add(6, 1);
+
+ Vector<Span<int>> values;
+ for (Span<int> value_span : map.values()) {
+ values.append(value_span);
+ }
+
+ EXPECT_EQ(values.size(), 2);
+}
+
+TEST(multi_value_map, Items)
+{
+ MultiValueMap<int, int> map;
+ map.add_multiple(4, {1, 2, 3});
+
+ for (auto &&item : map.items()) {
+ int key = item.key;
+ Span<int> values = item.value;
+ EXPECT_EQ(key, 4);
+ EXPECT_EQ(values.size(), 3);
+ EXPECT_EQ(values[0], 1);
+ EXPECT_EQ(values[1], 2);
+ EXPECT_EQ(values[2], 3);
+ }
+}
+
+TEST(multi_value_map, UniquePtr)
+{
+ /* Mostly testing if it compiles here. */
+ MultiValueMap<std::unique_ptr<int>, std::unique_ptr<int>> map;
+ map.add(std::make_unique<int>(4), std::make_unique<int>(6));
+ map.add(std::make_unique<int>(4), std::make_unique<int>(7));
+ EXPECT_EQ(map.lookup(std::make_unique<int>(10)).size(), 0);
+}
+
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/source/blender/blenlib/tests/BLI_set_test.cc
index fcd958dc2f1..7bd0b258df8 100644
--- a/tests/gtests/blenlib/BLI_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_set_test.cc
@@ -12,6 +12,7 @@
#include "testing/testing.h"
namespace blender {
+namespace tests {
TEST(set, DefaultConstructor)
{
@@ -81,7 +82,7 @@ TEST(set, MoveConstructor)
Set<int> set = {1, 2, 3};
EXPECT_EQ(set.size(), 3);
Set<int> set2(std::move(set));
- EXPECT_EQ(set.size(), 0);
+ EXPECT_EQ(set.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(set2.size(), 3);
}
@@ -106,7 +107,7 @@ TEST(set, MoveAssignment)
EXPECT_EQ(set.size(), 3);
Set<int> set2;
set2 = std::move(set);
- EXPECT_EQ(set.size(), 0);
+ EXPECT_EQ(set.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(set2.size(), 3);
}
@@ -279,31 +280,32 @@ struct Type2 {
uint32_t value;
};
-bool operator==(const Type1 &a, const Type1 &b)
+static bool operator==(const Type1 &a, const Type1 &b)
{
return a.value == b.value;
}
-bool operator==(const Type1 &a, const Type2 &b)
-{
- return a.value == b.value;
-}
-bool operator==(const Type2 &a, const Type1 &b)
+static bool operator==(const Type2 &a, const Type1 &b)
{
return a.value == b.value;
}
-template<> struct DefaultHash<Type1> {
- uint32_t operator()(const Type1 &value) const
+} // namespace tests
+
+/* This has to be defined in ::blender namespace. */
+template<> struct DefaultHash<tests::Type1> {
+ uint32_t operator()(const tests::Type1 &value) const
{
return value.value;
}
- uint32_t operator()(const Type2 &value) const
+ uint32_t operator()(const tests::Type2 &value) const
{
return value.value;
}
};
+namespace tests {
+
TEST(set, ContainsAs)
{
Set<Type1> set;
@@ -559,4 +561,5 @@ TEST(set, Benchmark)
#endif /* Benchmark */
+} // namespace tests
} // namespace blender
diff --git a/tests/gtests/blenlib/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc
index 9c2e7cf26fb..587497624f4 100644
--- a/tests/gtests/blenlib/BLI_span_test.cc
+++ b/source/blender/blenlib/tests/BLI_span_test.cc
@@ -5,7 +5,7 @@
#include "BLI_vector.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(span, FromSmallVector)
{
@@ -295,4 +295,17 @@ TEST(span, VoidPointerSpan)
func1({&a, &b, &c});
}
-} // namespace blender
+TEST(span, CopyFrom)
+{
+ std::array<int, 4> src = {5, 6, 7, 8};
+ std::array<int, 4> dst = {1, 2, 3, 4};
+
+ EXPECT_EQ(dst[2], 3);
+ MutableSpan(dst).copy_from(src);
+ EXPECT_EQ(dst[0], 5);
+ EXPECT_EQ(dst[1], 6);
+ EXPECT_EQ(dst[2], 7);
+ EXPECT_EQ(dst[3], 8);
+}
+
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_stack_cxx_test.cc b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
index 43b3dd8b3ae..3572e751b88 100644
--- a/tests/gtests/blenlib/BLI_stack_cxx_test.cc
+++ b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
@@ -5,7 +5,7 @@
#include "BLI_vector.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(stack, DefaultConstructor)
{
@@ -45,7 +45,7 @@ TEST(stack, MoveConstructor)
{
Stack<int> stack1 = {1, 2, 3, 4, 5, 6, 7};
Stack<int> stack2 = std::move(stack1);
- EXPECT_EQ(stack1.size(), 0);
+ EXPECT_EQ(stack1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(stack2.size(), 7);
for (int i = 7; i >= 1; i--) {
EXPECT_EQ(stack2.pop(), i);
@@ -75,7 +75,7 @@ TEST(stack, MoveAssignment)
Stack<int> stack1 = {1, 2, 3, 4, 5, 6, 7};
Stack<int> stack2 = {5, 3, 7, 2, 2};
stack2 = std::move(stack1);
- EXPECT_EQ(stack1.size(), 0);
+ EXPECT_EQ(stack1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(stack2.size(), 7);
for (int i = 7; i >= 1; i--) {
EXPECT_EQ(stack2.pop(), i);
@@ -185,4 +185,4 @@ TEST(stack, OveralignedValues)
}
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_string_ref_test.cc b/source/blender/blenlib/tests/BLI_string_ref_test.cc
index 83099741c29..d08c8a77455 100644
--- a/tests/gtests/blenlib/BLI_string_ref_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_ref_test.cc
@@ -5,7 +5,7 @@
#include "BLI_vector.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(string_ref_null, DefaultConstructor)
{
@@ -274,4 +274,4 @@ TEST(string_ref, Copy)
EXPECT_EQ(ref, dst);
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_vector_set_test.cc b/source/blender/blenlib/tests/BLI_vector_set_test.cc
index 116c4747c5a..8f3db8d8403 100644
--- a/tests/gtests/blenlib/BLI_vector_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_set_test.cc
@@ -4,7 +4,7 @@
#include "BLI_vector_set.hh"
#include "testing/testing.h"
-namespace blender {
+namespace blender::tests {
TEST(vector_set, DefaultConstructor)
{
@@ -57,7 +57,7 @@ TEST(vector_set, Move)
{
VectorSet<int> set1 = {1, 2, 3};
VectorSet<int> set2 = std::move(set1);
- EXPECT_EQ(set1.size(), 0);
+ EXPECT_EQ(set1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(set2.size(), 3);
}
@@ -66,7 +66,7 @@ TEST(vector_set, MoveAssignment)
VectorSet<int> set1 = {1, 2, 3};
VectorSet<int> set2 = {};
set2 = std::move(set1);
- EXPECT_EQ(set1.size(), 0);
+ EXPECT_EQ(set1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(set2.size(), 3);
}
@@ -161,4 +161,4 @@ TEST(vector_set, Remove)
EXPECT_FALSE(set.contains(5));
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index f581626d1ad..f72dfc5deb8 100644
--- a/tests/gtests/blenlib/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -5,7 +5,7 @@
#include "testing/testing.h"
#include <forward_list>
-namespace blender {
+namespace blender::tests {
TEST(vector, DefaultConstructor)
{
@@ -167,7 +167,7 @@ TEST(vector, MoveConstructor)
Vector<int> vec1 = {1, 2, 3, 4};
Vector<int> vec2(std::move(vec1));
- EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(vec2.size(), 4);
EXPECT_EQ(vec2[0], 1);
EXPECT_EQ(vec2[1], 2);
@@ -180,7 +180,7 @@ TEST(vector, MoveConstructor2)
Vector<int, 2> vec1 = {1, 2, 3, 4};
Vector<int, 3> vec2(std::move(vec1));
- EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(vec2.size(), 4);
EXPECT_EQ(vec2[0], 1);
EXPECT_EQ(vec2[1], 2);
@@ -193,7 +193,7 @@ TEST(vector, MoveConstructor3)
Vector<int, 20> vec1 = {1, 2, 3, 4};
Vector<int, 1> vec2(std::move(vec1));
- EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(vec2.size(), 4);
EXPECT_EQ(vec2[2], 3);
}
@@ -203,7 +203,7 @@ TEST(vector, MoveConstructor4)
Vector<int, 5> vec1 = {1, 2, 3, 4};
Vector<int, 6> vec2(std::move(vec1));
- EXPECT_EQ(vec1.size(), 0);
+ EXPECT_EQ(vec1.size(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(vec2.size(), 4);
EXPECT_EQ(vec2[3], 4);
}
@@ -473,11 +473,11 @@ class TypeConstructMock {
{
}
- TypeConstructMock(const TypeConstructMock &other) : copy_constructed(true)
+ TypeConstructMock(const TypeConstructMock &UNUSED(other)) : copy_constructed(true)
{
}
- TypeConstructMock(TypeConstructMock &&other) noexcept : move_constructed(true)
+ TypeConstructMock(TypeConstructMock &&UNUSED(other)) noexcept : move_constructed(true)
{
}
@@ -636,4 +636,4 @@ TEST(vector, Fill)
EXPECT_EQ(vec[4], 3);
}
-} // namespace blender
+} // namespace blender::tests
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 9320187f2a0..b37029726f4 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4162,7 +4162,7 @@ static void direct_link_curve(BlendDataReader *reader, Curve *cu)
direct_link_animdata(reader, cu->adt);
/* Protect against integer overflow vulnerability. */
- CLAMP(cu->len_wchar, 0, INT_MAX - 4);
+ CLAMP(cu->len_char32, 0, INT_MAX - 4);
BLO_read_pointer_array(reader, (void **)&cu->mat);
@@ -8677,9 +8677,8 @@ static void direct_link_volume(BlendDataReader *reader, Volume *volume)
static void lib_link_simulation(BlendLibReader *reader, Simulation *simulation)
{
- LISTBASE_FOREACH (
- PersistentDataHandleItem *, handle_item, &simulation->persistent_data_handles) {
- BLO_read_id_address(reader, simulation->id.lib, &handle_item->id);
+ LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation->dependencies) {
+ BLO_read_id_address(reader, simulation->id.lib, &dependency->id);
}
}
@@ -8698,7 +8697,7 @@ static void direct_link_simulation(BlendDataReader *reader, Simulation *simulati
}
}
- BLO_read_list(reader, &simulation->persistent_data_handles);
+ BLO_read_list(reader, &simulation->dependencies);
}
/** \} */
@@ -11107,9 +11106,8 @@ static void expand_simulation(BlendExpander *expander, Simulation *simulation)
if (simulation->adt) {
expand_animdata(expander, simulation->adt);
}
- LISTBASE_FOREACH (
- PersistentDataHandleItem *, handle_item, &simulation->persistent_data_handles) {
- BLO_expand(expander, handle_item->id);
+ LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation->dependencies) {
+ BLO_expand(expander, dependency->id);
}
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index b3bf8991c3e..5e91fea3e20 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -2520,7 +2520,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
if (cu->str) {
- cu->len_wchar = BLI_strlen_utf8(cu->str);
+ cu->len_char32 = BLI_strlen_utf8(cu->str);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 50e3b375166..e2dc27d7e88 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -366,7 +366,7 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(250, 0)) {
/* adjust grease-pencil distances */
- userdef->gp_manhattendist = 1;
+ userdef->gp_manhattandist = 1;
userdef->gp_euclideandist = 2;
/* adjust default interpolation for new IPO-curves */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 46ac6b43c92..3db2fada85f 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2007,7 +2007,7 @@ static void write_curve(BlendWriter *writer, Curve *cu, const void *id_address)
if (cu->vfont) {
BLO_write_raw(writer, cu->len + 1, cu->str);
- BLO_write_struct_array(writer, CharInfo, cu->len_wchar + 1, cu->strinfo);
+ BLO_write_struct_array(writer, CharInfo, cu->len_char32 + 1, cu->strinfo);
BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb);
}
else {
@@ -3862,7 +3862,7 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const
}
}
- BLO_write_struct_list(writer, PersistentDataHandleItem, &simulation->persistent_data_handles);
+ BLO_write_struct_list(writer, SimulationDependency, &simulation->dependencies);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 588f716142d..39174a49283 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -917,7 +917,7 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
* segment (and its continuation into vmesh) can usually arbitrarily be
* the previous face or the next face.
* Or, for the center polygon of a corner, all of the faces around
- * the vertex are possible choices.
+ * the vertex are possibleface_component choices.
* If we just choose randomly, the resulting UV maps or material
* assignment can look ugly/inconsistent.
* Allow for the case when arguments are null.
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cpp
index 0967984899d..b8329b1cb29 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cpp
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cpp
@@ -34,7 +34,7 @@ InpaintSimpleOperation::InpaintSimpleOperation() : NodeOperation()
this->setComplex(true);
this->m_inputImageProgram = NULL;
this->m_pixelorder = NULL;
- this->m_manhatten_distance = NULL;
+ this->m_manhattan_distance = NULL;
this->m_cached_buffer = NULL;
this->m_cached_buffer_ready = false;
}
@@ -43,7 +43,7 @@ void InpaintSimpleOperation::initExecution()
this->m_inputImageProgram = this->getInputSocketReader(0);
this->m_pixelorder = NULL;
- this->m_manhatten_distance = NULL;
+ this->m_manhattan_distance = NULL;
this->m_cached_buffer = NULL;
this->m_cached_buffer_ready = false;
@@ -85,7 +85,7 @@ int InpaintSimpleOperation::mdist(int x, int y)
ASSERT_XY_RANGE(x, y);
- return this->m_manhatten_distance[y * width + x];
+ return this->m_manhattan_distance[y * width + x];
}
bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters)
@@ -108,11 +108,11 @@ bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters)
return true;
}
-void InpaintSimpleOperation::calc_manhatten_distance()
+void InpaintSimpleOperation::calc_manhattan_distance()
{
int width = this->getWidth();
int height = this->getHeight();
- short *m = this->m_manhatten_distance = (short *)MEM_mallocN(sizeof(short) * width * height,
+ short *m = this->m_manhattan_distance = (short *)MEM_mallocN(sizeof(short) * width * height,
__func__);
int *offsets;
@@ -223,7 +223,7 @@ void *InpaintSimpleOperation::initializeTileData(rcti *rect)
MemoryBuffer *buf = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect);
this->m_cached_buffer = (float *)MEM_dupallocN(buf->getBuffer());
- this->calc_manhatten_distance();
+ this->calc_manhattan_distance();
int curr = 0;
int x, y;
@@ -258,9 +258,9 @@ void InpaintSimpleOperation::deinitExecution()
this->m_pixelorder = NULL;
}
- if (this->m_manhatten_distance) {
- MEM_freeN(this->m_manhatten_distance);
- this->m_manhatten_distance = NULL;
+ if (this->m_manhattan_distance) {
+ MEM_freeN(this->m_manhattan_distance);
+ this->m_manhattan_distance = NULL;
}
this->m_cached_buffer_ready = false;
}
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.h b/source/blender/compositor/operations/COM_InpaintOperation.h
index 2fef7c590ea..76c1ae81b28 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.h
+++ b/source/blender/compositor/operations/COM_InpaintOperation.h
@@ -34,7 +34,7 @@ class InpaintSimpleOperation : public NodeOperation {
int *m_pixelorder;
int m_area_size;
- short *m_manhatten_distance;
+ short *m_manhattan_distance;
public:
InpaintSimpleOperation();
@@ -65,7 +65,7 @@ class InpaintSimpleOperation : public NodeOperation {
rcti *output);
private:
- void calc_manhatten_distance();
+ void calc_manhattan_distance();
void clamp_xy(int &x, int &y);
float *get_pixel(int x, int y);
int mdist(int x, int y);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index c8309656f21..390e996b63f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -1126,6 +1126,12 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
if (object->type != OB_MESH) {
continue;
}
+ if (object->rigidbody_object == nullptr) {
+ continue;
+ }
+ if (object->rigidbody_object->type == RBO_TYPE_PASSIVE) {
+ continue;
+ }
/* Create operation for flushing results. */
/* Object's transform component - where the rigidbody operation
* lives. */
@@ -1466,6 +1472,18 @@ void DepsgraphNodeBuilder::build_light(Light *lamp)
function_bind(BKE_light_eval, _1, lamp_cow));
}
+void DepsgraphNodeBuilder::build_nodetree_socket(bNodeSocket *socket)
+{
+ build_idproperties(socket->prop);
+
+ if (socket->type == SOCK_OBJECT) {
+ build_id((ID *)((bNodeSocketValueObject *)socket->default_value)->value);
+ }
+ else if (socket->type == SOCK_IMAGE) {
+ build_id((ID *)((bNodeSocketValueImage *)socket->default_value)->value);
+ }
+}
+
void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
{
if (ntree == nullptr) {
@@ -1494,10 +1512,10 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) {
- build_idproperties(socket->prop);
+ build_nodetree_socket(socket);
}
LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) {
- build_idproperties(socket->prop);
+ build_nodetree_socket(socket);
}
ID *id = bnode->id;
@@ -1780,8 +1798,10 @@ void DepsgraphNodeBuilder::build_simulation(Simulation *simulation)
return;
}
add_id_node(&simulation->id);
+ build_idproperties(simulation->id.properties);
build_animdata(&simulation->id);
build_parameters(&simulation->id);
+ build_nodetree(simulation->nodetree);
Simulation *simulation_cow = get_cow_datablock(simulation);
Scene *scene_cow = get_cow_datablock(scene_);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 256fa3450a6..40f42705a52 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -31,6 +31,7 @@
#include "DEG_depsgraph.h"
+struct bNodeSocket;
struct CacheFile;
struct Camera;
struct Collection;
@@ -211,6 +212,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_camera(Camera *camera);
virtual void build_light(Light *lamp);
virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_nodetree_socket(bNodeSocket *socket);
virtual void build_material(Material *ma);
virtual void build_materials(Material **materials, int num_materials);
virtual void build_freestyle_lineset(FreestyleLineSet *fls);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index c5c509ee853..8932d875776 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1698,6 +1698,12 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
if (object->type != OB_MESH) {
continue;
}
+ if (object->rigidbody_object == nullptr) {
+ continue;
+ }
+ if (object->rigidbody_object->type == RBO_TYPE_PASSIVE) {
+ continue;
+ }
OperationKey rb_transform_copy_key(
&object->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
/* Rigid body synchronization depends on the actual simulation. */
@@ -1747,13 +1753,18 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* final result of the constraint object's transform controls how
* the constraint affects the physics sim for these objects. */
ComponentKey trans_key(&object->id, NodeType::TRANSFORM);
- OperationKey ob1_key(
- &rbc->ob1->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
- OperationKey ob2_key(
- &rbc->ob2->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
- /* Constrained-objects sync depends on the constraint-holder. */
- add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1");
- add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2");
+ if (rbc->ob1->rigidbody_object->type == RBO_TYPE_ACTIVE) {
+ OperationKey ob1_key(
+ &rbc->ob1->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
+ /* Constrained-objects sync depends on the constraint-holder. */
+ add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1");
+ }
+ if (rbc->ob2->rigidbody_object->type == RBO_TYPE_ACTIVE) {
+ OperationKey ob2_key(
+ &rbc->ob2->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
+ /* Constrained-objects sync depends on the constraint-holder. */
+ add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2");
+ }
/* Ensure that sim depends on this constraint's transform. */
add_relation(trans_key, rb_simulate_key, "RigidBodyConstraint Transform -> RB Simulation");
}
@@ -2276,6 +2287,24 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
}
+void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket)
+{
+ build_idproperties(socket->prop);
+
+ if (socket->type == SOCK_OBJECT) {
+ Object *object = ((bNodeSocketValueObject *)socket->default_value)->value;
+ if (object != nullptr) {
+ build_object(object);
+ }
+ }
+ else if (socket->type == SOCK_IMAGE) {
+ Image *image = ((bNodeSocketValueImage *)socket->default_value)->value;
+ if (image != nullptr) {
+ build_image(image);
+ }
+ }
+}
+
void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
{
if (ntree == nullptr) {
@@ -2292,10 +2321,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) {
- build_idproperties(socket->prop);
+ build_nodetree_socket(socket);
}
LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) {
- build_idproperties(socket->prop);
+ build_nodetree_socket(socket);
}
ID *id = bnode->id;
@@ -2602,13 +2631,39 @@ void DepsgraphRelationBuilder::build_simulation(Simulation *simulation)
if (built_map_.checkIsBuiltAndTag(simulation)) {
return;
}
+ build_idproperties(simulation->id.properties);
build_animdata(&simulation->id);
build_parameters(&simulation->id);
- OperationKey simulation_update_key(
+ build_nodetree(simulation->nodetree);
+ build_nested_nodetree(&simulation->id, simulation->nodetree);
+
+ OperationKey simulation_eval_key(
&simulation->id, NodeType::SIMULATION, OperationCode::SIMULATION_EVAL);
TimeSourceKey time_src_key;
- add_relation(time_src_key, simulation_update_key, "TimeSrc -> Simulation");
+ add_relation(time_src_key, simulation_eval_key, "TimeSrc -> Simulation");
+
+ OperationKey nodetree_key(
+ &simulation->nodetree->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT);
+ add_relation(nodetree_key, simulation_eval_key, "NodeTree -> Simulation", 0);
+
+ LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation->dependencies) {
+ if (dependency->id == nullptr) {
+ continue;
+ }
+ build_id(dependency->id);
+ if (GS(dependency->id->name) == ID_OB) {
+ Object *object = (Object *)dependency->id;
+ if (dependency->flag & SIM_DEPENDS_ON_TRANSFORM) {
+ ComponentKey object_transform_key(&object->id, NodeType::TRANSFORM);
+ add_relation(object_transform_key, simulation_eval_key, "Object Transform -> Simulation");
+ }
+ if (dependency->flag & SIM_DEPENDS_ON_GEOMETRY) {
+ ComponentKey object_geometry_key(&object->id, NodeType::GEOMETRY);
+ add_relation(object_geometry_key, simulation_eval_key, "Object Geometry -> Simulation");
+ }
+ }
+ }
}
void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index b4b0dc71f85..04f2a3f911d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -46,6 +46,7 @@
#include "intern/node/deg_node_operation.h"
struct Base;
+struct bNodeSocket;
struct CacheFile;
struct Camera;
struct Collection;
@@ -275,6 +276,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_camera(Camera *camera);
virtual void build_light(Light *lamp);
virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_nodetree_socket(bNodeSocket *socket);
virtual void build_material(Material *ma);
virtual void build_materials(Material **materials, int num_materials);
virtual void build_freestyle_lineset(FreestyleLineSet *fls);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
index c48c6489c47..d03903d508c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
@@ -96,7 +96,7 @@ class RNANodeQuery {
/* Check whether prop_identifier contains rna_path_component.
*
- * This checks more than a substring:
+ * This checks more than a sub-string:
*
* prop_identifier contains(prop_identifier, "location")
* ------------------------ -------------------------------------
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 848275eb899..1863a333930 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -786,6 +786,7 @@ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
DEG_graph_id_type_tag(depsgraph, ID_LA);
DEG_graph_id_type_tag(depsgraph, ID_WO);
DEG_graph_id_type_tag(depsgraph, ID_SCE);
+ DEG_graph_id_type_tag(depsgraph, ID_SIM);
}
const int id_type_index = BKE_idtype_idcode_to_index(id_type);
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
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 79d6c8d6a77..82cb311ec45 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
@@ -120,6 +120,7 @@ union NestedIDHackTempStorage {
Scene scene;
Tex tex;
World world;
+ Simulation simulation;
};
/* Set nested owned ID pointers to nullptr. */
@@ -137,6 +138,7 @@ void nested_id_hack_discard_pointers(ID *id_cow)
SPECIAL_CASE(ID_MA, Material, nodetree)
SPECIAL_CASE(ID_TE, Tex, nodetree)
SPECIAL_CASE(ID_WO, World, nodetree)
+ SPECIAL_CASE(ID_SIM, Simulation, nodetree)
SPECIAL_CASE(ID_CU, Curve, key)
SPECIAL_CASE(ID_LT, Lattice, key)
@@ -185,6 +187,7 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage
SPECIAL_CASE(ID_MA, Material, nodetree, material)
SPECIAL_CASE(ID_TE, Tex, nodetree, tex)
SPECIAL_CASE(ID_WO, World, nodetree, world)
+ SPECIAL_CASE(ID_SIM, Simulation, nodetree, simulation)
SPECIAL_CASE(ID_CU, Curve, key, curve)
SPECIAL_CASE(ID_LT, Lattice, key, lattice)
@@ -224,6 +227,7 @@ void nested_id_hack_restore_pointers(const ID *old_id, ID *new_id)
SPECIAL_CASE(ID_SCE, Scene, nodetree)
SPECIAL_CASE(ID_TE, Tex, nodetree)
SPECIAL_CASE(ID_WO, World, nodetree)
+ SPECIAL_CASE(ID_SIM, Simulation, nodetree)
SPECIAL_CASE(ID_CU, Curve, key)
SPECIAL_CASE(ID_LT, Lattice, key)
@@ -261,6 +265,7 @@ void ntree_hack_remap_pointers(const Depsgraph *depsgraph, ID *id_cow)
SPECIAL_CASE(ID_SCE, Scene, nodetree, bNodeTree)
SPECIAL_CASE(ID_TE, Tex, nodetree, bNodeTree)
SPECIAL_CASE(ID_WO, World, nodetree, bNodeTree)
+ SPECIAL_CASE(ID_SIM, Simulation, nodetree, bNodeTree)
SPECIAL_CASE(ID_CU, Curve, key, Key)
SPECIAL_CASE(ID_LT, Lattice, key, Key)
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index cfcd4e0c65a..8bd4832e446 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/draw_color_management.c
intern/draw_common.c
intern/draw_debug.c
+ intern/draw_fluid.c
intern/draw_hair.c
intern/draw_instance_data.c
intern/draw_manager.c
@@ -186,10 +187,10 @@ set(LIB
)
data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
@@ -204,8 +205,8 @@ data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lit_surface_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_lit_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
@@ -229,7 +230,6 @@ data_to_c_simple(engines/eevee/shaders/object_motion_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_accum_frag.glsl SRC)
-
data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
@@ -240,9 +240,14 @@ 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_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/surface_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/surface_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/surface_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/surface_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_accum_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC)
@@ -288,6 +293,8 @@ data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_pointcloud_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_math_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_math_geom_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
index 4a3cc36ddef..05cd6426911 100644
--- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -54,24 +54,30 @@ extern char datatoc_common_view_lib_glsl[];
static void eevee_create_shader_depth_of_field(const bool use_alpha)
{
- char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_effect_dof_frag_glsl);
- e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen(
- frag,
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
+
+ e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_dof_frag_glsl,
+ lib,
use_alpha ? "#define USE_ALPHA_DOF\n"
"#define STEP_DOWNSAMPLE\n" :
"#define STEP_DOWNSAMPLE\n");
- e_data.dof_scatter_sh[use_alpha] = DRW_shader_create(datatoc_effect_dof_vert_glsl,
- NULL,
- frag,
- use_alpha ? "#define USE_ALPHA_DOF\n"
- "#define STEP_SCATTER\n" :
- "#define STEP_SCATTER\n");
- e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(frag,
- use_alpha ?
- "#define USE_ALPHA_DOF\n"
- "#define STEP_RESOLVE\n" :
- "#define STEP_RESOLVE\n");
- MEM_freeN(frag);
+
+ e_data.dof_scatter_sh[use_alpha] = DRW_shader_create_with_shaderlib(
+ datatoc_effect_dof_vert_glsl,
+ NULL,
+ datatoc_effect_dof_frag_glsl,
+ lib,
+ use_alpha ? "#define USE_ALPHA_DOF\n"
+ "#define STEP_SCATTER\n" :
+ "#define STEP_SCATTER\n");
+
+ e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_dof_frag_glsl,
+ lib,
+ use_alpha ? "#define USE_ALPHA_DOF\n"
+ "#define STEP_RESOLVE\n" :
+ "#define STEP_RESOLVE\n");
}
int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata),
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index f42c60b04bf..7bf4c78d870 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -32,6 +32,8 @@
#include "DNA_world_types.h"
+#include "IMB_imbuf.h"
+
#include "eevee_private.h"
#include "eevee_engine.h" /* own include */
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 72187dc29eb..a4c07584b86 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -326,38 +326,28 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
{
DRW_PASS_CREATE(psl->probe_background, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
- struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = NULL;
+ EEVEE_lookdev_cache_init(vedata, sldata, psl->probe_background, pinfo, &grp);
- Scene *scene = draw_ctx->scene;
- World *wo = scene->world;
-
- /* LookDev */
- EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->probe_background, wo, pinfo);
+ if (grp == NULL) {
+ Scene *scene = draw_ctx->scene;
+ World *world = (scene->world) ? scene->world : EEVEE_world_default_get();
- if (!grp && wo) {
- struct GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_PROBE);
+ const int options = VAR_WORLD_BACKGROUND | VAR_WORLD_PROBE;
+ struct GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, NULL, world, options);
grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
- /* TODO (fclem): remove those (need to clean the GLSL files). */
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- DRW_shgroup_call(grp, geom, NULL);
}
- /* Fallback if shader fails or if not using nodetree. */
- if (grp == NULL) {
- grp = DRW_shgroup_create(EEVEE_shaders_probe_default_sh_get(), psl->probe_background);
- DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1);
- DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
- DRW_shgroup_call(grp, geom, NULL);
- }
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &stl->g_data->renderpass_ubo);
+ DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
if (DRW_state_draw_support()) {
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index b044213e029..403a8e2af55 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -97,10 +97,9 @@ static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerD
void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
- DRWShadingGroup **r_grp,
DRWPass *pass,
- World *UNUSED(world),
- EEVEE_LightProbesInfo *pinfo)
+ EEVEE_LightProbesInfo *pinfo,
+ DRWShadingGroup **r_shgrp)
{
EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
@@ -153,89 +152,88 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
const View3DShading *shading = &v3d->shading;
StudioLight *sl = BKE_studiolight_find(shading->lookdev_light,
STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE);
- if (sl && (sl->flag & STUDIOLIGHT_TYPE_WORLD)) {
- GPUShader *shader = probe_render ? EEVEE_shaders_default_studiolight_sh_get() :
- EEVEE_shaders_background_studiolight_sh_get();
+ if (sl == NULL || (sl->flag & STUDIOLIGHT_TYPE_WORLD) == 0) {
+ return;
+ }
+
+ GPUShader *shader = probe_render ? EEVEE_shaders_studiolight_probe_sh_get() :
+ EEVEE_shaders_studiolight_background_sh_get();
- const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- int cube_res = scene_eval->eevee.gi_cubemap_resolution;
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ 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) ||
- (txl->lookdev_grid_tx == NULL) || (txl->lookdev_cube_tx == NULL) ||
- (g_data->light_cache && g_data->light_cache->ref_res != cube_res)) {
- eevee_lookdev_lightcache_delete(vedata);
- }
+ /* If one of the component is missing we start from scratch. */
+ if ((stl->lookdev_grid_data == NULL) || (stl->lookdev_cube_data == NULL) ||
+ (txl->lookdev_grid_tx == NULL) || (txl->lookdev_cube_tx == NULL) ||
+ (g_data->light_cache && g_data->light_cache->ref_res != cube_res)) {
+ eevee_lookdev_lightcache_delete(vedata);
+ }
- if (stl->lookdev_lightcache == NULL) {
+ if (stl->lookdev_lightcache == NULL) {
#if defined(IRRADIANCE_SH_L2)
- int grid_res = 4;
+ int grid_res = 4;
#elif defined(IRRADIANCE_HL2)
- int grid_res = 4;
+ int grid_res = 4;
#endif
- stl->lookdev_lightcache = EEVEE_lightcache_create(
- 1, 1, cube_res, 8, (int[3]){grid_res, grid_res, 1});
-
- /* XXX: Fix memleak. TODO find out why. */
- MEM_SAFE_FREE(stl->lookdev_cube_mips);
-
- /* We do this to use a special light cache for lookdev.
- * This light-cache needs to be per viewport. But we need to
- * have correct freeing when the viewport is closed. So we
- * need to reference all textures to the txl and the memblocks
- * to the stl. */
- stl->lookdev_grid_data = stl->lookdev_lightcache->grid_data;
- stl->lookdev_cube_data = stl->lookdev_lightcache->cube_data;
- stl->lookdev_cube_mips = stl->lookdev_lightcache->cube_mips;
- txl->lookdev_grid_tx = stl->lookdev_lightcache->grid_tx.tex;
- txl->lookdev_cube_tx = stl->lookdev_lightcache->cube_tx.tex;
- }
-
- g_data->light_cache = stl->lookdev_lightcache;
-
- DRWShadingGroup *grp = *r_grp = DRW_shgroup_create(shader, pass);
- axis_angle_to_mat3_single(g_data->studiolight_matrix, 'Z', shading->studiolight_rot_z);
- DRW_shgroup_uniform_mat3(grp, "StudioLightMatrix", g_data->studiolight_matrix);
-
- if (probe_render) {
- DRW_shgroup_uniform_float_copy(
- grp, "studioLightIntensity", shading->studiolight_intensity);
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
- DRW_shgroup_uniform_texture(grp, "image", sl->equirect_radiance_gputexture);
- /* Do not fadeout when doing probe rendering, only when drawing the background */
- DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
- }
- else {
- float background_alpha = g_data->background_alpha * shading->studiolight_background;
- float studiolight_blur = powf(shading->studiolight_blur, 2.5f);
- DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", background_alpha);
- DRW_shgroup_uniform_float_copy(grp, "studioLightBlur", studiolight_blur);
- DRW_shgroup_uniform_texture(grp, "probeCubes", txl->lookdev_cube_tx);
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
- }
-
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-
- /* Do we need to recalc the lightprobes? */
- if (g_data->studiolight_index != sl->index ||
- g_data->studiolight_rot_z != shading->studiolight_rot_z ||
- g_data->studiolight_intensity != shading->studiolight_intensity ||
- g_data->studiolight_cubemap_res != scene->eevee.gi_cubemap_resolution ||
- g_data->studiolight_glossy_clamp != scene->eevee.gi_glossy_clamp ||
- g_data->studiolight_filter_quality != scene->eevee.gi_filter_quality) {
- stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD;
- g_data->studiolight_index = sl->index;
- g_data->studiolight_rot_z = shading->studiolight_rot_z;
- g_data->studiolight_intensity = shading->studiolight_intensity;
- g_data->studiolight_cubemap_res = scene->eevee.gi_cubemap_resolution;
- g_data->studiolight_glossy_clamp = scene->eevee.gi_glossy_clamp;
- g_data->studiolight_filter_quality = scene->eevee.gi_filter_quality;
- }
+ stl->lookdev_lightcache = EEVEE_lightcache_create(
+ 1, 1, cube_res, 8, (int[3]){grid_res, grid_res, 1});
+
+ /* XXX: Fix memleak. TODO find out why. */
+ MEM_SAFE_FREE(stl->lookdev_cube_mips);
+
+ /* We do this to use a special light cache for lookdev.
+ * This light-cache needs to be per viewport. But we need to
+ * have correct freeing when the viewport is closed. So we
+ * need to reference all textures to the txl and the memblocks
+ * to the stl. */
+ stl->lookdev_grid_data = stl->lookdev_lightcache->grid_data;
+ stl->lookdev_cube_data = stl->lookdev_lightcache->cube_data;
+ stl->lookdev_cube_mips = stl->lookdev_lightcache->cube_mips;
+ txl->lookdev_grid_tx = stl->lookdev_lightcache->grid_tx.tex;
+ txl->lookdev_cube_tx = stl->lookdev_lightcache->cube_tx.tex;
+ }
+
+ g_data->light_cache = stl->lookdev_lightcache;
+
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+ axis_angle_to_mat3_single(g_data->studiolight_matrix, 'Z', shading->studiolight_rot_z);
+ DRW_shgroup_uniform_mat3(grp, "StudioLightMatrix", g_data->studiolight_matrix);
+
+ if (probe_render) {
+ /* Avoid artifact with equirectangular mapping. */
+ eGPUSamplerState state = (GPU_SAMPLER_FILTER | GPU_SAMPLER_REPEAT_S);
+ DRW_shgroup_uniform_float_copy(grp, "studioLightIntensity", shading->studiolight_intensity);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ DRW_shgroup_uniform_texture_ex(grp, "studioLight", sl->equirect_radiance_gputexture, state);
+ /* Do not fadeout when doing probe rendering, only when drawing the background */
+ DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
+ }
+ else {
+ float background_alpha = g_data->background_alpha * shading->studiolight_background;
+ float studiolight_blur = powf(shading->studiolight_blur, 2.5f);
+ DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", background_alpha);
+ DRW_shgroup_uniform_float_copy(grp, "studioLightBlur", studiolight_blur);
+ DRW_shgroup_uniform_texture(grp, "probeCubes", txl->lookdev_cube_tx);
+ }
+
+ /* Common UBOs are setup latter. */
+ *r_shgrp = grp;
+
+ /* Do we need to recalc the lightprobes? */
+ if (g_data->studiolight_index != sl->index ||
+ g_data->studiolight_rot_z != shading->studiolight_rot_z ||
+ g_data->studiolight_intensity != shading->studiolight_intensity ||
+ g_data->studiolight_cubemap_res != scene->eevee.gi_cubemap_resolution ||
+ g_data->studiolight_glossy_clamp != scene->eevee.gi_glossy_clamp ||
+ g_data->studiolight_filter_quality != scene->eevee.gi_filter_quality) {
+ stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD;
+ g_data->studiolight_index = sl->index;
+ g_data->studiolight_rot_z = shading->studiolight_rot_z;
+ g_data->studiolight_intensity = shading->studiolight_intensity;
+ g_data->studiolight_cubemap_res = scene->eevee.gi_cubemap_resolution;
+ g_data->studiolight_glossy_clamp = scene->eevee.gi_glossy_clamp;
+ g_data->studiolight_filter_quality = scene->eevee.gi_filter_quality;
}
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_lut_gen.c b/source/blender/draw/engines/eevee/eevee_lut_gen.c
index 6cee05bf015..8c3fb29e941 100644
--- a/source/blender/draw/engines/eevee/eevee_lut_gen.c
+++ b/source/blender/draw/engines/eevee/eevee_lut_gen.c
@@ -31,6 +31,8 @@
#include "BLI_rand.h"
#include "BLI_string_utils.h"
+#include "eevee_private.h"
+
extern char datatoc_bsdf_lut_frag_glsl[];
extern char datatoc_btdf_lut_frag_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
@@ -45,15 +47,13 @@ static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h))
static float samples_len = 8192.0f;
static float inv_samples_len = 1.0f / 8192.0f;
- char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl);
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
- struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl,
- datatoc_lightprobe_geom_glsl,
- datatoc_bsdf_lut_frag_glsl,
- lib_str,
- "#define HAMMERSLEY_SIZE 8192\n"
- "#define BRDF_LUT_SIZE 64\n"
- "#define NOISE_SIZE 64\n");
+ struct GPUShader *sh = DRW_shader_create_with_shaderlib(datatoc_lightprobe_vert_glsl,
+ datatoc_lightprobe_geom_glsl,
+ datatoc_bsdf_lut_frag_glsl,
+ lib,
+ "#define HAMMERSLEY_SIZE 8192\n");
DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
@@ -105,16 +105,10 @@ static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h)
static float a2 = 0.0f;
static float inv_samples_len = 1.0f / 8192.0f;
- char *frag_str = BLI_string_joinN(
- datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl);
-
- struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str,
- "#define HAMMERSLEY_SIZE 8192\n"
- "#define BRDF_LUT_SIZE 64\n"
- "#define NOISE_SIZE 64\n"
- "#define LUT_SIZE 64\n");
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
- MEM_freeN(frag_str);
+ struct GPUShader *sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_btdf_lut_frag_glsl, lib, "#define HAMMERSLEY_SIZE 8192\n");
DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 143945b637a..59e8c1407e6 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -56,37 +56,6 @@ static struct {
float noise_offsets[3];
} e_data = {NULL}; /* Engine data */
-extern char datatoc_lights_lib_glsl[];
-extern char datatoc_lightprobe_lib_glsl[];
-extern char datatoc_ambient_occlusion_lib_glsl[];
-extern char datatoc_prepass_frag_glsl[];
-extern char datatoc_prepass_vert_glsl[];
-extern char datatoc_default_frag_glsl[];
-extern char datatoc_default_world_frag_glsl[];
-extern char datatoc_ltc_lib_glsl[];
-extern char datatoc_bsdf_common_lib_glsl[];
-extern char datatoc_bsdf_sampling_lib_glsl[];
-extern char datatoc_common_uniforms_lib_glsl[];
-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[];
-extern char datatoc_ssr_lib_glsl[];
-extern char datatoc_shadow_vert_glsl[];
-extern char datatoc_lightprobe_geom_glsl[];
-extern char datatoc_lightprobe_vert_glsl[];
-extern char datatoc_background_vert_glsl[];
-extern char datatoc_update_noise_frag_glsl[];
-extern char datatoc_volumetric_vert_glsl[];
-extern char datatoc_volumetric_geom_glsl[];
-extern char datatoc_volumetric_frag_glsl[];
-extern char datatoc_volumetric_lib_glsl[];
-extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-
typedef struct EeveeMaterialCache {
struct DRWShadingGroup *depth_grp;
struct DRWShadingGroup *shading_grp;
@@ -238,46 +207,6 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d
DRW_draw_pass(psl->update_noise_pass);
}
-void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4])
-{
- /* view vectors for the corners of the view frustum.
- * Can be used to recreate the world space position easily */
- float view_vecs[4][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},
- {-1.0f, -1.0f, 1.0f, 1.0f},
- };
-
- /* convert the view vectors to view space */
- const bool is_persp = (winmat[3][3] == 0.0f);
- for (int i = 0; i < 4; i++) {
- mul_project_m4_v3(invproj, view_vecs[i]);
- /* normalized trick see:
- * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- if (is_persp) {
- /* Divide XY by Z. */
- mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
- }
- }
-
- /**
- * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
- * view_vecs[1] is the vector going from the near-bottom-left corner to
- * the far-top-right corner.
- * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
- * when Z = 1, and top-left corner if Z = 1.
- * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
- * distance from the near plane to the far clip plane.
- */
- copy_v4_v4(r_viewvecs[0], view_vecs[0]);
-
- /* we need to store the differences */
- r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
- r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
- r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
-}
-
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
EEVEE_StorageList *stl,
@@ -305,15 +234,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
}
{
- /* Update view_vecs */
- float invproj[4][4], winmat[4][4];
- DRW_view_winmat_get(NULL, winmat, false);
- DRW_view_winmat_get(NULL, invproj, true);
-
- EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs);
- }
-
- {
/* Update noise Framebuffer. */
GPU_framebuffer_ensure_config(
&fbl->update_noise_fb,
@@ -391,39 +311,28 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
DRW_PASS_CREATE(psl->background_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
- struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = NULL;
+ EEVEE_lookdev_cache_init(vedata, sldata, psl->background_ps, NULL, &grp);
- Scene *scene = draw_ctx->scene;
- World *wo = scene->world;
-
- EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_ps, wo, NULL);
+ if (grp == NULL) {
+ Scene *scene = draw_ctx->scene;
+ World *world = (scene->world) ? scene->world : EEVEE_world_default_get();
- if (!grp && wo) {
- struct GPUMaterial *gpumat = EEVEE_material_get(
- vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND);
+ const int options = VAR_WORLD_BACKGROUND;
+ struct GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, NULL, world, options);
grp = DRW_shgroup_material_create(gpumat, psl->background_ps);
DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- /* TODO (fclem): remove those (need to clean the GLSL files). */
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &stl->g_data->renderpass_ubo);
- DRW_shgroup_call(grp, geom, NULL);
}
- /* Fallback if shader fails or if not using nodetree. */
- if (grp == NULL) {
- GPUShader *sh = EEVEE_shaders_default_background_sh_get();
- grp = DRW_shgroup_create(sh, psl->background_ps);
- DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1);
- DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- DRW_shgroup_call(grp, geom, NULL);
- }
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &stl->g_data->renderpass_ubo);
+ DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
#define EEVEE_PASS_CREATE(pass, state) \
diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c
index 1cedd334d67..d2f3a13eb7c 100644
--- a/source/blender/draw/engines/eevee/eevee_mist.c
+++ b/source/blender/draw/engines/eevee/eevee_mist.c
@@ -56,14 +56,10 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
if (e_data.mist_sh == NULL) {
- char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_effect_mist_frag_glsl);
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
- e_data.mist_sh = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
-
- MEM_freeN(frag_str);
+ e_data.mist_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_mist_frag_glsl, lib, "#define FIRST_PASS\n");
}
/* Create FrameBuffer. */
@@ -98,11 +94,11 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
else {
- float near = -sldata->common_data.view_vecs[0][2];
- float range = sldata->common_data.view_vecs[1][2];
+ float near = DRW_view_near_distance_get(NULL);
+ float far = DRW_view_far_distance_get(NULL);
/* Fallback */
g_data->mist_start = near;
- g_data->mist_inv_dist = 1.0f / fabsf(range);
+ g_data->mist_inv_dist = 1.0f / fabsf(far - near);
g_data->mist_falloff = 1.0f;
}
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 586ee780f1d..0e8a2493b01 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -68,27 +68,23 @@ extern char datatoc_common_view_lib_glsl[];
static void eevee_create_shader_motion_blur(void)
{
- e_data.motion_blur_sh = DRW_shader_create_fullscreen(
- datatoc_effect_motion_blur_frag_glsl,
- "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n");
- e_data.motion_blur_object_sh = DRW_shader_create_with_lib(datatoc_object_motion_vert_glsl,
- NULL,
- datatoc_object_motion_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- e_data.velocity_tiles_sh = DRW_shader_create_fullscreen(
- datatoc_effect_velocity_tile_frag_glsl,
- "#define TILE_GATHER\n"
- "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n");
+#define TILE_SIZE_STR "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
+ e_data.motion_blur_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_motion_blur_frag_glsl, lib, TILE_SIZE_STR);
+ e_data.motion_blur_object_sh = DRW_shader_create_with_shaderlib(
+ datatoc_object_motion_vert_glsl, NULL, datatoc_object_motion_frag_glsl, lib, NULL);
+
+ e_data.motion_blur_hair_sh = DRW_shader_create_with_shaderlib(datatoc_object_motion_vert_glsl,
+ NULL,
+ datatoc_object_motion_frag_glsl,
+ lib,
+ "#define HAIR\n");
+
+ e_data.velocity_tiles_sh = DRW_shader_create_fullscreen(datatoc_effect_velocity_tile_frag_glsl,
+ "#define TILE_GATHER\n" TILE_SIZE_STR);
e_data.velocity_tiles_expand_sh = DRW_shader_create_fullscreen(
- datatoc_effect_velocity_tile_frag_glsl,
- "#define TILE_EXPANSION\n"
- "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n");
-
- char *vert = BLI_string_joinN(datatoc_common_hair_lib_glsl, datatoc_object_motion_vert_glsl);
- e_data.motion_blur_hair_sh = DRW_shader_create_with_lib(
- vert, NULL, datatoc_object_motion_frag_glsl, datatoc_common_view_lib_glsl, "#define HAIR\n");
- MEM_freeN(vert);
+ datatoc_effect_velocity_tile_frag_glsl, "#define TILE_EXPANSION\n" TILE_SIZE_STR);
}
int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index a075210967c..1929bbb9b98 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -53,17 +53,14 @@ extern char datatoc_effect_gtao_frag_glsl[];
static void eevee_create_shader_occlusion(void)
{
- char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_ambient_occlusion_lib_glsl,
- datatoc_effect_gtao_frag_glsl);
-
- e_data.gtao_sh = DRW_shader_create_fullscreen(frag_str, NULL);
- e_data.gtao_layer_sh = DRW_shader_create_fullscreen(frag_str, "#define LAYERED_DEPTH\n");
- e_data.gtao_debug_sh = DRW_shader_create_fullscreen(frag_str, "#define DEBUG_AO\n");
-
- MEM_freeN(frag_str);
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
+
+ e_data.gtao_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_gtao_frag_glsl, lib, NULL);
+ e_data.gtao_layer_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_gtao_frag_glsl, lib, "#define LAYERED_DEPTH\n");
+ e_data.gtao_debug_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_gtao_frag_glsl, lib, "#define DEBUG_AO\n");
}
int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 81a50d36e17..c202bbbb754 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -163,7 +163,7 @@ enum {
VAR_MAT_MESH = (1 << 0),
VAR_MAT_VOLUME = (1 << 1),
VAR_MAT_HAIR = (1 << 2),
- VAR_MAT_PROBE = (1 << 3),
+ /* VAR_MAT_PROBE = (1 << 3), UNUSED */
VAR_MAT_BLEND = (1 << 4),
VAR_MAT_LOOKDEV = (1 << 5),
VAR_MAT_HOLDOUT = (1 << 6),
@@ -747,7 +747,6 @@ typedef struct EEVEE_EffectsInfo {
* - sizeof(bool) == sizeof(int) in GLSL so use int in C */
typedef struct EEVEE_CommonUniformBuffer {
float prev_persmat[4][4]; /* mat4 */
- float view_vecs[2][4]; /* vec4[2] */
float mip_ratio[10][4]; /* vec2[10] */
/* Ambient Occlusion */
/* -- 16 byte aligned -- */
@@ -1001,7 +1000,6 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata,
void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_materials_free(void);
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
-void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]);
void EEVEE_material_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1057,15 +1055,14 @@ void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
void EEVEE_shaders_lightprobe_shaders_init(void);
void EEVEE_shaders_material_shaders_init(void);
+struct DRWShaderLibrary *EEVEE_shader_lib_get(void);
struct GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void);
-struct GPUShader *EEVEE_shaders_probe_default_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void);
-struct GPUShader *EEVEE_shaders_default_studiolight_sh_get(void);
-struct GPUShader *EEVEE_shaders_default_background_sh_get(void);
-struct GPUShader *EEVEE_shaders_background_studiolight_sh_get(void);
+struct GPUShader *EEVEE_shaders_studiolight_probe_sh_get(void);
+struct GPUShader *EEVEE_shaders_studiolight_background_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void);
@@ -1077,6 +1074,7 @@ struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo);
Material *EEVEE_material_default_diffuse_get(void);
Material *EEVEE_material_default_glossy_get(void);
Material *EEVEE_material_default_error_get(void);
+World *EEVEE_world_default_get(void);
struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options);
struct GPUMaterial *EEVEE_material_get(
EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options);
@@ -1300,10 +1298,9 @@ void EEVEE_render_update_passes(struct RenderEngine *engine,
/** eevee_lookdev.c */
void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
- DRWShadingGroup **grp,
DRWPass *pass,
- struct World *world,
- EEVEE_LightProbesInfo *pinfo);
+ EEVEE_LightProbesInfo *pinfo,
+ DRWShadingGroup **r_shgrp);
void EEVEE_lookdev_draw(EEVEE_Data *vedata);
/** eevee_engine.c */
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index be771d7cf42..089d8b7a287 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -199,12 +199,10 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0;
if (needs_post_processing) {
if (e_data.postprocess_sh == NULL) {
- char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_renderpass_postprocess_frag_glsl);
- e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL);
- MEM_freeN(frag_str);
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
+
+ e_data.postprocess_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_renderpass_postprocess_frag_glsl, lib, NULL);
}
DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR);
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 32d758dba4b..a1755e60c06 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -48,30 +48,12 @@ static struct {
struct GPUTexture *depth_src;
} e_data = {{NULL}}; /* Engine data */
-extern char datatoc_ambient_occlusion_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_common_uniforms_lib_glsl[];
-extern char datatoc_bsdf_common_lib_glsl[];
-extern char datatoc_bsdf_sampling_lib_glsl[];
-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[];
static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
{
if (e_data.ssr_sh[options] == NULL) {
- char *ssr_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_bsdf_sampling_lib_glsl,
- 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);
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
DynStr *ds_defines = BLI_dynstr_new();
BLI_dynstr_append(ds_defines, SHADER_DEFINES);
@@ -91,9 +73,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines);
BLI_dynstr_free(ds_defines);
- e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str);
+ e_data.ssr_sh[options] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_ssr_frag_glsl, lib, ssr_define_str);
- MEM_freeN(ssr_shader_str);
MEM_freeN(ssr_define_str);
}
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 09e74c84948..5f125d395d3 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -28,6 +28,8 @@
#include "BLI_dynstr.h"
#include "BLI_string_utils.h"
+#include "DNA_world_types.h"
+
#include "MEM_guardedalloc.h"
#include "GPU_material.h"
@@ -40,19 +42,17 @@
static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
#if defined(IRRADIANCE_SH_L2)
- "#define IRRADIANCE_SH_L2\n"
-#elif defined(IRRADIANCE_CUBEMAP)
- "#define IRRADIANCE_CUBEMAP\n"
+ "#define IRRADIANCE_SH_L2\n";
#elif defined(IRRADIANCE_HL2)
- "#define IRRADIANCE_HL2\n"
+ "#define IRRADIANCE_HL2\n";
#endif
- "#define NOISE_SIZE 64\n";
static struct {
+ /* Lookdev */
+ struct GPUShader *studiolight_probe_sh;
+ struct GPUShader *studiolight_background_sh;
+
/* Probes */
- struct GPUShader *probe_default_sh;
- struct GPUShader *probe_default_studiolight_sh;
- struct GPUShader *probe_background_studiolight_sh;
struct GPUShader *probe_grid_display_sh;
struct GPUShader *probe_cube_display_sh;
struct GPUShader *probe_planar_display_sh;
@@ -70,17 +70,16 @@ static struct {
struct GPUShader *taa_resolve_reproject_sh;
/* General purpose Shaders. */
- struct GPUShader *default_background;
+ struct GPUShader *lookdev_background;
struct GPUShader *update_noise_sh;
/* Shader strings */
- char *frag_shader_lib;
- char *vert_shader_str;
- char *vert_shadow_shader_str;
- char *vert_background_shader_str;
- char *vert_volume_shader_str;
- char *geom_volume_shader_str;
- char *volume_shader_lib;
+ char *closure_lit_lib;
+ char *surface_lit_frag;
+ char *surface_prepass_frag;
+ char *surface_geom_barycentric;
+
+ DRWShaderLibrary *lib;
/* LookDev Materials */
Material *glossy_mat;
@@ -88,6 +87,8 @@ static struct {
Material *error_mat;
+ World *default_world;
+
/* Default Material */
struct {
bNodeTree *ntree;
@@ -103,16 +104,39 @@ static struct {
} world;
} e_data = {NULL}; /* Engine data */
-extern char datatoc_bsdf_common_lib_glsl[];
-extern char datatoc_bsdf_sampling_lib_glsl[];
-extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_common_math_lib_glsl[];
+extern char datatoc_common_math_geom_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
extern char datatoc_ambient_occlusion_lib_glsl[];
extern char datatoc_background_vert_glsl[];
-extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_lut_frag_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_btdf_lut_frag_glsl[];
+extern char datatoc_closure_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_utiltex_lib_glsl[];
extern char datatoc_cubemap_lib_glsl[];
-extern char datatoc_default_world_frag_glsl[];
+extern char datatoc_default_frag_glsl[];
+extern char datatoc_lookdev_world_frag_glsl[];
+extern char datatoc_effect_bloom_frag_glsl[];
+extern char datatoc_effect_dof_frag_glsl[];
+extern char datatoc_effect_dof_vert_glsl[];
+extern char datatoc_effect_downsample_cube_frag_glsl[];
+extern char datatoc_effect_downsample_frag_glsl[];
+extern char datatoc_effect_gtao_frag_glsl[];
+extern char datatoc_effect_minmaxz_frag_glsl[];
+extern char datatoc_effect_mist_frag_glsl[];
+extern char datatoc_effect_motion_blur_frag_glsl[];
+extern char datatoc_effect_ssr_frag_glsl[];
+extern char datatoc_effect_subsurface_frag_glsl[];
+extern char datatoc_effect_temporal_aa_glsl[];
+extern char datatoc_effect_translucency_frag_glsl[];
+extern char datatoc_effect_velocity_resolve_frag_glsl[];
+extern char datatoc_effect_velocity_tile_frag_glsl[];
extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lightprobe_cube_display_frag_glsl[];
extern char datatoc_lightprobe_cube_display_vert_glsl[];
@@ -131,72 +155,111 @@ extern char datatoc_lightprobe_planar_downsample_geom_glsl[];
extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_lights_lib_glsl[];
-extern char datatoc_lit_surface_frag_glsl[];
-extern char datatoc_lit_surface_vert_glsl[];
+extern char datatoc_closure_lit_lib_glsl[];
extern char datatoc_ltc_lib_glsl[];
+extern char datatoc_object_motion_frag_glsl[];
+extern char datatoc_object_motion_vert_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_prepass_frag_glsl[];
+extern char datatoc_prepass_vert_glsl[];
extern char datatoc_raytrace_lib_glsl[];
+extern char datatoc_renderpass_lib_glsl[];
+extern char datatoc_renderpass_postprocess_frag_glsl[];
+extern char datatoc_shadow_accum_frag_glsl[];
+extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_vert_glsl[];
extern char datatoc_ssr_lib_glsl[];
+extern char datatoc_surface_frag_glsl[];
+extern char datatoc_surface_geom_glsl[];
+extern char datatoc_surface_lib_glsl[];
+extern char datatoc_surface_vert_glsl[];
extern char datatoc_update_noise_frag_glsl[];
+extern char datatoc_volumetric_accum_frag_glsl[];
extern char datatoc_volumetric_frag_glsl[];
extern char datatoc_volumetric_geom_glsl[];
+extern char datatoc_volumetric_integration_frag_glsl[];
extern char datatoc_volumetric_lib_glsl[];
+extern char datatoc_volumetric_resolve_frag_glsl[];
+extern char datatoc_volumetric_scatter_frag_glsl[];
extern char datatoc_volumetric_vert_glsl[];
-/* Velocity Resolve */
-extern char datatoc_effect_velocity_resolve_frag_glsl[];
-
-/* Temporal Sampling */
-extern char datatoc_effect_temporal_aa_glsl[];
-
/* *********** FUNCTIONS *********** */
+static void eevee_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_math_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, common_math_geom_lib);
+ 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, common_uniforms_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, bsdf_common_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, common_utiltex_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, bsdf_sampling_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, cubemap_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, raytrace_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, ambient_occlusion_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, octahedron_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, irradiance_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, lightprobe_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, ltc_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, lights_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, surface_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
+
+ /* Add one for each Closure */
+ e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl,
+ datatoc_closure_lit_lib_glsl);
+
+ DRW_shader_library_add_file(e_data.lib, e_data.closure_lit_lib, "closure_lit_lib.glsl");
+
+ e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_surface_frag_glsl);
+
+ e_data.surface_prepass_frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_prepass_frag_glsl);
+
+ e_data.surface_geom_barycentric = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_surface_geom_glsl);
+ }
+}
+
void EEVEE_shaders_lightprobe_shaders_init(void)
{
BLI_assert(e_data.probe_filter_glossy_sh == NULL);
- char *shader_str = NULL;
-
- shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_bsdf_sampling_lib_glsl,
- datatoc_lightprobe_filter_glossy_frag_glsl);
-
- e_data.probe_filter_glossy_sh = DRW_shader_create(
- datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines);
-
- e_data.probe_default_sh = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
- NULL,
- datatoc_default_world_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- MEM_freeN(shader_str);
+ eevee_shader_library_ensure();
- shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_bsdf_sampling_lib_glsl,
- datatoc_lightprobe_filter_diffuse_frag_glsl);
+ e_data.probe_filter_glossy_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_vert_glsl,
+ datatoc_lightprobe_geom_glsl,
+ datatoc_lightprobe_filter_glossy_frag_glsl,
+ e_data.lib,
+ filter_defines);
- e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
+ e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_lightprobe_filter_diffuse_frag_glsl, e_data.lib, filter_defines);
- MEM_freeN(shader_str);
+ e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_lightprobe_filter_visibility_frag_glsl, e_data.lib, filter_defines);
- shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_bsdf_sampling_lib_glsl,
- datatoc_lightprobe_filter_visibility_frag_glsl);
-
- e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
-
- MEM_freeN(shader_str);
-
- e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(datatoc_lightprobe_grid_fill_frag_glsl,
- filter_defines);
+ e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_lightprobe_grid_fill_frag_glsl, e_data.lib, filter_defines);
e_data.probe_planar_downsample_sh = DRW_shader_create(
datatoc_lightprobe_planar_downsample_vert_glsl,
@@ -207,70 +270,18 @@ void EEVEE_shaders_lightprobe_shaders_init(void)
void EEVEE_shaders_material_shaders_init(void)
{
- e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_bsdf_sampling_lib_glsl,
- datatoc_ambient_occlusion_lib_glsl,
- datatoc_raytrace_lib_glsl,
- datatoc_ssr_lib_glsl,
- datatoc_octahedron_lib_glsl,
- datatoc_cubemap_lib_glsl,
- datatoc_irradiance_lib_glsl,
- datatoc_lightprobe_lib_glsl,
- datatoc_ltc_lib_glsl,
- datatoc_lights_lib_glsl,
- /* Add one for each Closure */
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_volumetric_lib_glsl);
-
- e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- 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,
- datatoc_lights_lib_glsl,
- datatoc_volumetric_lib_glsl,
- datatoc_volumetric_frag_glsl);
-
- e_data.vert_shader_str = BLI_string_joinN(
- datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl);
-
- e_data.vert_shadow_shader_str = BLI_string_joinN(
- datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
-
- e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_background_vert_glsl);
-
- e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_volumetric_vert_glsl);
-
- e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_volumetric_geom_glsl);
+ eevee_shader_library_ensure();
}
-GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void)
+DRWShaderLibrary *EEVEE_shader_lib_get(void)
{
- return e_data.probe_filter_glossy_sh;
+ eevee_shader_library_ensure();
+ return e_data.lib;
}
-GPUShader *EEVEE_shaders_probe_default_sh_get(void)
+GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void)
{
- return e_data.probe_default_sh;
+ return e_data.probe_filter_glossy_sh;
}
GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void)
@@ -293,59 +304,40 @@ GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void)
return e_data.probe_planar_downsample_sh;
}
-GPUShader *EEVEE_shaders_default_studiolight_sh_get(void)
+GPUShader *EEVEE_shaders_studiolight_probe_sh_get(void)
{
- if (e_data.probe_default_studiolight_sh == NULL) {
- e_data.probe_default_studiolight_sh = DRW_shader_create_with_lib(
- datatoc_background_vert_glsl,
- NULL,
- datatoc_default_world_frag_glsl,
- datatoc_common_view_lib_glsl,
- "#define LOOKDEV\n");
- }
- return e_data.probe_default_studiolight_sh;
+ if (e_data.studiolight_probe_sh == NULL) {
+ e_data.studiolight_probe_sh = DRW_shader_create_with_shaderlib(datatoc_background_vert_glsl,
+ NULL,
+ datatoc_lookdev_world_frag_glsl,
+ e_data.lib,
+ SHADER_DEFINES);
+ }
+ return e_data.studiolight_probe_sh;
}
-GPUShader *EEVEE_shaders_background_studiolight_sh_get(void)
+GPUShader *EEVEE_shaders_studiolight_background_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,
- datatoc_default_world_frag_glsl);
-
- e_data.probe_background_studiolight_sh = DRW_shader_create_with_lib(
+ if (e_data.studiolight_background_sh == NULL) {
+ e_data.studiolight_background_sh = DRW_shader_create_with_shaderlib(
datatoc_background_vert_glsl,
NULL,
- frag_str,
- datatoc_common_view_lib_glsl,
+ datatoc_lookdev_world_frag_glsl,
+ e_data.lib,
"#define LOOKDEV_BG\n" SHADER_DEFINES);
-
- MEM_freeN(frag_str);
}
- return e_data.probe_background_studiolight_sh;
+ return e_data.studiolight_background_sh;
}
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,
- datatoc_lightprobe_lib_glsl,
- datatoc_lightprobe_cube_display_frag_glsl);
-
- char *vert_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_lightprobe_cube_display_vert_glsl);
-
- e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, SHADER_DEFINES);
-
- MEM_freeN(vert_str);
- MEM_freeN(shader_str);
+ e_data.probe_cube_display_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_cube_display_vert_glsl,
+ NULL,
+ datatoc_lightprobe_cube_display_frag_glsl,
+ e_data.lib,
+ SHADER_DEFINES);
}
return e_data.probe_cube_display_sh;
}
@@ -353,22 +345,12 @@ GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void)
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,
- datatoc_irradiance_lib_glsl,
- datatoc_lightprobe_lib_glsl,
- datatoc_lightprobe_grid_display_frag_glsl);
-
- char *vert_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_lightprobe_grid_display_vert_glsl);
-
- e_data.probe_grid_display_sh = DRW_shader_create(vert_str, NULL, shader_str, filter_defines);
-
- MEM_freeN(vert_str);
- MEM_freeN(shader_str);
+ e_data.probe_grid_display_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_grid_display_vert_glsl,
+ NULL,
+ datatoc_lightprobe_grid_display_frag_glsl,
+ e_data.lib,
+ filter_defines);
}
return e_data.probe_grid_display_sh;
}
@@ -376,16 +358,12 @@ GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void)
GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void)
{
if (e_data.probe_planar_display_sh == NULL) {
- char *vert_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_lightprobe_planar_display_vert_glsl);
-
- char *shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_lightprobe_planar_display_frag_glsl);
-
- e_data.probe_planar_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL);
-
- MEM_freeN(vert_str);
- MEM_freeN(shader_str);
+ e_data.probe_planar_display_sh = DRW_shader_create_with_shaderlib(
+ datatoc_lightprobe_planar_display_vert_glsl,
+ NULL,
+ datatoc_lightprobe_planar_display_frag_glsl,
+ e_data.lib,
+ NULL);
}
return e_data.probe_planar_display_sh;
}
@@ -393,34 +371,17 @@ GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void)
GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void)
{
if (e_data.velocity_resolve_sh == NULL) {
- char *frag_str = BLI_string_joinN(datatoc_common_uniforms_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_effect_velocity_resolve_frag_glsl);
-
- e_data.velocity_resolve_sh = DRW_shader_create_fullscreen(frag_str, NULL);
-
- MEM_freeN(frag_str);
+ e_data.velocity_resolve_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_velocity_resolve_frag_glsl, e_data.lib, NULL);
}
return e_data.velocity_resolve_sh;
}
-GPUShader *EEVEE_shaders_default_background_sh_get(void)
-{
- if (e_data.default_background == NULL) {
- e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
- NULL,
- datatoc_default_world_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
- return e_data.default_background;
-}
-
GPUShader *EEVEE_shaders_update_noise_sh_get(void)
{
if (e_data.update_noise_sh == NULL) {
- e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL);
+ e_data.update_noise_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_update_noise_frag_glsl, e_data.lib, NULL);
}
return e_data.update_noise_sh;
}
@@ -437,13 +398,8 @@ GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects)
sh = &e_data.taa_resolve_sh;
}
if (*sh == NULL) {
- char *frag_str = BLI_string_joinN(datatoc_common_uniforms_lib_glsl,
- datatoc_common_view_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_effect_temporal_aa_glsl);
-
- *sh = DRW_shader_create_fullscreen(frag_str, define);
- MEM_freeN(frag_str);
+ *sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_temporal_aa_glsl, e_data.lib, define);
}
return *sh;
@@ -583,6 +539,18 @@ struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo)
return e_data.world.ntree;
}
+World *EEVEE_world_default_get(void)
+{
+ if (e_data.default_world == NULL) {
+ e_data.default_world = BKE_id_new_nomain(ID_WO, "EEVEEE default world");
+ copy_v3_fl(&e_data.default_world->horr, 0.0f);
+ e_data.default_world->use_nodes = 0;
+ e_data.default_world->nodetree = NULL;
+ BLI_listbase_clear(&e_data.default_world->gpumaterial);
+ }
+ return e_data.default_world;
+}
+
static char *eevee_get_defines(int options)
{
char *str = NULL;
@@ -605,7 +573,7 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_HAIR) != 0) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
- if ((options & (VAR_MAT_PROBE | VAR_WORLD_PROBE)) != 0) {
+ if ((options & VAR_WORLD_PROBE) != 0) {
BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n");
}
if ((options & VAR_MAT_HASH) != 0) {
@@ -635,13 +603,13 @@ static char *eevee_get_vert(int options)
char *str = NULL;
if ((options & VAR_MAT_VOLUME) != 0) {
- str = BLI_strdup(e_data.vert_volume_shader_str);
+ str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_vert_glsl);
}
else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) {
- str = BLI_strdup(e_data.vert_background_shader_str);
+ str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_background_vert_glsl);
}
else {
- str = BLI_strdup(e_data.vert_shader_str);
+ str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_surface_vert_glsl);
}
return str;
@@ -652,7 +620,7 @@ static char *eevee_get_geom(int options)
char *str = NULL;
if ((options & VAR_MAT_VOLUME) != 0) {
- str = BLI_strdup(e_data.geom_volume_shader_str);
+ str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_geom_glsl);
}
return str;
@@ -663,18 +631,36 @@ static char *eevee_get_frag(int options)
char *str = NULL;
if ((options & VAR_MAT_VOLUME) != 0) {
- str = BLI_strdup(e_data.volume_shader_lib);
+ str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_frag_glsl);
}
else if ((options & VAR_MAT_DEPTH) != 0) {
- str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl);
+ str = BLI_strdup(e_data.surface_prepass_frag);
}
else {
- str = BLI_strdup(e_data.frag_shader_lib);
+ str = BLI_strdup(e_data.surface_lit_frag);
}
return str;
}
+static void eevee_material_post_eval(GPUMaterial *mat,
+ int options,
+ const char **UNUSED(vert_code),
+ const char **geom_code,
+ const char **UNUSED(frag_lib),
+ const char **UNUSED(defines))
+{
+ const bool is_hair = (options & VAR_MAT_HAIR) != 0;
+ const bool is_mesh = (options & VAR_MAT_MESH) != 0;
+
+ /* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used.
+ * Note: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */
+ if (!is_hair && is_mesh && GPU_material_flag_get(mat, GPU_MATFLAG_BARYCENTRIC) &&
+ *geom_code == NULL) {
+ *geom_code = e_data.surface_geom_barycentric;
+ }
+}
+
static struct GPUMaterial *eevee_material_get_ex(
struct Scene *scene, Material *ma, World *wo, int options, bool deferred)
{
@@ -702,14 +688,16 @@ static struct GPUMaterial *eevee_material_get_ex(
char *frag = eevee_get_frag(options);
if (ma) {
+ GPUMaterialEvalCallbackFn cbfn = &eevee_material_post_eval;
+
bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma);
mat = DRW_shader_create_from_material(
- scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred);
+ scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred, cbfn);
}
else {
bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo);
mat = DRW_shader_create_from_world(
- scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred);
+ scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred, NULL);
}
MEM_SAFE_FREE(defines);
@@ -764,30 +752,31 @@ struct GPUMaterial *EEVEE_material_get(
void EEVEE_shaders_free(void)
{
- MEM_SAFE_FREE(e_data.frag_shader_lib);
- MEM_SAFE_FREE(e_data.vert_shader_str);
- MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
- MEM_SAFE_FREE(e_data.vert_background_shader_str);
- MEM_SAFE_FREE(e_data.vert_volume_shader_str);
- MEM_SAFE_FREE(e_data.geom_volume_shader_str);
- MEM_SAFE_FREE(e_data.volume_shader_lib);
- DRW_SHADER_FREE_SAFE(e_data.default_background);
+ MEM_SAFE_FREE(e_data.closure_lit_lib);
+ MEM_SAFE_FREE(e_data.surface_prepass_frag);
+ MEM_SAFE_FREE(e_data.surface_lit_frag);
+ MEM_SAFE_FREE(e_data.surface_geom_barycentric);
+ DRW_SHADER_FREE_SAFE(e_data.lookdev_background);
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
- DRW_SHADER_FREE_SAFE(e_data.probe_default_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_planar_downsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.probe_default_studiolight_sh);
- DRW_SHADER_FREE_SAFE(e_data.probe_background_studiolight_sh);
+ DRW_SHADER_FREE_SAFE(e_data.studiolight_probe_sh);
+ DRW_SHADER_FREE_SAFE(e_data.studiolight_background_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh);
DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh);
+ DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
+ if (e_data.default_world) {
+ BKE_id_free(NULL, e_data.default_world);
+ e_data.default_world = NULL;
+ }
if (e_data.glossy_mat) {
BKE_id_free(NULL, e_data.glossy_mat);
e_data.glossy_mat = NULL;
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index 8c50b26b45f..0da356b75ac 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -42,11 +42,6 @@ static struct {
extern char datatoc_shadow_vert_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_accum_frag_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_common_uniforms_lib_glsl[];
-extern char datatoc_bsdf_common_lib_glsl[];
-extern char datatoc_lights_lib_glsl[];
-extern char datatoc_raytrace_lib_glsl[];
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
{
@@ -65,23 +60,13 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
if (!e_data.shadow_sh) {
- e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
- NULL,
- datatoc_shadow_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
- if (!e_data.shadow_accum_sh) {
- char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_raytrace_lib_glsl,
- datatoc_lights_lib_glsl,
- datatoc_shadow_accum_frag_glsl);
+ e_data.shadow_sh = DRW_shader_create_with_shaderlib(
+ datatoc_shadow_vert_glsl, NULL, datatoc_shadow_frag_glsl, lib, NULL);
- e_data.shadow_accum_sh = DRW_shader_create_fullscreen(frag_str, SHADER_DEFINES);
- MEM_freeN(frag_str);
+ e_data.shadow_accum_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_shadow_accum_frag_glsl, lib, SHADER_DEFINES);
}
if (!sldata->lights) {
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index ef4588f4aca..637c5201afc 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -38,41 +38,19 @@ static struct {
struct GPUShader *sss_sh[3];
} e_data = {{NULL}}; /* Engine data */
-extern char datatoc_common_view_lib_glsl[];
-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[];
extern char datatoc_effect_translucency_frag_glsl[];
static void eevee_create_shader_subsurface(void)
{
- char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_effect_subsurface_frag_glsl);
-
- /* TODO(fclem) remove some of these dependencies. */
- char *frag_translucent_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- 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);
-
- e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
- e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n");
- e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_translucent_str,
- "#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES);
-
- MEM_freeN(frag_translucent_str);
- MEM_freeN(frag_str);
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
+
+ e_data.sss_sh[0] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_subsurface_frag_glsl, lib, "#define FIRST_PASS\n");
+ e_data.sss_sh[1] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_subsurface_frag_glsl, lib, "#define SECOND_PASS\n");
+ e_data.sss_sh[2] = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_translucency_frag_glsl, lib, "#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES);
}
void EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *UNUSED(vedata))
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 300022e97a9..57d5e54290e 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -44,16 +44,12 @@
#include "DEG_depsgraph_query.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
#include "GPU_texture.h"
#include "eevee_private.h"
static struct {
- char *volumetric_common_lib;
- char *volumetric_common_lights_lib;
-
struct GPUShader *volumetric_clear_sh;
struct GPUShader *scatter_sh;
struct GPUShader *scatter_with_lights_sh;
@@ -97,57 +93,48 @@ extern char datatoc_common_fullscreen_vert_glsl[];
static void eevee_create_shader_volumes(void)
{
- e_data.volumetric_common_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_volumetric_lib_glsl);
-
- e_data.volumetric_common_lights_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
- 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);
-
- e_data.volumetric_clear_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
- datatoc_volumetric_frag_glsl,
- e_data.volumetric_common_lib,
- "#define VOLUMETRICS\n"
- "#define CLEAR\n");
- e_data.scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
- datatoc_volumetric_scatter_frag_glsl,
- e_data.volumetric_common_lights_lib,
- SHADER_DEFINES
- "#define VOLUMETRICS\n"
- "#define VOLUME_SHADOW\n");
- e_data.scatter_with_lights_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
- datatoc_volumetric_scatter_frag_glsl,
- e_data.volumetric_common_lights_lib,
- SHADER_DEFINES
- "#define VOLUMETRICS\n"
- "#define VOLUME_LIGHTING\n"
- "#define VOLUME_SHADOW\n");
- e_data.volumetric_integration_sh = DRW_shader_create_with_lib(
+ DRWShaderLibrary *lib = EEVEE_shader_lib_get();
+
+ e_data.volumetric_clear_sh = DRW_shader_create_with_shaderlib(datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_frag_glsl,
+ lib,
+ SHADER_DEFINES
+ "#define VOLUMETRICS\n"
+ "#define CLEAR\n");
+
+ e_data.scatter_sh = DRW_shader_create_with_shaderlib(datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_scatter_frag_glsl,
+ lib,
+ SHADER_DEFINES
+ "#define VOLUMETRICS\n"
+ "#define VOLUME_SHADOW\n");
+
+ e_data.scatter_with_lights_sh = DRW_shader_create_with_shaderlib(
+ datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_scatter_frag_glsl,
+ lib,
+ SHADER_DEFINES
+ "#define VOLUMETRICS\n"
+ "#define VOLUME_LIGHTING\n"
+ "#define VOLUME_SHADOW\n");
+
+ e_data.volumetric_integration_sh = DRW_shader_create_with_shaderlib(
datatoc_volumetric_vert_glsl,
datatoc_volumetric_geom_glsl,
datatoc_volumetric_integration_frag_glsl,
- e_data.volumetric_common_lib,
+ lib,
USE_VOLUME_OPTI ? "#extension GL_ARB_shader_image_load_store: enable\n"
"#extension GL_ARB_shading_language_420pack: enable\n"
- "#define USE_VOLUME_OPTI\n" :
- NULL);
- e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
- NULL,
- datatoc_volumetric_resolve_frag_glsl,
- e_data.volumetric_common_lib,
- NULL);
- e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl,
- NULL);
+ "#define USE_VOLUME_OPTI\n" SHADER_DEFINES :
+ SHADER_DEFINES);
+
+ e_data.volumetric_resolve_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_volumetric_resolve_frag_glsl, lib, SHADER_DEFINES);
+ e_data.volumetric_accum_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_volumetric_accum_frag_glsl, lib, SHADER_DEFINES);
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);
@@ -259,17 +246,11 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->vol_shadow_steps = 0;
}
- /* Update view_vecs */
- float invproj[4][4], winmat[4][4];
- DRW_view_winmat_get(NULL, winmat, false);
- DRW_view_winmat_get(NULL, invproj, true);
- EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs);
-
if (DRW_view_is_persp_get(NULL)) {
float sample_distribution = scene_eval->eevee.volumetric_sample_distribution;
sample_distribution = 4.0f * (max_ff(1.0f - sample_distribution, 1e-2f));
- const float clip_start = common_data->view_vecs[0][2];
+ const float clip_start = DRW_view_near_distance_get(NULL);
/* Negate */
float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f);
float far = integration_end = min_ff(-integration_end, near - 1e-4f);
@@ -280,8 +261,8 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->vol_depth_param[2] = sample_distribution;
}
else {
- const float clip_start = common_data->view_vecs[0][2];
- const float clip_end = clip_start + common_data->view_vecs[1][2];
+ const float clip_start = DRW_view_near_distance_get(NULL);
+ const float clip_end = DRW_view_far_distance_get(NULL);
integration_start = min_ff(integration_end, clip_start);
integration_end = max_ff(-integration_end, clip_end);
@@ -504,12 +485,7 @@ static bool eevee_volume_object_mesh_init(Scene *scene,
#endif
if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) {
- if (!(fds->flags & FLUID_DOMAIN_USE_NOISE)) {
- GPU_create_smoke(fmd, 0);
- }
- else if (fds->flags & FLUID_DOMAIN_USE_NOISE) {
- GPU_create_smoke(fmd, 1);
- }
+ DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(fmd));
}
@@ -841,16 +817,13 @@ void EEVEE_volumes_free_smoke_textures(void)
/* Free Smoke Textures after rendering */
LISTBASE_FOREACH (LinkData *, link, &e_data.smoke_domains) {
FluidModifierData *fmd = (FluidModifierData *)link->data;
- GPU_free_smoke(fmd);
+ DRW_smoke_free(fmd);
}
BLI_freelistN(&e_data.smoke_domains);
}
void EEVEE_volumes_free(void)
{
- MEM_SAFE_FREE(e_data.volumetric_common_lib);
- MEM_SAFE_FREE(e_data.volumetric_common_lights_lib);
-
DRW_TEXTURE_FREE_SAFE(e_data.dummy_scatter);
DRW_TEXTURE_FREE_SAFE(e_data.dummy_transmit);
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 57b16418696..2f6f8327f58 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -1,4 +1,7 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
+
/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion
* http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf
* http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pptx
@@ -24,12 +27,6 @@
#define MAX_SEARCH_ITER 32
#define MAX_LOD 6.0
-#ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-#endif /* UTIL_TEX */
-
uniform sampler2D horizonBuffer;
/* aoSettings flags */
@@ -243,6 +240,11 @@ float gtao_multibounce(float visibility, vec3 albedo)
return max(x, ((x * a + b) * x + c) * x);
}
+float specular_occlusion(float NV, float AO, float roughness)
+{
+ return saturate(pow(NV + AO, roughness) - 1.0 + AO);
+}
+
/* Use the right occlusion */
float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal)
{
diff --git a/source/blender/draw/engines/eevee/shaders/background_vert.glsl b/source/blender/draw/engines/eevee/shaders/background_vert.glsl
index aff8e0857f6..ab5d9a7ebe4 100644
--- a/source/blender/draw/engines/eevee/shaders/background_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/background_vert.glsl
@@ -1,17 +1,17 @@
-in vec2 pos;
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
-out vec3 viewPosition;
+in vec2 pos;
-#ifndef VOLUMETRICS
-/* necessary for compilation*/
-out vec3 worldPosition;
-out vec3 worldNormal;
-out vec3 viewNormal;
-#endif
+RESOURCE_ID_VARYING
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ PASS_RESOURCE_ID
+
gl_Position = vec4(pos, 1.0, 1.0);
viewPosition = vec3(pos, -1.0);
@@ -22,6 +22,6 @@ void main()
#endif
#ifdef USE_ATTR
- pass_attr(viewPosition);
+ pass_attr(viewPosition, NormalMatrix, ModelMatrixInverse);
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index a8b8566edec..deedde64194 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -1,487 +1,7 @@
-#define M_PI 3.14159265358979323846 /* pi */
-#define M_2PI 6.28318530717958647692 /* 2*pi */
-#define M_PI_2 1.57079632679489661923 /* pi/2 */
-#define M_1_PI 0.318309886183790671538 /* 1/pi */
-#define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */
-#define M_1_PI2 0.101321183642337771443 /* 1/(pi^2) */
-#define FLT_MAX 3.402823e+38
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
-#define LUT_SIZE 64
-
-/* Buffers */
-uniform sampler2D colorBuffer;
-uniform sampler2D depthBuffer;
-uniform sampler2D maxzBuffer;
-uniform sampler2D minzBuffer;
-uniform sampler2DArray planarDepth;
-
-#define cameraForward ViewMatrixInverse[2].xyz
-#define cameraPos ViewMatrixInverse[3].xyz
-#define cameraVec \
- ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
-#define viewCameraVec \
- ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0))
-
-/* ------- Structures -------- */
-
-/* ------ Lights ----- */
-struct LightData {
- vec4 position_influence; /* w : InfluenceRadius (inversed and squared) */
- vec4 color_spec; /* w : Spec Intensity */
- vec4 spotdata_radius_shadow; /* x : spot size, y : spot blend, z : radius, w: shadow id */
- vec4 rightvec_sizex; /* xyz: Normalized up vector, w: area size X or spot scale X */
- vec4 upvec_sizey; /* xyz: Normalized right vector, w: area size Y or spot scale Y */
- vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Light Type */
-};
-
-/* convenience aliases */
-#define l_color color_spec.rgb
-#define l_spec color_spec.a
-#define l_position position_influence.xyz
-#define l_influence position_influence.w
-#define l_sizex rightvec_sizex.w
-#define l_sizey upvec_sizey.w
-#define l_right rightvec_sizex.xyz
-#define l_up upvec_sizey.xyz
-#define l_forward forwardvec_type.xyz
-#define l_type forwardvec_type.w
-#define l_spot_size spotdata_radius_shadow.x
-#define l_spot_blend spotdata_radius_shadow.y
-#define l_radius spotdata_radius_shadow.z
-#define l_shadowid spotdata_radius_shadow.w
-
-/* ------ Shadows ----- */
-#ifndef MAX_CASCADE_NUM
-# define MAX_CASCADE_NUM 4
-#endif
-
-struct ShadowData {
- vec4 near_far_bias_id;
- vec4 contact_shadow_data;
-};
-
-struct ShadowCubeData {
- mat4 shadowmat;
- vec4 position;
-};
-
-struct ShadowCascadeData {
- mat4 shadowmat[MAX_CASCADE_NUM];
- vec4 split_start_distances;
- vec4 split_end_distances;
- vec4 shadow_vec_id;
-};
-
-/* convenience aliases */
-#define sh_near near_far_bias_id.x
-#define sh_far near_far_bias_id.y
-#define sh_bias near_far_bias_id.z
-#define sh_data_index near_far_bias_id.w
-#define sh_contact_dist contact_shadow_data.x
-#define sh_contact_offset contact_shadow_data.y
-#define sh_contact_spread contact_shadow_data.z
-#define sh_contact_thickness contact_shadow_data.w
-#define sh_shadow_vec shadow_vec_id.xyz
-#define sh_tex_index shadow_vec_id.w
-
-/* ------ Render Passes ----- */
-layout(std140) uniform renderpass_block
-{
- bool renderPassDiffuse;
- bool renderPassDiffuseLight;
- bool renderPassGlossy;
- bool renderPassGlossyLight;
- bool renderPassEmit;
- bool renderPassSSSColor;
- bool renderPassEnvironment;
-};
-
-vec3 render_pass_diffuse_mask(vec3 diffuse_color, vec3 diffuse_light)
-{
- return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : diffuse_color) : vec3(0.0);
-}
-
-vec3 render_pass_sss_mask(vec3 sss_color)
-{
- return renderPassSSSColor ? sss_color : vec3(0.0);
-}
-
-vec3 render_pass_glossy_mask(vec3 specular_color, vec3 specular_light)
-{
- return renderPassGlossy ? (renderPassGlossyLight ? specular_light : specular_color) : vec3(0.0);
-}
-
-vec3 render_pass_emission_mask(vec3 emission_light)
-{
- return renderPassEmit ? emission_light : vec3(0.0);
-}
-
-/* ------- Convenience functions --------- */
-
-vec3 mul(mat3 m, vec3 v)
-{
- return m * v;
-}
-mat3 mul(mat3 m1, mat3 m2)
-{
- return m1 * m2;
-}
-vec3 transform_direction(mat4 m, vec3 v)
-{
- return mat3(m) * v;
-}
-vec3 transform_point(mat4 m, vec3 v)
-{
- return (m * vec4(v, 1.0)).xyz;
-}
-vec3 project_point(mat4 m, vec3 v)
-{
- vec4 tmp = m * vec4(v, 1.0);
- return tmp.xyz / tmp.w;
-}
-
-#define min3(a, b, c) min(a, min(b, c))
-#define min4(a, b, c, d) min(a, min3(b, c, d))
-#define min5(a, b, c, d, e) min(a, min4(b, c, d, e))
-#define min6(a, b, c, d, e, f) min(a, min5(b, c, d, e, f))
-#define min7(a, b, c, d, e, f, g) min(a, min6(b, c, d, e, f, g))
-#define min8(a, b, c, d, e, f, g, h) min(a, min7(b, c, d, e, f, g, h))
-#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i))
-
-#define max3(a, b, c) max(a, max(b, c))
-#define max4(a, b, c, d) max(a, max3(b, c, d))
-#define max5(a, b, c, d, e) max(a, max4(b, c, d, e))
-#define max6(a, b, c, d, e, f) max(a, max5(b, c, d, e, f))
-#define max7(a, b, c, d, e, f, g) max(a, max6(b, c, d, e, f, g))
-#define max8(a, b, c, d, e, f, g, h) max(a, max7(b, c, d, e, f, g, h))
-#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i))
-
-#define avg3(a, b, c) (a + b + c) * (1.0 / 3.0)
-#define avg4(a, b, c, d) (a + b + c + d) * (1.0 / 4.0)
-#define avg5(a, b, c, d, e) (a + b + c + d + e) * (1.0 / 5.0)
-#define avg6(a, b, c, d, e, f) (a + b + c + d + e + f) * (1.0 / 6.0)
-#define avg7(a, b, c, d, e, f, g) (a + b + c + d + e + f + g) * (1.0 / 7.0)
-#define avg8(a, b, c, d, e, f, g, h) (a + b + c + d + e + f + g + h) * (1.0 / 8.0)
-#define avg9(a, b, c, d, e, f, g, h, i) (a + b + c + d + e + f + g + h + i) * (1.0 / 9.0)
-
-float min_v2(vec2 v)
-{
- return min(v.x, v.y);
-}
-float min_v3(vec3 v)
-{
- return min(v.x, min(v.y, v.z));
-}
-float min_v4(vec4 v)
-{
- return min(min(v.x, v.y), min(v.z, v.w));
-}
-float max_v2(vec2 v)
-{
- return max(v.x, v.y);
-}
-float max_v3(vec3 v)
-{
- return max(v.x, max(v.y, v.z));
-}
-float max_v4(vec4 v)
-{
- return max(max(v.x, v.y), max(v.z, v.w));
-}
-
-float sum(vec2 v)
-{
- return dot(vec2(1.0), v);
-}
-float sum(vec3 v)
-{
- return dot(vec3(1.0), v);
-}
-float sum(vec4 v)
-{
- return dot(vec4(1.0), v);
-}
-
-float avg(vec2 v)
-{
- return dot(vec2(1.0 / 2.0), v);
-}
-float avg(vec3 v)
-{
- return dot(vec3(1.0 / 3.0), v);
-}
-float avg(vec4 v)
-{
- return dot(vec4(1.0 / 4.0), v);
-}
-
-float saturate(float a)
-{
- return clamp(a, 0.0, 1.0);
-}
-vec2 saturate(vec2 a)
-{
- return clamp(a, 0.0, 1.0);
-}
-vec3 saturate(vec3 a)
-{
- return clamp(a, 0.0, 1.0);
-}
-vec4 saturate(vec4 a)
-{
- return clamp(a, 0.0, 1.0);
-}
-
-float distance_squared(vec2 a, vec2 b)
-{
- a -= b;
- return dot(a, a);
-}
-float distance_squared(vec3 a, vec3 b)
-{
- a -= b;
- return dot(a, a);
-}
-float len_squared(vec3 a)
-{
- return dot(a, a);
-}
-
-float inverse_distance(vec3 V)
-{
- return max(1 / length(V), 1e-8);
-}
-
-vec2 mip_ratio_interp(float mip)
-{
- float low_mip = floor(mip);
- return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip);
-}
-
-/* ------- RNG ------- */
-
-float wang_hash_noise(uint s)
-{
- s = (s ^ 61u) ^ (s >> 16u);
- s *= 9u;
- s = s ^ (s >> 4u);
- s *= 0x27d4eb2du;
- s = s ^ (s >> 15u);
-
- return fract(float(s) / 4294967296.0);
-}
-
-/* ------- Fast Math ------- */
-
-/* [Drobot2014a] Low Level Optimizations for GCN */
-float fast_sqrt(float v)
-{
- return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1));
-}
-
-vec2 fast_sqrt(vec2 v)
-{
- return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1));
-}
-
-/* [Eberly2014] GPGPU Programming for Games and Science */
-float fast_acos(float v)
-{
- float res = -0.156583 * abs(v) + M_PI_2;
- res *= fast_sqrt(1.0 - abs(v));
- return (v >= 0) ? res : M_PI - res;
-}
-
-vec2 fast_acos(vec2 v)
-{
- vec2 res = -0.156583 * abs(v) + M_PI_2;
- res *= fast_sqrt(1.0 - abs(v));
- v.x = (v.x >= 0) ? res.x : M_PI - res.x;
- v.y = (v.y >= 0) ? res.y : M_PI - res.y;
- return v;
-}
-
-float point_plane_projection_dist(vec3 lineorigin, vec3 planeorigin, vec3 planenormal)
-{
- return dot(planenormal, planeorigin - lineorigin);
-}
-
-float line_plane_intersect_dist(vec3 lineorigin,
- vec3 linedirection,
- vec3 planeorigin,
- vec3 planenormal)
-{
- return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);
-}
-
-float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec4 plane)
-{
- vec3 plane_co = plane.xyz * (-plane.w / len_squared(plane.xyz));
- vec3 h = lineorigin - plane_co;
- return -dot(plane.xyz, h) / dot(plane.xyz, linedirection);
-}
-
-vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
-{
- float dist = line_plane_intersect_dist(lineorigin, linedirection, planeorigin, planenormal);
- return lineorigin + linedirection * dist;
-}
-
-vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec4 plane)
-{
- float dist = line_plane_intersect_dist(lineorigin, linedirection, plane);
- return lineorigin + linedirection * dist;
-}
-
-float line_aligned_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
-{
- /* aligned plane normal */
- vec3 L = planeorigin - lineorigin;
- float diskdist = length(L);
- vec3 planenormal = -normalize(L);
- return -diskdist / dot(planenormal, linedirection);
-}
-
-vec3 line_aligned_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
-{
- float dist = line_aligned_plane_intersect_dist(lineorigin, linedirection, planeorigin);
- if (dist < 0) {
- /* if intersection is behind we fake the intersection to be
- * really far and (hopefully) not inside the radius of interest */
- dist = 1e16;
- }
- return lineorigin + linedirection * dist;
-}
-
-float line_unit_sphere_intersect_dist(vec3 lineorigin, vec3 linedirection)
-{
- float a = dot(linedirection, linedirection);
- float b = dot(linedirection, lineorigin);
- float c = dot(lineorigin, lineorigin) - 1;
-
- float dist = 1e15;
- float determinant = b * b - a * c;
- if (determinant >= 0) {
- dist = (sqrt(determinant) - b) / a;
- }
-
- return dist;
-}
-
-float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
-{
- /* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
- */
- vec3 firstplane = (vec3(1.0) - lineorigin) / linedirection;
- vec3 secondplane = (vec3(-1.0) - lineorigin) / linedirection;
- vec3 furthestplane = max(firstplane, secondplane);
-
- return min_v3(furthestplane);
-}
-
-/* Return texture coordinates to sample Surface LUT */
-vec2 lut_coords(float cosTheta, float roughness)
-{
- float theta = acos(cosTheta);
- vec2 coords = vec2(roughness, theta / M_PI_2);
-
- /* scale and bias coordinates, for correct filtered lookup */
- return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
-}
-
-vec2 lut_coords_ltc(float cosTheta, float roughness)
-{
- vec2 coords = vec2(roughness, sqrt(1.0 - cosTheta));
-
- /* scale and bias coordinates, for correct filtered lookup */
- return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
-}
-
-/* -- Tangent Space conversion -- */
-vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
-{
- return T * vector.x + B * vector.y + N * vector.z;
-}
-
-vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B)
-{
- return vec3(dot(T, vector), dot(B, vector), dot(N, vector));
-}
-
-void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B)
-{
- vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- T = normalize(cross(UpVector, N));
- B = cross(N, T);
-}
-
-/* ---- Opengl Depth conversion ---- */
-
-float linear_depth(bool is_persp, float z, float zf, float zn)
-{
- if (is_persp) {
- return (zn * zf) / (z * (zn - zf) + zf);
- }
- else {
- return (z * 2.0 - 1.0) * zf;
- }
-}
-
-float buffer_depth(bool is_persp, float z, float zf, float zn)
-{
- if (is_persp) {
- return (zf * (zn - z)) / (z * (zn - zf));
- }
- else {
- return (z / (zf * 2.0)) + 0.5;
- }
-}
-
-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;
- }
-}
-
-float get_depth_from_view_z(float z)
-{
- if (ProjectionMatrix[3][3] == 0.0) {
- float d = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
- return d * 0.5 + 0.5;
- }
- else {
- return (z - viewVecs[0].z) / viewVecs[1].z;
- }
-}
-
-vec2 get_uvs_from_view(vec3 view)
-{
- vec3 ndc = project_point(ProjectionMatrix, view);
- return ndc.xy * 0.5 + 0.5;
-}
-
-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;
- }
-}
-
-vec3 get_world_space_from_depth(vec2 uvcoords, float depth)
-{
- return (ViewMatrixInverse * vec4(get_view_space_from_depth(uvcoords, depth), 1.0)).xyz;
-}
-
-vec3 get_specular_reflection_dominant_dir(vec3 N, vec3 V, float roughness)
+vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness)
{
vec3 R = -reflect(V, N);
float smoothness = 1.0 - roughness;
@@ -489,13 +9,6 @@ vec3 get_specular_reflection_dominant_dir(vec3 N, vec3 V, float roughness)
return normalize(mix(N, R, fac));
}
-float specular_occlusion(float NV, float AO, float roughness)
-{
- return saturate(pow(NV + AO, roughness) - 1.0 + AO);
-}
-
-/* --- Refraction utils --- */
-
float ior_from_f0(float f0)
{
float f = sqrt(f0);
@@ -508,7 +21,7 @@ float f0_from_ior(float eta)
return A * A;
}
-vec3 get_specular_refraction_dominant_dir(vec3 N, vec3 V, float roughness, float ior)
+vec3 refraction_dominant_dir(vec3 N, vec3 V, float roughness, float ior)
{
/* TODO: This a bad approximation. Better approximation should fit
* the refracted vector and roughness into the best prefiltered reflection
@@ -527,128 +40,6 @@ vec3 get_specular_refraction_dominant_dir(vec3 N, vec3 V, float roughness, float
return R;
}
-float get_btdf_lut(sampler2DArray btdf_lut_tex, float NV, float roughness, float ior)
-{
- const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
-
- vec3 coords;
- /* Try to compensate for the low resolution and interpolation error. */
- coords.x = (ior > 1.0) ? (0.9 + lut_scale_bias_texel_size.z) +
- (0.1 - lut_scale_bias_texel_size.z) * f0_from_ior(ior) :
- (0.9 + lut_scale_bias_texel_size.z) * ior * ior;
- coords.y = 1.0 - saturate(NV);
- coords.xy *= lut_scale_bias_texel_size.x;
- coords.xy += lut_scale_bias_texel_size.y;
-
- const float lut_lvl_ofs = 4.0; /* First texture lvl of roughness. */
- const float lut_lvl_scale = 16.0; /* How many lvl of roughness in the lut. */
-
- float mip = roughness * lut_lvl_scale;
- float mip_floor = floor(mip);
-
- coords.z = lut_lvl_ofs + mip_floor + 1.0;
- float btdf_high = textureLod(btdf_lut_tex, coords, 0.0).r;
-
- coords.z -= 1.0;
- float btdf_low = textureLod(btdf_lut_tex, coords, 0.0).r;
-
- float btdf = (ior == 1.0) ? 1.0 : mix(btdf_low, btdf_high, mip - coords.z);
-
- return btdf;
-}
-
-/* ---- Encode / Decode Normal buffer data ---- */
-/* From http://aras-p.info/texts/CompactNormalStorage.html
- * Using Method #4: Spheremap Transform */
-vec2 normal_encode(vec3 n, vec3 view)
-{
- float p = sqrt(n.z * 8.0 + 8.0);
- return n.xy / p + 0.5;
-}
-
-vec3 normal_decode(vec2 enc, vec3 view)
-{
- vec2 fenc = enc * 4.0 - 2.0;
- float f = dot(fenc, fenc);
- float g = sqrt(1.0 - f / 4.0);
- vec3 n;
- n.xy = fenc * g;
- n.z = 1 - f / 2;
- return n;
-}
-
-/* ---- RGBM (shared multiplier) encoding ---- */
-/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */
-
-/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */
-#define RGBM_MAX_RANGE 512.0
-
-vec4 rgbm_encode(vec3 rgb)
-{
- float maxRGB = max_v3(rgb);
- float M = maxRGB / RGBM_MAX_RANGE;
- M = ceil(M * 255.0) / 255.0;
- return vec4(rgb / (M * RGBM_MAX_RANGE), M);
-}
-
-vec3 rgbm_decode(vec4 data)
-{
- return data.rgb * (data.a * RGBM_MAX_RANGE);
-}
-
-/* ---- RGBE (shared exponent) encoding ---- */
-vec4 rgbe_encode(vec3 rgb)
-{
- float maxRGB = max_v3(rgb);
- float fexp = ceil(log2(maxRGB));
- return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
-}
-
-vec3 rgbe_decode(vec4 data)
-{
- float fexp = data.a * 255.0 - 128.0;
- return data.rgb * exp2(fexp);
-}
-
-#if 1
-# define irradiance_encode rgbe_encode
-# define irradiance_decode rgbe_decode
-#else /* No ecoding (when using floating point format) */
-# define irradiance_encode(X) (X).rgbb
-# define irradiance_decode(X) (X).rgb
-#endif
-
-/* Irradiance Visibility Encoding */
-#if 1
-vec4 visibility_encode(vec2 accum, float range)
-{
- accum /= range;
-
- vec4 data;
- data.x = fract(accum.x);
- data.y = floor(accum.x) / 255.0;
- data.z = fract(accum.y);
- data.w = floor(accum.y) / 255.0;
-
- return data;
-}
-
-vec2 visibility_decode(vec4 data, float range)
-{
- return (data.xz + data.yw * 255.0) * range;
-}
-#else /* No ecoding (when using floating point format) */
-vec4 visibility_encode(vec2 accum, float range)
-{
- return accum.xyxy;
-}
-
-vec2 visibility_decode(vec4 data, float range)
-{
- return data.xy;
-}
-#endif
-
/* Fresnel monochromatic, perfect mirror */
float F_eta(float eta, float cos_theta)
{
@@ -766,265 +157,3 @@ float cone_cosine(float r)
/* Jimenez 2016 in Practical Realtime Strategies for Accurate Indirect Occlusion*/
return exp2(-3.32193 * r * r);
}
-
-/* --------- Closure ---------- */
-
-#ifdef VOLUMETRICS
-
-struct Closure {
- vec3 absorption;
- vec3 scatter;
- vec3 emission;
- float anisotropy;
-};
-
-Closure nodetree_exec(void); /* Prototype */
-
-# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
-
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
-{
- Closure cl;
- cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
- cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
- cl.emission = mix(cl1.emission, cl2.emission, fac);
- cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
- return cl;
-}
-
-Closure closure_add(Closure cl1, Closure cl2)
-{
- Closure cl;
- cl.absorption = cl1.absorption + cl2.absorption;
- cl.scatter = cl1.scatter + cl2.scatter;
- cl.emission = cl1.emission + cl2.emission;
- cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
- return cl;
-}
-
-Closure closure_emission(vec3 rgb)
-{
- Closure cl = CLOSURE_DEFAULT;
- cl.emission = rgb;
- return cl;
-}
-
-#else /* VOLUMETRICS */
-
-struct Closure {
- vec3 radiance;
- vec3 transmittance;
- float holdout;
-# ifdef USE_SSS
- vec3 sss_irradiance;
- vec3 sss_albedo;
- float sss_radius;
-# endif
- vec4 ssr_data;
- vec2 ssr_normal;
- int flag;
-};
-
-Closure nodetree_exec(void); /* Prototype */
-
-# define FLAG_TEST(flag, val) (((flag) & (val)) != 0)
-
-# define CLOSURE_SSR_FLAG 1
-# define CLOSURE_SSS_FLAG 2
-# define CLOSURE_HOLDOUT_FLAG 4
-
-# ifdef USE_SSS
-# define CLOSURE_DEFAULT \
- Closure(vec3(0.0), vec3(0.0), 0.0, vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
-# else
-# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
-# endif
-
-uniform int outputSsrId = 1;
-uniform int outputSssId = 1;
-
-void closure_load_ssr_data(
- vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
-{
- /* Still encode to avoid artifacts in the SSR pass. */
- vec3 vN = normalize(mat3(ViewMatrix) * N);
- cl.ssr_normal = normal_encode(vN, viewVec);
-
- if (ssr_id == outputSsrId) {
- cl.ssr_data = vec4(ssr_spec, roughness);
- cl.flag |= CLOSURE_SSR_FLAG;
- }
-}
-
-void closure_load_sss_data(
- float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl)
-{
-# ifdef USE_SSS
- if (sss_id == outputSssId) {
- cl.sss_irradiance = sss_irradiance;
- cl.sss_radius = radius;
- cl.sss_albedo = sss_albedo;
- cl.flag |= CLOSURE_SSS_FLAG;
- cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0));
- }
- else
-# endif
- {
- cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo);
- }
-}
-
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
-{
- Closure cl;
- cl.holdout = mix(cl1.holdout, cl2.holdout, fac);
-
- if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) {
- fac = 1.0;
- }
- else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) {
- fac = 0.0;
- }
-
- cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac);
- cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
- cl.flag = cl1.flag | cl2.flag;
- cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac);
- bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
- /* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz).*/
- cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
- cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
-
-# ifdef USE_SSS
- cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac);
- bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or irradiance. */
- cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
- cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
-# endif
- return cl;
-}
-
-Closure closure_add(Closure cl1, Closure cl2)
-{
- Closure cl;
- cl.transmittance = cl1.transmittance + cl2.transmittance;
- cl.radiance = cl1.radiance + cl2.radiance;
- cl.holdout = cl1.holdout + cl2.holdout;
- cl.flag = cl1.flag | cl2.flag;
- cl.ssr_data = cl1.ssr_data + cl2.ssr_data;
- bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
- /* When mixing SSR don't blend roughness and normals.*/
- cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
- cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
-
-# ifdef USE_SSS
- cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo;
- bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or irradiance. */
- cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
- cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
-# endif
- return cl;
-}
-
-Closure closure_emission(vec3 rgb)
-{
- Closure cl = CLOSURE_DEFAULT;
- cl.radiance = rgb;
- return cl;
-}
-
-/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
-/* clang-format off */
-# if defined(MESH_SHADER) && !defined(DEPTH_SHADER)
-/* clang-format on */
-# ifndef USE_ALPHA_BLEND
-layout(location = 0) out vec4 outRadiance;
-layout(location = 1) out vec2 ssrNormals;
-layout(location = 2) out vec4 ssrData;
-# ifdef USE_SSS
-layout(location = 3) out vec3 sssIrradiance;
-layout(location = 4) out float sssRadius;
-layout(location = 5) out vec3 sssAlbedo;
-# endif
-# else /* USE_ALPHA_BLEND */
-/* Use dual source blending to be able to make a whole range of effects. */
-layout(location = 0, index = 0) out vec4 outRadiance;
-layout(location = 0, index = 1) out vec4 outTransmittance;
-# endif /* USE_ALPHA_BLEND */
-
-# if defined(USE_ALPHA_BLEND)
-/* Prototype because this file is included before volumetric_lib.glsl */
-void volumetric_resolve(vec2 frag_uvs,
- float frag_depth,
- out vec3 transmittance,
- out vec3 scattering);
-# endif
-
-# define NODETREE_EXEC
-void main()
-{
- Closure cl = nodetree_exec();
-
- float holdout = saturate(1.0 - cl.holdout);
- float transmit = saturate(avg(cl.transmittance));
- float alpha = 1.0 - transmit;
-
-# ifdef USE_ALPHA_BLEND
- vec2 uvs = gl_FragCoord.xy * volCoordScale.zw;
- vec3 vol_transmit, vol_scatter;
- volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
-
- /* Removes part of the volume scattering that have
- * already been added to the destination pixels.
- * Since we do that using the blending pipeline we need to account for material transmittance. */
- vol_scatter -= vol_scatter * cl.transmittance;
-
- cl.radiance = cl.radiance * holdout * vol_transmit + vol_scatter;
- outRadiance = vec4(cl.radiance, alpha * holdout);
- outTransmittance = vec4(cl.transmittance, transmit) * holdout;
-# else
- outRadiance = vec4(cl.radiance, holdout);
- ssrNormals = cl.ssr_normal;
- ssrData = cl.ssr_data;
-# ifdef USE_SSS
- sssIrradiance = cl.sss_irradiance;
- sssRadius = cl.sss_radius;
- sssAlbedo = cl.sss_albedo;
-# endif
-# endif
-
- /* For Probe capture */
-# ifdef USE_SSS
- float fac = float(!sssToggle);
-
- /* TODO(fclem) we shouldn't need this.
- * Just disable USE_SSS when USE_REFRACTION is enabled. */
-# ifdef USE_REFRACTION
- /* SSRefraction pass is done after the SSS pass.
- * In order to not loose the diffuse light totally we
- * need to merge the SSS radiance to the main radiance. */
- fac = 1.0;
-# endif
-
- outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
-# endif
-
-# ifdef LOOKDEV
- gl_FragDepth = 0.0;
-# endif
-
-# ifndef USE_ALPHA_BLEND
- float alpha_div = 1.0 / max(1e-8, alpha);
- outRadiance.rgb *= alpha_div;
- ssrData.rgb *= alpha_div;
-# ifdef USE_SSS
- sssAlbedo.rgb *= alpha_div;
-# endif
-# endif
-}
-
-# endif /* MESH_SHADER */
-
-#endif /* VOLUMETRICS */
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
index f05b3396428..2b2da884fde 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
@@ -1,3 +1,4 @@
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
out vec4 FragColor;
@@ -5,8 +6,8 @@ void main()
{
vec3 N, T, B, V;
- float NV = (1.0 - (clamp(gl_FragCoord.y / BRDF_LUT_SIZE, 1e-4, 0.9999)));
- float sqrtRoughness = clamp(gl_FragCoord.x / BRDF_LUT_SIZE, 1e-4, 0.9999);
+ float NV = (1.0 - (clamp(gl_FragCoord.y / b, 1e-4, 0.9999)));
+ float sqrtRoughness = clamp(gl_FragCoord.x / LUT_SIZE, 1e-4, 0.9999);
float a = sqrtRoughness * sqrtRoughness;
float a2 = a * a;
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
index 5f2b719095e..066ea58e2bf 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -1,6 +1,7 @@
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+
uniform sampler1D texHammersley;
-uniform sampler2D texJitter;
uniform float sampleCount;
uniform float invSampleCount;
@@ -8,8 +9,7 @@ vec2 jitternoise = vec2(0.0);
#ifndef UTIL_TEX
# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+
#endif /* UTIL_TEX */
void setup_noise(void)
@@ -17,6 +17,11 @@ void setup_noise(void)
jitternoise = texelfetch_noise_tex(gl_FragCoord.xy).rg; /* Global variable */
}
+vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
+{
+ return T * vector.x + B * vector.y + N * vector.z;
+}
+
#ifdef HAMMERSLEY_SIZE
vec3 hammersley_3d(float i, float invsamplenbr)
{
diff --git a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
index 1389a9763c0..d815d9d4e6b 100644
--- a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
@@ -1,3 +1,4 @@
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
uniform float a2;
@@ -7,8 +8,8 @@ void main()
{
vec3 N, T, B, V;
- float x = gl_FragCoord.x / BRDF_LUT_SIZE;
- float y = gl_FragCoord.y / BRDF_LUT_SIZE;
+ float x = gl_FragCoord.x / LUT_SIZE;
+ float y = gl_FragCoord.y / LUT_SIZE;
/* There is little variation if ior > 1.0 so we
* maximize LUT precision for ior < 1.0 */
x = x * 1.1;
diff --git a/source/blender/draw/engines/eevee/shaders/closure_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_lib.glsl
new file mode 100644
index 00000000000..0be638f3cbb
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_lib.glsl
@@ -0,0 +1,181 @@
+
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
+
+#ifndef VOLUMETRICS
+
+uniform int outputSsrId = 1;
+uniform int outputSssId = 1;
+
+#endif
+
+struct Closure {
+#ifdef VOLUMETRICS
+ vec3 absorption;
+ vec3 scatter;
+ vec3 emission;
+ float anisotropy;
+
+#else /* SURFACE */
+ vec3 radiance;
+ vec3 transmittance;
+ float holdout;
+ vec4 ssr_data;
+ vec2 ssr_normal;
+ int flag;
+# ifdef USE_SSS
+ vec3 sss_irradiance;
+ vec3 sss_albedo;
+ float sss_radius;
+# endif
+
+#endif
+};
+
+/* Prototype */
+Closure nodetree_exec(void);
+
+/* clang-format off */
+/* Avoid multiline defines. */
+#ifdef VOLUMETRICS
+# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), vec3(0), 0.0)
+#elif !defined(USE_SSS)
+# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0, vec4(0), vec2(0), 0)
+#else
+# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0, vec4(0), vec2(0), 0, vec3(0), vec3(0), 0.0)
+#endif
+/* clang-format on */
+
+#define FLAG_TEST(flag, val) (((flag) & (val)) != 0)
+
+#define CLOSURE_SSR_FLAG 1
+#define CLOSURE_SSS_FLAG 2
+#define CLOSURE_HOLDOUT_FLAG 4
+
+#ifdef VOLUMETRICS
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
+ cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
+ cl.emission = mix(cl1.emission, cl2.emission, fac);
+ cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.absorption = cl1.absorption + cl2.absorption;
+ cl.scatter = cl1.scatter + cl2.scatter;
+ cl.emission = cl1.emission + cl2.emission;
+ cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
+ return cl;
+}
+
+Closure closure_emission(vec3 rgb)
+{
+ Closure cl = CLOSURE_DEFAULT;
+ cl.emission = rgb;
+ return cl;
+}
+
+#else /* SURFACE */
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.holdout = mix(cl1.holdout, cl2.holdout, fac);
+
+ if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) {
+ fac = 1.0;
+ }
+ else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) {
+ fac = 0.0;
+ }
+
+ cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac);
+ cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+ cl.flag = cl1.flag | cl2.flag;
+ cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac);
+ bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
+ /* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz).*/
+ cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
+ cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
+
+# ifdef USE_SSS
+ cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac);
+ bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
+ /* It also does not make sense to mix SSS radius or irradiance. */
+ cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
+ cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
+# endif
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.transmittance = cl1.transmittance + cl2.transmittance;
+ cl.radiance = cl1.radiance + cl2.radiance;
+ cl.holdout = cl1.holdout + cl2.holdout;
+ cl.flag = cl1.flag | cl2.flag;
+ cl.ssr_data = cl1.ssr_data + cl2.ssr_data;
+ bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
+ /* When mixing SSR don't blend roughness and normals.*/
+ cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
+ cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
+
+# ifdef USE_SSS
+ cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo;
+ bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
+ /* It also does not make sense to mix SSS radius or irradiance. */
+ cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
+ cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
+# endif
+ return cl;
+}
+
+Closure closure_emission(vec3 rgb)
+{
+ Closure cl = CLOSURE_DEFAULT;
+ cl.radiance = rgb;
+ return cl;
+}
+
+#endif
+
+#ifndef VOLUMETRICS
+
+void closure_load_ssr_data(
+ vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
+{
+ /* Still encode to avoid artifacts in the SSR pass. */
+ vec3 vN = normalize(mat3(ViewMatrix) * N);
+ cl.ssr_normal = normal_encode(vN, viewVec);
+
+ if (ssr_id == outputSsrId) {
+ cl.ssr_data = vec4(ssr_spec, roughness);
+ cl.flag |= CLOSURE_SSR_FLAG;
+ }
+}
+
+void closure_load_sss_data(
+ float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl)
+{
+# ifdef USE_SSS
+ if (sss_id == outputSssId) {
+ cl.sss_irradiance = sss_irradiance;
+ cl.sss_radius = radius;
+ cl.sss_albedo = sss_albedo;
+ cl.flag |= CLOSURE_SSS_FLAG;
+ cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0));
+ }
+ else
+# endif
+ {
+ cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo);
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
index bc7879763c3..bf33caf9854 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
@@ -1,32 +1,8 @@
-#ifndef LIT_SURFACE_UNIFORM
-# define LIT_SURFACE_UNIFORM
-
-uniform float refractionDepth;
-
-# ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-# endif /* UTIL_TEX */
-
-in vec3 worldPosition;
-in vec3 viewPosition;
-
-in vec3 worldNormal;
-in vec3 viewNormal;
-
-# ifdef HAIR_SHADER
-in vec3 hairTangent; /* world space */
-in float hairThickTime;
-in float hairThickness;
-in float hairTime;
-flat in int hairStrandID;
-
-uniform int hairThicknessRes = 1;
-# endif
-
-#endif /* LIT_SURFACE_UNIFORM */
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+#pragma BLENDER_REQUIRE(ssr_lib.glsl)
/**
* AUTO CONFIG
@@ -209,7 +185,7 @@ void CLOSURE_NAME(vec3 N
vec3 V = cameraVec;
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
/* ---------------------------------------------------------------- */
/* -------------------- SCENE LIGHTS LIGHTING --------------------- */
@@ -328,11 +304,11 @@ void CLOSURE_NAME(vec3 N
# endif
# ifdef CLOSURE_GLOSSY
- vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
+ vec3 spec_dir = specular_dominant_dir(N, V, roughnessSquared);
# endif
# ifdef CLOSURE_CLEARCOAT
- vec3 C_spec_dir = get_specular_reflection_dominant_dir(C_N, V, C_roughnessSquared);
+ vec3 C_spec_dir = specular_dominant_dir(C_N, V, C_roughnessSquared);
# endif
# ifdef CLOSURE_REFRACTION
@@ -345,7 +321,7 @@ void CLOSURE_NAME(vec3 N
line_plane_intersect(
worldPosition, refr_V, worldPosition - N * refractionDepth, N) :
worldPosition;
- vec3 refr_dir = get_specular_refraction_dominant_dir(N, refr_V, roughness, final_ior);
+ vec3 refr_dir = refraction_dominant_dir(N, refr_V, roughness, final_ior);
# endif
# ifdef CLOSURE_REFRACTION
@@ -485,7 +461,7 @@ void CLOSURE_NAME(vec3 N
# endif
# ifdef CLOSURE_REFRACTION
- float btdf = get_btdf_lut(utilTex, NV, roughness, ior);
+ float btdf = get_btdf_lut(NV, roughness, ior);
out_refr += refr_accum.rgb * btdf;
# endif
diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
index 759b4098b37..a6c9eebaff2 100644
--- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
@@ -2,7 +2,6 @@
layout(std140) uniform common_block
{
mat4 pastViewProjectionMatrix;
- vec4 viewVecs[2];
vec2 mipRatio[10]; /* To correct mip level texel misalignment */
/* Ambient Occlusion */
vec4 aoParameters[2];
@@ -70,3 +69,9 @@ layout(std140) uniform common_block
#define ssrQuality ssrParameters.x
#define ssrThickness ssrParameters.y
#define ssrPixelSize ssrParameters.zw
+
+vec2 mip_ratio_interp(float mip)
+{
+ float low_mip = floor(mip);
+ return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
new file mode 100644
index 00000000000..7e959026987
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
@@ -0,0 +1,65 @@
+
+#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
+
+/* ---------------------------------------------------------------------- */
+/** \name Utiltex
+ *
+ * Utiltex is a sampler2DArray that stores a number of useful small utilitary textures and lookup
+ * tables.
+ * \{ */
+
+uniform sampler2DArray utilTex;
+
+#define LUT_SIZE 64
+
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+
+/* Return texture coordinates to sample Surface LUT */
+vec2 lut_coords(float cosTheta, float roughness)
+{
+ float theta = acos(cosTheta);
+ vec2 coords = vec2(roughness, theta / M_PI_2);
+
+ /* scale and bias coordinates, for correct filtered lookup */
+ return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
+}
+
+vec2 lut_coords_ltc(float cosTheta, float roughness)
+{
+ vec2 coords = vec2(roughness, sqrt(1.0 - cosTheta));
+
+ /* scale and bias coordinates, for correct filtered lookup */
+ return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
+}
+
+float get_btdf_lut(float NV, float roughness, float ior)
+{
+ const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
+
+ vec3 coords;
+ /* Try to compensate for the low resolution and interpolation error. */
+ coords.x = (ior > 1.0) ? (0.9 + lut_scale_bias_texel_size.z) +
+ (0.1 - lut_scale_bias_texel_size.z) * f0_from_ior(ior) :
+ (0.9 + lut_scale_bias_texel_size.z) * ior * ior;
+ coords.y = 1.0 - saturate(NV);
+ coords.xy *= lut_scale_bias_texel_size.x;
+ coords.xy += lut_scale_bias_texel_size.y;
+
+ const float lut_lvl_ofs = 4.0; /* First texture lvl of roughness. */
+ const float lut_lvl_scale = 16.0; /* How many lvl of roughness in the lut. */
+
+ float mip = roughness * lut_lvl_scale;
+ float mip_floor = floor(mip);
+
+ coords.z = lut_lvl_ofs + mip_floor + 1.0;
+ float btdf_high = textureLod(utilTex, coords, 0.0).r;
+
+ coords.z -= 1.0;
+ float btdf_low = textureLod(utilTex, coords, 0.0).r;
+
+ float btdf = (ior == 1.0) ? 1.0 : mix(btdf_low, btdf_high, mip - coords.z);
+
+ return btdf;
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
deleted file mode 100644
index 1014b25033a..00000000000
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-
-uniform vec3 basecol;
-uniform float metallic;
-uniform float specular;
-uniform float roughness;
-
-Closure nodetree_exec(void)
-{
-#ifdef HAIR_SHADER
- vec3 B = normalize(cross(worldNormal, hairTangent));
- float cos_theta;
- if (hairThicknessRes == 1) {
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
- /* Random cosine normal distribution on the hair surface. */
- cos_theta = rand.x * 2.0 - 1.0;
- }
- else {
- /* Shade as a cylinder. */
- cos_theta = hairThickTime / hairThickness;
- }
- float sin_theta = sqrt(max(0.0, 1.0f - cos_theta * cos_theta));
- vec3 N = normalize(worldNormal * sin_theta + B * cos_theta);
- vec3 vN = mat3(ViewMatrix) * N;
-#else
- vec3 N = normalize(gl_FrontFacing ? worldNormal : -worldNormal);
- vec3 vN = normalize(gl_FrontFacing ? viewNormal : -viewNormal);
-#endif
-
- vec3 dielectric = vec3(0.034) * specular * 2.0;
- vec3 albedo = mix(basecol, vec3(0.0), metallic);
- vec3 f0 = mix(dielectric, basecol, metallic);
- vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
- vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec);
-
- Closure cl = CLOSURE_DEFAULT;
- cl.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) +
- render_pass_diffuse_mask(albedo, out_diff * albedo);
- closure_load_ssr_data(ssr_spec, roughness, N, viewCameraVec, 1, cl);
-
-#ifdef LOOKDEV
- gl_FragDepth = 0.0;
-#endif
-
-#ifdef HOLDOUT
- cl = CLOSURE_DEFAULT;
- cl.holdout = 1.0;
-#endif
-
- return cl;
-}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
index d56890769a7..9c1ca17f87c 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
@@ -1,4 +1,8 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform sampler2D colorBuffer;
uniform sampler2D depthBuffer;
@@ -18,9 +22,6 @@ uniform vec4 bokehParams[2];
uniform vec2 nearFar; /* Near & far view depths values */
-#define M_PI 3.1415926535897932384626433832795
-#define M_2PI 6.2831853071795864769252868
-
/* -------------- Utils ------------- */
/* divide by sensor size to get the normalized size */
@@ -34,11 +35,6 @@ uniform vec2 nearFar; /* Near & far view depths values */
#define weighted_sum(a, b, c, d, e) \
(a * e.x + b * e.y + c * e.z + d * e.w) / max(1e-6, dot(e, vec4(1.0)));
-float max_v4(vec4 v)
-{
- return max(max(v.x, v.y), max(v.z, v.w));
-}
-
vec4 safe_color(vec4 c)
{
/* Clamp to avoid black square artifacts if a pixel goes NaN. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
index d83b410125a..6e35d4a54ae 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform vec4 bokehParams[2];
#define bokeh_rotation bokehParams[0].x
@@ -15,8 +17,6 @@ flat out float smoothFac;
flat out ivec2 edge;
out vec2 particlecoord;
-#define M_PI 3.1415926535897932384626433832795
-
/* Scatter pass, calculate a triangle covering the CoC. */
void main()
{
diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
index eea0ce0aae2..47fe21928b3 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
@@ -1,14 +1,34 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+
/**
* This shader only compute maximum horizon angles for each directions.
* The final integration is done at the resolve stage with the shading normal.
*/
-uniform float rotationOffset;
-
out vec4 FragColor;
-#ifdef DEBUG_AO
uniform sampler2D normalBuffer;
+#ifdef LAYERED_DEPTH
+uniform sampler2DArray depthBufferLayered;
+uniform int layer;
+# define gtao_depthBuffer depthBufferLayered
+# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c)
+
+#else
+uniform sampler2D depthBuffer;
+# define gtao_depthBuffer depthBuffer
+# define gtao_textureLod(a, b, c) textureLod(a, b, c)
+
+#endif
+
+uniform float rotationOffset;
+
+#ifdef DEBUG_AO
void main()
{
@@ -34,18 +54,6 @@ void main()
#else
-# ifdef LAYERED_DEPTH
-uniform sampler2DArray depthBufferLayered;
-uniform int layer;
-# define gtao_depthBuffer depthBufferLayered
-# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c)
-
-# else
-# define gtao_depthBuffer depthBuffer
-# define gtao_textureLod(a, b, c) textureLod(a, b, c)
-
-# endif
-
void main()
{
vec2 uvs = saturate(gl_FragCoord.xy / vec2(textureSize(gtao_depthBuffer, 0).xy));
diff --git a/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl
index edee55a07e0..7331f92ba6d 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl
@@ -1,5 +1,10 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
/* Convert depth to Mist factor */
uniform vec3 mistSettings;
+uniform sampler2D depthBuffer;
#define mistStart mistSettings.x
#define mistInvDistance mistSettings.y
diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
index fbf507a2e40..3501a4448c5 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+
/*
* Based on:
* A Fast and Stable Feature-Aware Motion Blur Filter
@@ -15,11 +17,6 @@ uniform sampler2D tileMaxBuffer;
#define KERNEL 8
-/* TODO(fclem) deduplicate this code. */
-uniform sampler2DArray utilTex;
-#define LUT_SIZE 64
-#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-
uniform float depthScale;
uniform ivec2 tileBufferSize;
uniform vec2 viewportSize;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index 598cc3e5183..f8dccb7511a 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -1,4 +1,11 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ssr_lib.glsl)
+
/* Based on Stochastic Screen Space Reflections
* https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */
@@ -131,7 +138,7 @@ void main()
return;
}
- vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0);
+ vec4 rand = texelfetch_noise_tex(halfres_texel);
/* Gives *perfect* reflection for very small roughness */
if (roughness < 0.04) {
diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
index e9da49c9eb9..2a53a4f119f 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -1,4 +1,9 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+
/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
#define MAX_SSS_SAMPLES 65
@@ -14,36 +19,16 @@ uniform sampler2D sssIrradiance;
uniform sampler2D sssRadius;
uniform sampler2D sssAlbedo;
-#ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-#endif /* UTIL_TEX */
-
layout(location = 0) out vec4 sssRadiance;
-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;
- }
-}
-
-#define LUT_SIZE 64
-#define M_PI_2 1.5707963267948966 /* pi/2 */
-#define M_2PI 6.2831853071795865 /* 2*pi */
-
void main(void)
{
vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */
vec2 uvs = gl_FragCoord.xy * pixel_size;
vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb;
float sss_radius = texture(sssRadius, uvs).r;
- float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r);
+ float depth = texture(depthBuffer, uvs).r;
+ float depth_view = get_view_z_from_depth(depth);
float rand = texelfetch_noise_tex(gl_FragCoord.xy).r;
#ifdef FIRST_PASS
diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
index b44645174bd..28947e971d2 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
@@ -1,5 +1,11 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+uniform sampler2D colorBuffer;
+uniform sampler2D depthBuffer;
uniform sampler2D colorHistoryBuffer;
+
uniform mat4 prevViewProjectionMatrix;
out vec4 FragColor;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
index 6531ceb8dbe..c85eff92e37 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
@@ -1,11 +1,16 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+
in vec4 uvcoordsvar;
out vec4 FragColor;
+uniform sampler2D depthBuffer;
uniform sampler1D sssTexProfile;
uniform sampler2D sssRadius;
-
uniform sampler2DArray sssShadowCubes;
uniform sampler2DArray sssShadowCascades;
@@ -27,12 +32,6 @@ vec3 sss_profile(float s)
return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
}
-#ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-#endif /* UTIL_TEX */
-
float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
{
float power, falloff;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl
index d927fd78d30..145939cefb2 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl
@@ -1,4 +1,8 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
+uniform sampler2D depthBuffer;
+
uniform mat4 prevViewProjMatrix;
uniform mat4 currViewProjMatrixInv;
uniform mat4 nextViewProjMatrix;
diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
index 64ea87001f4..2274bf8b950 100644
--- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
@@ -1,18 +1,71 @@
-uniform sampler2DArray irradianceGrid;
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+#pragma BLENDER_REQUIRE(octahedron_lib.glsl)
#define IRRADIANCE_LIB
+/* ---------------------------------------------------------------------- */
+/** \name Structure
+ * \{ */
+
#if defined(IRRADIANCE_SH_L2)
struct IrradianceData {
vec3 shcoefs[9];
};
+
#else /* defined(IRRADIANCE_HL2) */
struct IrradianceData {
vec3 cubesides[3];
};
+
#endif
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Resources
+ * \{ */
+
+uniform sampler2DArray irradianceGrid;
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Functions
+ * \{ */
+
+vec4 irradiance_encode(vec3 rgb)
+{
+ float maxRGB = max_v3(rgb);
+ float fexp = ceil(log2(maxRGB));
+ return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
+}
+
+vec3 irradiance_decode(vec4 data)
+{
+ float fexp = data.a * 255.0 - 128.0;
+ return data.rgb * exp2(fexp);
+}
+
+vec4 visibility_encode(vec2 accum, float range)
+{
+ accum /= range;
+
+ vec4 data;
+ data.x = fract(accum.x);
+ data.y = floor(accum.x) / 255.0;
+ data.z = fract(accum.y);
+ data.w = floor(accum.y) / 255.0;
+
+ return data;
+}
+
+vec2 visibility_decode(vec4 data, float range)
+{
+ return (data.xz + data.yw * 255.0) * range;
+}
+
IrradianceData load_irradiance_cell(int cell, vec3 N)
{
/* Keep in sync with diffuse_filter_probe() */
@@ -155,3 +208,5 @@ vec3 irradiance_from_cell_get(int cell, vec3 ir_dir)
IrradianceData ir_data = load_irradiance_cell(cell, ir_dir);
return compute_irradiance(ir_dir, ir_data);
}
+
+/** \} */
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 96fe94fc41e..a12069dc57b 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
@@ -1,4 +1,7 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(cubemap_lib.glsl)
+
flat in int pid;
in vec2 quadCoord;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
index db780714091..d06ad553ca4 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
/* XXX TODO fix code duplication */
struct CubeData {
vec4 position_type;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
index b485511318b..bf45169ebaa 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -1,4 +1,8 @@
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(irradiance_lib.glsl)
+
uniform samplerCube probeHdr;
uniform int probeSize;
uniform float lodFactor;
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 00eb3c7e200..ccb77427ed2 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
@@ -1,4 +1,7 @@
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+
uniform samplerCube probeHdr;
uniform float roughnessSquared;
uniform float texelSize;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
index 5d8af21032a..8d7c58a93d5 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
@@ -1,4 +1,8 @@
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
+#pragma BLENDER_REQUIRE(irradiance_lib.glsl)
+
uniform samplerCube probeDepth;
uniform int outputSize;
uniform float lodFactor;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
index f8bc1703c66..009ccf6535e 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
@@ -40,9 +40,6 @@ void main()
for (int v = 0; v < 3; v++) {
gl_Position = vPos[v];
worldPosition = x_axis[fFace] * vPos[v].x + y_axis[fFace] * vPos[v].y + maj_axes[fFace];
-#ifdef USE_ATTR
- pass_attr(v);
-#endif
EmitVertex();
}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
index 4e500db827e..6fefe1319bd 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
uniform float sphere_size;
uniform int offset;
uniform ivec3 grid_resolution;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 6c6db88139b..a2e25b83532 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -1,3 +1,12 @@
+
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+#pragma BLENDER_REQUIRE(cubemap_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+#pragma BLENDER_REQUIRE(irradiance_lib.glsl)
+
/* ----------- Uniforms --------- */
uniform sampler2DArray probePlanars;
@@ -73,12 +82,6 @@ struct GridData {
# define MAX_PLANAR 1
#endif
-#ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-#endif /* UTIL_TEX */
-
layout(std140) uniform probe_block
{
CubeData probes_data[MAX_PROBE];
@@ -218,7 +221,7 @@ void fallback_cubemap(vec3 N,
inout vec4 spec_accum)
{
/* Specular probes */
- vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
+ vec3 spec_dir = specular_dominant_dir(N, V, roughnessSquared);
#ifdef SSR_AO
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
@@ -246,7 +249,6 @@ void fallback_cubemap(vec3 N,
}
}
-#ifdef IRRADIANCE_LIB
vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
{
localpos = localpos * 0.5 + 0.5;
@@ -308,5 +310,3 @@ vec3 probe_evaluate_world_diff(vec3 N)
{
return irradiance_from_cell_get(0, N);
}
-
-#endif /* IRRADIANCE_LIB */
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
index 2807488db6c..0a53abcb04a 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
uniform sampler2DArray probePlanars;
in vec3 worldPosition;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
index 65506e5c7b1..6759c060259 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
in vec3 pos;
in int probe_id;
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index 3b9d0a8f2bc..949e4d8f04f 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -1,8 +1,76 @@
-uniform sampler2DArrayShadow shadowCubeTexture;
-uniform sampler2DArrayShadow shadowCascadeTexture;
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
+#pragma BLENDER_REQUIRE(ltc_lib.glsl)
+
+#ifndef MAX_CASCADE_NUM
+# define MAX_CASCADE_NUM 4
+#endif
+
+/* ---------------------------------------------------------------------- */
+/** \name Structure
+ * \{ */
+
+struct LightData {
+ vec4 position_influence; /* w : InfluenceRadius (inversed and squared) */
+ vec4 color_spec; /* w : Spec Intensity */
+ vec4 spotdata_radius_shadow; /* x : spot size, y : spot blend, z : radius, w: shadow id */
+ vec4 rightvec_sizex; /* xyz: Normalized up vector, w: area size X or spot scale X */
+ vec4 upvec_sizey; /* xyz: Normalized right vector, w: area size Y or spot scale Y */
+ vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Light Type */
+};
+
+/* convenience aliases */
+#define l_color color_spec.rgb
+#define l_spec color_spec.a
+#define l_position position_influence.xyz
+#define l_influence position_influence.w
+#define l_sizex rightvec_sizex.w
+#define l_sizey upvec_sizey.w
+#define l_right rightvec_sizex.xyz
+#define l_up upvec_sizey.xyz
+#define l_forward forwardvec_type.xyz
+#define l_type forwardvec_type.w
+#define l_spot_size spotdata_radius_shadow.x
+#define l_spot_blend spotdata_radius_shadow.y
+#define l_radius spotdata_radius_shadow.z
+#define l_shadowid spotdata_radius_shadow.w
+
+struct ShadowData {
+ vec4 near_far_bias_id;
+ vec4 contact_shadow_data;
+};
+
+struct ShadowCubeData {
+ mat4 shadowmat;
+ vec4 position;
+};
+
+struct ShadowCascadeData {
+ mat4 shadowmat[MAX_CASCADE_NUM];
+ vec4 split_start_distances;
+ vec4 split_end_distances;
+ vec4 shadow_vec_id;
+};
+
+/* convenience aliases */
+#define sh_near near_far_bias_id.x
+#define sh_far near_far_bias_id.y
+#define sh_bias near_far_bias_id.z
+#define sh_data_index near_far_bias_id.w
+#define sh_contact_dist contact_shadow_data.x
+#define sh_contact_offset contact_shadow_data.y
+#define sh_contact_spread contact_shadow_data.z
+#define sh_contact_thickness contact_shadow_data.w
+#define sh_shadow_vec shadow_vec_id.xyz
+#define sh_tex_index shadow_vec_id.w
+
+/** \} */
-#define LAMPS_LIB
+/* ---------------------------------------------------------------------- */
+/** \name Resources
+ * \{ */
layout(std140) uniform shadow_block
{
@@ -16,6 +84,15 @@ layout(std140) uniform light_block
LightData lights_data[MAX_LIGHT];
};
+uniform sampler2DArrayShadow shadowCubeTexture;
+uniform sampler2DArrayShadow shadowCascadeTexture;
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Shadow Functions
+ * \{ */
+
/* type */
#define POINT 0.0
#define SUN 1.0
@@ -133,9 +210,11 @@ float sample_cascade_shadow(int shadow_id, vec3 W)
#undef scube
#undef scsmd
-/* ----------------------------------------------------------- */
-/* --------------------- Light Functions --------------------- */
-/* ----------------------------------------------------------- */
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Light Functions
+ * \{ */
/* From Frostbite PBR Course
* Distance based attenuation
@@ -258,7 +337,6 @@ float light_visibility(LightData ld,
l_atten);
}
-#ifdef USE_LTC
float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
{
if (ld.l_type == AREA_RECT) {
@@ -321,4 +399,5 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
return ltc_evaluate_disk(N, V, ltc_matrix(ltc_mat), points);
}
}
-#endif
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl b/source/blender/draw/engines/eevee/shaders/lookdev_world_frag.glsl
index 8c876cf582c..9077b414026 100644
--- a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lookdev_world_frag.glsl
@@ -1,20 +1,17 @@
-uniform float backgroundAlpha;
-uniform vec3 color;
-
-out vec4 FragColor;
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
-#if defined(LOOKDEV_BG) || defined(LOOKDEV)
+uniform sampler2D studioLight;
+uniform float backgroundAlpha;
uniform mat3 StudioLightMatrix;
-uniform sampler2D image;
uniform float studioLightIntensity = 1.0;
uniform float studioLightBlur = 0.0;
-in vec3 viewPosition;
-# ifndef M_PI
-# define M_PI 3.14159265358979323846
-# endif
+out vec4 FragColor;
vec3 background_transform_to_world(vec3 viewvec)
{
@@ -35,36 +32,20 @@ vec4 node_tex_environment_equirectangular(vec3 co, sampler2D ima)
vec3 nco = normalize(co);
float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
-
- /* Fix pole bleeding */
- float width = float(textureSize(ima, 0).x);
- float texel_width = 1.0 / width;
- v = clamp(v, texel_width, 1.0 - texel_width);
-
- /* Fix u = 0 seam */
- /* This is caused by texture filtering, since uv don't have smooth derivatives
- * at u = 0 or 2PI, hardware filtering is using the smallest mipmap for certain
- * texels. So we force the highest mipmap and don't do anisotropic filtering. */
return textureLod(ima, vec2(u, v), 0.0);
}
-#endif
void main()
{
- vec3 background_color;
+ vec3 worldvec = background_transform_to_world(viewPosition);
+ vec3 background_color;
#if defined(LOOKDEV_BG)
- vec3 worldvec = background_transform_to_world(viewPosition);
background_color = probe_evaluate_world_spec(worldvec, studioLightBlur).rgb;
- background_color *= studioLightIntensity;
-
-#elif defined(LOOKDEV)
- vec3 worldvec = background_transform_to_world(viewPosition);
- background_color = node_tex_environment_equirectangular(StudioLightMatrix * worldvec, image).rgb;
- background_color *= studioLightIntensity;
-
#else
- background_color = color;
+ worldvec = StudioLightMatrix * worldvec;
+ background_color = node_tex_environment_equirectangular(worldvec, studioLight).rgb;
+ background_color *= studioLightIntensity;
#endif
FragColor = vec4(clamp(background_color, vec3(0.0), vec3(1e10)), 1.0) * backgroundAlpha;
diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
index dbfc7ad5a71..2750d42a74a 100644
--- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
@@ -8,12 +8,6 @@
#define USE_LTC
-#ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-#endif /* UTIL_TEX */
-
/* Diffuse *clipped* sphere integral. */
float diffuse_sphere_integral(float avg_dir_z, float form_factor)
{
diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl
index 95cd69ba310..ef96bcbaedb 100644
--- a/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl
@@ -1,4 +1,7 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+
uniform mat4 currModelMatrix;
uniform mat4 prevModelMatrix;
uniform mat4 nextModelMatrix;
@@ -19,6 +22,8 @@ out vec3 nextWorldPos;
void main()
{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
#ifdef HAIR
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
float time, thick_time, thickness;
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index 9acd8f998f6..34999076f9c 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -1,4 +1,14 @@
+/* Required by some nodes. */
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+
#ifdef USE_ALPHA_HASH
/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire */
@@ -56,8 +66,6 @@ float hashed_alpha_threshold(vec3 co)
#endif
-#define NODETREE_EXEC
-
void main()
{
#if defined(USE_ALPHA_HASH)
@@ -66,11 +74,9 @@ void main()
float opacity = saturate(1.0 - avg(cl.transmittance));
-# if defined(USE_ALPHA_HASH)
/* Hashed Alpha Testing */
if (opacity < hashed_alpha_threshold(worldPosition)) {
discard;
}
-# endif
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
index 2c7e0aca3fb..f650e2eeb8c 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
@@ -1,16 +1,14 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
#ifndef HAIR_SHADER
in vec3 pos;
#endif
void main()
{
-#ifdef GPU_INTEL
- /* Due to some shader compiler bug, we somewhat
- * need to access gl_VertexID to make it work. even
- * if it's actually dead code. */
- gl_Position.x = float(gl_VertexID);
-#endif
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
#ifdef HAIR_SHADER
float time, thick_time, thickness;
@@ -34,5 +32,4 @@ void main()
#ifdef CLIP_PLANES
gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), clipPlanes[0]);
#endif
- /* TODO motion vectors */
}
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index f88cfdf3787..39db39f8756 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -1,3 +1,11 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+
+uniform sampler2D maxzBuffer;
+uniform sampler2DArray planarDepth;
+
#define MAX_STEP 256
float sample_depth(vec2 uv, int index, float lod)
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
new file mode 100644
index 00000000000..36cf3cecf40
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
@@ -0,0 +1,43 @@
+
+/* ---------------------------------------------------------------------- */
+/** \name Resources
+ * \{ */
+
+layout(std140) uniform renderpass_block
+{
+ bool renderPassDiffuse;
+ bool renderPassDiffuseLight;
+ bool renderPassGlossy;
+ bool renderPassGlossyLight;
+ bool renderPassEmit;
+ bool renderPassSSSColor;
+ bool renderPassEnvironment;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Functions
+ * \{ */
+
+vec3 render_pass_diffuse_mask(vec3 diffuse_color, vec3 diffuse_light)
+{
+ return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : diffuse_color) : vec3(0.0);
+}
+
+vec3 render_pass_sss_mask(vec3 sss_color)
+{
+ return renderPassSSSColor ? sss_color : vec3(0.0);
+}
+
+vec3 render_pass_glossy_mask(vec3 specular_color, vec3 specular_light)
+{
+ return renderPassGlossy ? (renderPassGlossyLight ? specular_light : specular_color) : vec3(0.0);
+}
+
+vec3 render_pass_emission_mask(vec3 emission_light)
+{
+ return renderPassEmit ? emission_light : vec3(0.0);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
index 361963d5ac3..89a411bc7cb 100644
--- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
@@ -1,3 +1,7 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+
#define PASS_POST_UNDEFINED 0
#define PASS_POST_ACCUMULATED_COLOR 1
#define PASS_POST_ACCUMULATED_LIGHT 2
@@ -9,6 +13,8 @@
uniform int postProcessType;
uniform int currentSample;
+
+uniform sampler2D depthBuffer;
uniform sampler2D inputBuffer;
uniform sampler2D inputSecondLightBuffer;
uniform sampler2D inputColorBuffer;
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
index 860ec9e1727..e0b9d4a60db 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
@@ -1,11 +1,11 @@
-out vec4 fragColor;
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+
+uniform sampler2D depthBuffer;
-#ifndef UTIL_TEX
-# define UTIL_TEX
-uniform sampler2DArray utilTex;
-# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
-#endif /* UTIL_TEX */
+out vec4 fragColor;
void main()
{
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index c42f905cf7e..0e342938396 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -1,39 +1,23 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+
in vec3 pos;
in vec3 nor;
-#ifdef MESH_SHADER
-out vec3 worldPosition;
-out vec3 viewPosition;
-out vec3 worldNormal;
-out vec3 viewNormal;
-#endif
-
-#ifdef HAIR_SHADER
-out vec3 hairTangent;
-out float hairThickTime;
-out float hairThickness;
-out float hairTime;
-flat out int hairStrandID;
-#endif
-
void main()
{
-#ifdef GPU_INTEL
- /* Due to some shader compiler bug, we somewhat
- * need to access gl_VertexID to make it work. even
- * if it's actually dead code. */
- gl_Position.x = float(gl_VertexID);
-#endif
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
#ifdef HAIR_SHADER
hairStrandID = hair_get_strand_id();
- vec3 world_pos, binor;
+ vec3 pos, binor;
hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
ModelMatrixInverse,
ViewMatrixInverse[3].xyz,
ViewMatrixInverse[2].xyz,
- world_pos,
+ pos,
hairTangent,
binor,
hairTime,
@@ -41,6 +25,7 @@ void main()
hairThickTime);
worldNormal = cross(hairTangent, binor);
+ vec3 world_pos = pos;
#else
vec3 world_pos = point_object_to_world(pos);
#endif
@@ -57,7 +42,10 @@ void main()
/* No need to normalize since this is just a rotation. */
viewNormal = normal_world_to_view(worldNormal);
# ifdef USE_ATTR
- pass_attr(pos);
+# ifdef HAIR_SHADER
+ pos = hair_get_strand_pos();
+# endif
+ pass_attr(pos, NormalMatrix, ModelMatrixInverse);
# endif
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
index 0591b247541..29495e98355 100644
--- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
@@ -1,3 +1,10 @@
+
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
+#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
+#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+
/* ------------ Refraction ------------ */
#define BTDF_BIAS 0.85
diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
new file mode 100644
index 00000000000..e746acfdfa3
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
@@ -0,0 +1,89 @@
+
+/* Required by some nodes. */
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+
+#pragma BLENDER_REQUIRE(closure_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
+
+#ifdef USE_ALPHA_BLEND
+/* Use dual source blending to be able to make a whole range of effects. */
+layout(location = 0, index = 0) out vec4 outRadiance;
+layout(location = 0, index = 1) out vec4 outTransmittance;
+
+#else /* OPAQUE */
+layout(location = 0) out vec4 outRadiance;
+layout(location = 1) out vec2 ssrNormals;
+layout(location = 2) out vec4 ssrData;
+# ifdef USE_SSS
+layout(location = 3) out vec3 sssIrradiance;
+layout(location = 4) out float sssRadius;
+layout(location = 5) out vec3 sssAlbedo;
+# endif
+
+#endif
+
+void main()
+{
+ Closure cl = nodetree_exec();
+
+ float holdout = saturate(1.0 - cl.holdout);
+ float transmit = saturate(avg(cl.transmittance));
+ float alpha = 1.0 - transmit;
+
+#ifdef USE_ALPHA_BLEND
+ vec2 uvs = gl_FragCoord.xy * volCoordScale.zw;
+ vec3 vol_transmit, vol_scatter;
+ volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
+
+ /* Removes part of the volume scattering that have
+ * already been added to the destination pixels.
+ * Since we do that using the blending pipeline we need to account for material transmittance. */
+ vol_scatter -= vol_scatter * cl.transmittance;
+
+ cl.radiance = cl.radiance * holdout * vol_transmit + vol_scatter;
+ outRadiance = vec4(cl.radiance, alpha * holdout);
+ outTransmittance = vec4(cl.transmittance, transmit) * holdout;
+#else
+ outRadiance = vec4(cl.radiance, holdout);
+ ssrNormals = cl.ssr_normal;
+ ssrData = cl.ssr_data;
+# ifdef USE_SSS
+ sssIrradiance = cl.sss_irradiance;
+ sssRadius = cl.sss_radius;
+ sssAlbedo = cl.sss_albedo;
+# endif
+#endif
+
+ /* For Probe capture */
+#ifdef USE_SSS
+ float fac = float(!sssToggle);
+
+ /* TODO(fclem) we shouldn't need this.
+ * Just disable USE_SSS when USE_REFRACTION is enabled. */
+# ifdef USE_REFRACTION
+ /* SSRefraction pass is done after the SSS pass.
+ * In order to not loose the diffuse light totally we
+ * need to merge the SSS radiance to the main radiance. */
+ fac = 1.0;
+# endif
+
+ outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
+#endif
+
+#ifndef USE_ALPHA_BLEND
+ float alpha_div = 1.0 / max(1e-8, alpha);
+ outRadiance.rgb *= alpha_div;
+ ssrData.rgb *= alpha_div;
+# ifdef USE_SSS
+ sssAlbedo.rgb *= alpha_div;
+# endif
+#endif
+
+#ifdef LOOKDEV
+ /* Lookdev spheres are rendered in front. */
+ gl_FragDepth = 0.0;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_geom.glsl b/source/blender/draw/engines/eevee/shaders/surface_geom.glsl
new file mode 100644
index 00000000000..ad437dca79a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/surface_geom.glsl
@@ -0,0 +1,46 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices = 3) out;
+
+RESOURCE_ID_VARYING
+
+/* Only used to compute barycentric coordinates. */
+
+void main()
+{
+#ifdef DO_BARYCENTRIC_DISTANCES
+ dataAttrOut.barycentricDist = calc_barycentric_distances(
+ dataIn[0].worldPosition, dataIn[1].worldPosition, dataIn[2].worldPosition);
+#endif
+
+ PASS_RESOURCE_ID
+
+#ifdef USE_ATTR
+ pass_attr(0);
+#endif
+ PASS_SURFACE_INTERFACE(0);
+ gl_Position = gl_in[0].gl_Position;
+ gl_ClipDistance[0] = gl_in[0].gl_ClipDistance[0];
+ EmitVertex();
+
+#ifdef USE_ATTR
+ pass_attr(1);
+#endif
+ PASS_SURFACE_INTERFACE(1);
+ gl_Position = gl_in[1].gl_Position;
+ gl_ClipDistance[0] = gl_in[1].gl_ClipDistance[0];
+ EmitVertex();
+
+#ifdef USE_ATTR
+ pass_attr(2);
+#endif
+ PASS_SURFACE_INTERFACE(2);
+ gl_Position = gl_in[2].gl_Position;
+ gl_ClipDistance[0] = gl_in[2].gl_ClipDistance[0];
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
new file mode 100644
index 00000000000..b93a3a23eff
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -0,0 +1,43 @@
+/** This describe the entire interface of the shader. */
+
+/* Samplers */
+uniform sampler2D colorBuffer;
+uniform sampler2D depthBuffer;
+
+/* Uniforms */
+uniform float refractionDepth;
+
+#define SURFACE_INTERFACE \
+ vec3 worldPosition; \
+ vec3 viewPosition; \
+ vec3 worldNormal; \
+ vec3 viewNormal;
+
+#ifdef GPU_GEOMETRY_SHADER
+in ShaderStageInterface{SURFACE_INTERFACE} dataIn[];
+
+out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
+
+# define PASS_SURFACE_INTERFACE(vert) \
+ dataOut.worldPosition = dataIn[vert].worldPosition; \
+ dataOut.viewPosition = dataIn[vert].viewPosition; \
+ dataOut.worldNormal = dataIn[vert].worldNormal; \
+ dataOut.viewNormal = dataIn[vert].viewNormal;
+
+#else
+
+IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
+
+#endif
+
+#ifdef HAIR_SHADER
+IN_OUT ShaderHairInterface
+{
+ /* world space */
+ vec3 hairTangent;
+ float hairThickTime;
+ float hairThickness;
+ float hairTime;
+ flat int hairStrandID;
+};
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 1b94fc2bee1..0ad1393dd70 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -1,32 +1,20 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(surface_lib.glsl)
+
#ifndef HAIR_SHADER
in vec3 pos;
in vec3 nor;
#endif
-#ifdef MESH_SHADER
-out vec3 worldPosition;
-out vec3 viewPosition;
-out vec3 worldNormal;
-out vec3 viewNormal;
-#endif
-
-#ifdef HAIR_SHADER
-out vec3 hairTangent;
-out float hairThickTime;
-out float hairThickness;
-out float hairTime;
-flat out int hairStrandID;
-#endif
+RESOURCE_ID_VARYING
void main()
{
-#ifdef GPU_INTEL
- /* Due to some shader compiler bug, we somewhat
- * need to access gl_VertexID to make it work. even
- * if it's actually dead code. */
- gl_Position.x = float(gl_VertexID);
-#endif
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ PASS_RESOURCE_ID
#ifdef HAIR_SHADER
hairStrandID = hair_get_strand_id();
@@ -63,7 +51,10 @@ void main()
/* No need to normalize since this is just a rotation. */
viewNormal = normal_world_to_view(worldNormal);
# ifdef USE_ATTR
- pass_attr(pos);
+# ifdef HAIR_SHADER
+ pos = hair_get_strand_pos();
+# endif
+ pass_attr(pos, NormalMatrix, ModelMatrixInverse);
# endif
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
index 02ad2170f06..0c01c46c2ba 100644
--- a/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
@@ -1,11 +1,11 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform sampler2D blueNoise;
uniform vec3 offsets;
out vec4 FragColor;
-#define M_2PI 6.28318530717958647692
-
void main(void)
{
vec3 blue_noise = texelFetch(blueNoise, ivec2(gl_FragCoord.xy), 0).xyz;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index 312fc07054a..bac69ab0355 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -1,9 +1,10 @@
+#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_lib.glsl)
+
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
-#define NODETREE_EXEC
-
#ifdef MESH_SHADER
uniform vec3 volumeOrcoLoc;
uniform vec3 volumeOrcoSize;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
index 96b891c929f..30cda401284 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
#ifdef MESH_SHADER
/* TODO tight slices */
layout(triangles) in;
@@ -12,12 +14,16 @@ in vec4 vPos[];
flat out int slice;
+RESOURCE_ID_VARYING
+
#ifdef MESH_SHADER
/* TODO tight slices */
void main()
{
gl_Layer = slice = int(vPos[0].z);
+ PASS_RESOURCE_ID
+
# ifdef USE_ATTR
pass_attr(0);
# endif
@@ -48,6 +54,8 @@ void main()
{
gl_Layer = slice = int(vPos[0].z);
+ PASS_RESOURCE_ID
+
# ifdef USE_ATTR
pass_attr(0);
# endif
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index c3c442e7b69..f4276bd61bd 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
+
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
@@ -11,9 +13,11 @@ uniform sampler3D volumeExtinction;
#ifdef USE_VOLUME_OPTI
uniform layout(binding = 0, r11f_g11f_b10f) writeonly restrict image3D finalScattering_img;
uniform layout(binding = 1, r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img;
+
vec3 finalScattering;
vec3 finalTransmittance;
#else
+
flat in int slice;
layout(location = 0) out vec3 finalScattering;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
index 40eb3da42d1..9b852a57ec4 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
@@ -1,4 +1,8 @@
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(irradiance_lib.glsl)
+
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
@@ -58,7 +62,6 @@ float phase_function(vec3 v, vec3 l, float g)
return (1 - sqr_g) / max(1e-8, 4.0 * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0 / 2.0));
}
-#ifdef LAMPS_LIB
vec3 light_volume(LightData ld, vec4 l_vector)
{
float power;
@@ -95,7 +98,7 @@ vec3 light_volume(LightData ld, vec4 l_vector)
return tint * lum;
}
-# define VOLUMETRIC_SHADOW_MAX_STEP 32.0
+#define VOLUMETRIC_SHADOW_MAX_STEP 32.0
vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction)
{
@@ -109,7 +112,7 @@ vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction)
vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D volume_extinction)
{
-# if defined(VOLUME_SHADOW)
+#if defined(VOLUME_SHADOW)
/* Heterogeneous volume shadows */
float dd = l_vector.w / volShadowSteps;
vec3 L = l_vector.xyz * l_vector.w;
@@ -120,27 +123,24 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v
shadow *= exp(-s_extinction * dd);
}
return shadow;
-# else
+#else
return vec3(1.0);
-# endif /* VOLUME_SHADOW */
+#endif /* VOLUME_SHADOW */
}
-#endif
-#ifdef IRRADIANCE_LIB
vec3 irradiance_volumetric(vec3 wpos)
{
-# ifdef IRRADIANCE_HL2
+#ifdef IRRADIANCE_HL2
IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0));
vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
ir_data = load_irradiance_cell(0, vec3(-1.0));
irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
irradiance *= 0.16666666; /* 1/6 */
return irradiance;
-# else
+#else
return vec3(0.0);
-# endif
-}
#endif
+}
uniform sampler3D inScattering;
uniform sampler3D inTransmittance;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl
index 1ff7e848c40..6ab21587c9a 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
+
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
index 9621fa1cc0d..806f1b5b205 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
+
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index b96360febb0..b70747ecec3 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -1,6 +1,10 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
out vec4 vPos;
+RESOURCE_ID_VARYING
+
void main()
{
/* Generate Triangle : less memory fetches from a VBO */
@@ -25,7 +29,9 @@ void main()
vPos.z = float(t_id);
vPos.w = 1.0;
+ PASS_RESOURCE_ID
+
#ifdef USE_ATTR
- pass_attr(vec3(0.0));
+ pass_attr(vec3(0.0), mat3(1), mat4(1));
#endif
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 6e6b35e19ca..ed443b2c73f 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -63,7 +63,7 @@ static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf != NULL && ibuf->rect != NULL) {
- gpu_tex = GPU_texture_from_blender(image, &iuser, ibuf, GL_TEXTURE_2D);
+ gpu_tex = BKE_image_get_gpu_texture(image, &iuser, ibuf);
*r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
}
BKE_image_release_ibuf(image, ibuf, lock);
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 47f05eda58e..1e766b3cc39 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -53,8 +53,6 @@
#include "ED_view3d.h"
-#include "GPU_draw.h"
-
#include "overlay_private.h"
#include "draw_common.h"
@@ -1339,7 +1337,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
else {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag && (1 << 0))) {
+ if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) {
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1422,7 +1420,7 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
line_count /= fds->res[axis];
}
- GPU_create_smoke_velocity(fmd);
+ DRW_smoke_ensure_velocity(fmd);
GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle);
DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]);
@@ -1452,7 +1450,7 @@ static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data)
LinkData *link;
while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) {
FluidModifierData *fmd = (FluidModifierData *)link->data;
- GPU_free_smoke_velocity(fmd);
+ DRW_smoke_free_velocity(fmd);
MEM_freeN(link);
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
index 67132a9e0ed..d456e147c15 100644
--- a/source/blender/draw/engines/overlay/overlay_image.c
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -175,7 +175,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
}
width = ibuf->x;
height = ibuf->y;
- tex = GPU_texture_from_blender(image, iuser, ibuf, GL_TEXTURE_2D);
+ tex = BKE_image_get_gpu_texture(image, iuser, ibuf);
BKE_image_release_ibuf(image, ibuf, lock);
iuser->scene = NULL;
@@ -203,7 +203,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
}
BKE_movieclip_user_set_frame(&bgpic->cuser, ctime);
- tex = GPU_texture_from_movieclip(clip, &bgpic->cuser, GL_TEXTURE_2D);
+ tex = BKE_movieclip_get_gpu_texture(clip, &bgpic->cuser);
if (tex == NULL) {
return NULL;
}
@@ -232,7 +232,7 @@ static void OVERLAY_image_free_movieclips_textures(OVERLAY_Data *data)
LinkData *link;
while ((link = BLI_pophead(&data->stl->pd->bg_movie_clips))) {
MovieClip *clip = (MovieClip *)link->data;
- GPU_free_texture_movieclip(clip);
+ BKE_movieclip_free_gputexture(clip);
MEM_freeN(link);
}
}
@@ -383,7 +383,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (ima != NULL) {
ImageUser iuser = *ob->iuser;
camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser);
- tex = GPU_texture_from_blender(ima, &iuser, NULL, GL_TEXTURE_2D);
+ tex = BKE_image_get_gpu_texture(ima, &iuser, NULL);
if (tex) {
size[0] = GPU_texture_orig_width(tex);
size[1] = GPU_texture_orig_height(tex);
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
index e94cc820568..25b8a953ba7 100644
--- a/source/blender/draw/engines/overlay/overlay_paint.c
+++ b/source/blender/draw/engines/overlay/overlay_paint.c
@@ -22,6 +22,8 @@
#include "DRW_render.h"
+#include "BKE_image.h"
+
#include "DNA_mesh_types.h"
#include "DEG_depsgraph_query.h"
@@ -136,7 +138,7 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
- GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, NULL, GL_TEXTURE_2D);
+ GPUTexture *tex = BKE_image_get_gpu_texture(imapaint->stencil, NULL, NULL);
const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
index 0d01f67c6ea..2989e07691f 100644
--- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
uniform sampler2D colorTex;
uniform sampler2D depthTex;
uniform sampler2D lineTex;
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
index 380708795e9..0925901a9c9 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
@@ -14,19 +14,6 @@ layout(depth_greater) out float gl_FragDepth;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 lineOutput;
-#define cameraPos ViewMatrixInverse[3].xyz
-
-float get_depth_from_view_z(float z)
-{
- if (ProjectionMatrix[3][3] == 0.0) {
- z = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
- }
- else {
- z = z * ProjectionMatrix[2][2] / (1.0 - ProjectionMatrix[3][2]);
- }
- return z * 0.5 + 0.5;
-}
-
void main()
{
const float sphere_radius = 0.05;
diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
index 317e9fe0447..d0b68df0625 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
@@ -14,8 +14,6 @@ uniform float meshSize;
uniform float lineKernel = 0.0;
uniform sampler2D depthBuffer;
-#define cameraPos (ViewMatrixInverse[3].xyz)
-
uniform int gridFlag;
#define STEPS_LEN 8
diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
index 496bb011c74..dd0e771ad93 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
@@ -7,8 +7,6 @@ uniform float meshSize;
uniform int gridFlag;
-#define cameraPos (ViewMatrixInverse[3].xyz)
-
#define PLANE_XY (1 << 4)
#define PLANE_XZ (1 << 5)
#define PLANE_YZ (1 << 6)
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 722dbdd0b5e..d0d52c8485b 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -28,7 +28,7 @@ void cavity_compute(vec2 screenco,
return;
}
- vec3 position = view_position_from_depth(screenco, depth, ViewVecs, ProjectionMatrix);
+ vec3 position = get_view_space_from_depth(screenco, depth);
vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco));
vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale;
@@ -68,7 +68,7 @@ void cavity_compute(vec2 screenco,
bool is_background = (s_depth == 1.0);
/* This trick provide good edge effect even if no neighbor is found. */
s_depth = (is_background) ? depth : s_depth;
- vec3 s_pos = view_position_from_depth(uvcoords, s_depth, ViewVecs, ProjectionMatrix);
+ vec3 s_pos = get_view_space_from_depth(uvcoords, s_depth);
if (is_background) {
s_pos.z -= world_data.cavity_distance;
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 c529f23265b..eb61edca6c7 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -67,31 +67,3 @@ void workbench_float_pair_decode(float data, out float v1, out float v2)
v1 = float(idata & v1_mask) * (1.0 / float(v1_mask));
v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask));
}
-
-vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[2], mat4 proj_mat)
-{
- if (proj_mat[3][3] == 0.0) {
- return normalize(vec3(viewvecs[0].xy + uv * viewvecs[1].xy, 1.0));
- }
- else {
- return vec3(0.0, 0.0, 1.0);
- }
-}
-
-vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[2], mat4 proj_mat)
-{
- if (proj_mat[3][3] == 0.0) {
- /* Perspective */
- float d = 2.0 * depth - 1.0;
-
- float zview = -proj_mat[3][2] / (d + proj_mat[2][2]);
-
- return zview * vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0);
- }
- else {
- /* Orthographic */
- vec3 offset = vec3(uvcoords, depth);
-
- return viewvecs[0].xyz + offset * viewvecs[1].xyz;
- }
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
index f3a238fd112..6e10a656fc1 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
@@ -14,7 +14,7 @@ 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, ViewVecs, ProjectionMatrix);
+ vec3 I = get_view_vector_from_screen_uv(uvcoordsvar.st);
vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st));
vec4 mat_data = texture(materialBuffer, uvcoordsvar.st);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
index 51007a9f246..71816f6ff6e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -1,3 +1,6 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
/**
* Separable Hexagonal Bokeh Blur by Colin Barré-Brisebois
* https://colinbarrebrisebois.com/2017/04/18/hexagonal-bokeh-blur-revisited-part-1-basic-3-pass-version/
@@ -21,13 +24,6 @@ uniform sampler2D noiseTex;
#define dof_distance dofParams.y
#define dof_invsensorsize dofParams.z
-#define M_PI 3.1415926535897932 /* pi */
-
-float max_v4(vec4 v)
-{
- return max(max(v.x, v.y), max(v.z, v.w));
-}
-
#define weighted_sum(a, b, c, d, e, e_sum) \
((a)*e.x + (b)*e.y + (c)*e.z + (d)*e.w) / max(1e-6, e_sum);
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
index ba8eeff1001..fd4d00d96dd 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
@@ -57,7 +57,7 @@ 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, ViewVecs, ProjectionMatrix);
+ vec3 I = get_view_vector_from_screen_uv(uv_viewport);
vec3 N = normalize(normal_interp);
vec3 color = color_interp;
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 6ab652cbf36..aa938d80fa3 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,5 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
@@ -33,11 +34,6 @@ float phase_function_isotropic()
return 1.0 / (4.0 * M_PI);
}
-float max_v3(vec3 v)
-{
- return max(v.x, max(v.y, v.z));
-}
-
float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
{
/* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
@@ -194,8 +190,8 @@ void main()
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
float depth_end = min(depth, gl_FragCoord.z);
- vec3 vs_ray_end = view_position_from_depth(screen_uv, depth_end, ViewVecs, ProjectionMatrix);
- vec3 vs_ray_ori = view_position_from_depth(screen_uv, 0.0, ViewVecs, ProjectionMatrix);
+ 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_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/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 3fa2e7ef084..824c3dc5ff1 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -261,11 +261,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
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);
+ tex = BKE_image_get_gpu_tiles(ima, iuser, NULL);
+ tex_tile_data = BKE_image_get_gpu_tilemap(ima, iuser, NULL);
}
else {
- tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D);
+ tex = BKE_image_get_gpu_texture(ima, iuser, NULL);
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c
index 835f10598d4..aab3cef00e6 100644
--- a/source/blender/draw/engines/workbench/workbench_shader.c
+++ b/source/blender/draw/engines/workbench/workbench_shader.c
@@ -28,6 +28,8 @@
#include "workbench_engine.h"
#include "workbench_private.h"
+extern char datatoc_common_math_lib_glsl[];
+extern char datatoc_common_math_geom_lib_glsl[];
extern char datatoc_common_hair_lib_glsl[];
extern char datatoc_common_pointcloud_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -119,6 +121,8 @@ 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_math_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, common_math_geom_lib);
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, common_pointcloud_lib);
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 8e345f8275b..d3c4d51dbd4 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -38,8 +38,6 @@
#include "BKE_volume.h"
#include "BKE_volume_render.h"
-#include "GPU_draw.h"
-
void workbench_volume_engine_init(WORKBENCH_Data *vedata)
{
WORKBENCH_TextureList *txl = vedata->txl;
@@ -79,13 +77,10 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
wpd->volumes_do = true;
if (fds->use_coba) {
- GPU_create_smoke_coba_field(fmd);
- }
- else if (!(fds->flags & FLUID_DOMAIN_USE_NOISE)) {
- GPU_create_smoke(fmd, 0);
+ DRW_smoke_ensure_coba_field(fmd);
}
- else if (fds->flags & FLUID_DOMAIN_USE_NOISE) {
- GPU_create_smoke(fmd, 1);
+ else {
+ DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
}
if ((!fds->use_coba && (fds->tex_density == NULL && fds->tex_color == NULL)) ||
@@ -293,7 +288,7 @@ void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
* all viewport in a redraw at least. */
LISTBASE_FOREACH (LinkData *, link, &wpd->smoke_domains) {
FluidModifierData *fmd = (FluidModifierData *)link->data;
- GPU_free_smoke(fmd);
+ DRW_smoke_free(fmd);
}
BLI_freelistN(&wpd->smoke_domains);
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 7a889d9399e..3551296cfc3 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -198,6 +198,17 @@ void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo);
} while (0)
/* Shaders */
+
+#ifndef __GPU_MATERIAL_H__
+/* FIXME: Meh avoid including all GPUMaterial. */
+typedef void (*GPUMaterialEvalCallbackFn)(struct GPUMaterial *mat,
+ int options,
+ const char **vert_code,
+ const char **geom_code,
+ const char **frag_lib,
+ const char **defines);
+#endif
+
struct GPUShader *DRW_shader_create(const char *vert,
const char *geom,
const char *frag,
@@ -237,7 +248,8 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
const char *geom,
const char *frag_lib,
const char *defines,
- bool deferred);
+ bool deferred,
+ GPUMaterialEvalCallbackFn callback);
struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
@@ -248,7 +260,8 @@ struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
const char *geom,
const char *frag_lib,
const char *defines,
- bool deferred);
+ bool deferred,
+ GPUMaterialEvalCallbackFn callback);
void DRW_shader_free(struct GPUShader *shader);
#define DRW_SHADER_FREE_SAFE(shader) \
do { \
diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.c b/source/blender/draw/intern/draw_cache_impl_pointcloud.c
index 17902f27513..06cedb9f72c 100644
--- a/source/blender/draw/intern/draw_cache_impl_pointcloud.c
+++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.c
@@ -158,6 +158,7 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
const bool has_radius = pointcloud->radius != NULL;
static GPUVertFormat format = {0};
+ static GPUVertFormat format_no_radius = {0};
static uint pos;
if (format.attr_len == 0) {
/* initialize vertex format */
@@ -167,11 +168,11 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
* If the vertex shader has more components than the array provides, the extras are given
* values from the vector (0, 0, 0, 1) for the missing XYZW components.
*/
- int comp_len = has_radius ? 4 : 3;
- pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, comp_len, GPU_FETCH_FLOAT);
+ pos = GPU_vertformat_attr_add(&format_no_radius, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
}
- cache->pos = GPU_vertbuf_create_with_format(&format);
+ cache->pos = GPU_vertbuf_create_with_format(has_radius ? &format : &format_no_radius);
GPU_vertbuf_data_alloc(cache->pos, pointcloud->totpoint);
if (has_radius) {
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 81c0e97a1a8..09f901c344f 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -27,8 +27,10 @@ struct DRWPass;
struct DRWShadingGroup;
struct GPUMaterial;
struct ModifierData;
+struct FluidModifierData;
struct Object;
struct ParticleSystem;
+struct RegionView3D;
struct ViewLayer;
#define UBO_FIRST_COLOR colorWire
@@ -159,14 +161,14 @@ void DRW_globals_update(void);
void DRW_globals_free(void);
struct DRWView *DRW_view_create_with_zoffset(const struct DRWView *parent_view,
- const RegionView3D *rv3d,
+ const struct RegionView3D *rv3d,
float offset);
int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color);
float *DRW_color_background_blend_get(int theme_id);
-bool DRW_object_is_flat(Object *ob, int *r_axis);
-bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis);
+bool DRW_object_is_flat(struct Object *ob, int *r_axis);
+bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis);
/* draw_hair.c */
@@ -188,6 +190,16 @@ void DRW_hair_init(void);
void DRW_hair_update(void);
void DRW_hair_free(void);
+/* draw_fluid.c */
+
+/* Fluid simulation. */
+void DRW_smoke_ensure(struct FluidModifierData *fmd, int highres);
+void DRW_smoke_ensure_coba_field(struct FluidModifierData *fmd);
+void DRW_smoke_ensure_velocity(struct FluidModifierData *fmd);
+
+void DRW_smoke_free(struct FluidModifierData *fmd);
+void DRW_smoke_free_velocity(struct FluidModifierData *fmd);
+
/* draw_common.c */
struct DRW_Global {
/** If needed, contains all global/Theme colors
diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/draw/intern/draw_fluid.c
index e0b94e20574..33311dc698f 100644
--- a/source/blender/gpu/intern/gpu_draw_smoke.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -35,10 +35,10 @@
#include "BKE_colorband.h"
-#include "GPU_draw.h"
-#include "GPU_glew.h"
#include "GPU_texture.h"
+#include "draw_common.h" /* Own include. */
+
#ifdef WITH_FLUID
# include "manta_fluid_API.h"
#endif
@@ -62,7 +62,8 @@ static void create_flame_spectrum_texture(float *data)
# define MAX_FIRE_ALPHA 0.06f
# define FULL_ON_FIRE 100
- float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+ float *spec_pixels = (float *)MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float),
+ "spec_pixels");
blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
@@ -105,7 +106,7 @@ static void create_color_ramp(const struct ColorBand *coba, float *data)
static GPUTexture *create_transfer_function(int type, const struct ColorBand *coba)
{
- float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
+ float *data = (float *)MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
switch (type) {
case TFUNC_FLAME_SPECTRUM:
@@ -184,7 +185,7 @@ static GPUTexture *create_field_texture(FluidDomainSettings *fds)
}
GPUTexture *tex = GPU_texture_create_nD(
- fds->res[0], fds->res[1], fds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+ UNPACK3(fds->res), 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
swizzle_texture_channel_single(tex);
return tex;
@@ -203,7 +204,7 @@ static GPUTexture *create_density_texture(FluidDomainSettings *fds, int highres)
}
GPUTexture *tex = GPU_texture_create_nD(
- dim[0], dim[1], dim[2], 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+ UNPACK3(dim), 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
swizzle_texture_channel_single(tex);
@@ -221,7 +222,7 @@ static GPUTexture *create_color_texture(FluidDomainSettings *fds, int highres)
int cell_count = (highres) ? manta_noise_get_cells(fds->fluid) : fds->total_cells;
int *dim = (highres) ? fds->res_noise : fds->res;
- float *data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
+ float *data = (float *)MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
if (data == NULL) {
return NULL;
@@ -276,7 +277,7 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *fds, int highres)
/** \name Public API
* \{ */
-void GPU_free_smoke(FluidModifierData *fmd)
+void DRW_smoke_free(FluidModifierData *fmd)
{
if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
if (fmd->domain->tex_density) {
@@ -316,7 +317,7 @@ void GPU_free_smoke(FluidModifierData *fmd)
}
}
-void GPU_create_smoke_coba_field(FluidModifierData *fmd)
+void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
{
#ifndef WITH_FLUID
UNUSED_VARS(fmd);
@@ -334,7 +335,7 @@ void GPU_create_smoke_coba_field(FluidModifierData *fmd)
#endif
}
-void GPU_create_smoke(FluidModifierData *fmd, int highres)
+void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
{
#ifndef WITH_FLUID
UNUSED_VARS(fmd, highres);
@@ -355,9 +356,7 @@ void GPU_create_smoke(FluidModifierData *fmd, int highres)
fds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
}
if (!fds->tex_shadow) {
- fds->tex_shadow = GPU_texture_create_nD(fds->res[0],
- fds->res[1],
- fds->res[2],
+ fds->tex_shadow = GPU_texture_create_nD(UNPACK3(fds->res),
3,
manta_smoke_get_shadow(fds->fluid),
GPU_R8,
@@ -370,7 +369,7 @@ void GPU_create_smoke(FluidModifierData *fmd, int highres)
#endif /* WITH_FLUID */
}
-void GPU_create_smoke_velocity(FluidModifierData *fmd)
+void DRW_smoke_ensure_velocity(FluidModifierData *fmd)
{
#ifndef WITH_FLUID
UNUSED_VARS(fmd);
@@ -387,19 +386,16 @@ void GPU_create_smoke_velocity(FluidModifierData *fmd)
}
if (!fds->tex_velocity_x) {
- fds->tex_velocity_x = GPU_texture_create_3d(
- fds->res[0], fds->res[1], fds->res[2], GPU_R16F, vel_x, NULL);
- fds->tex_velocity_y = GPU_texture_create_3d(
- fds->res[0], fds->res[1], fds->res[2], GPU_R16F, vel_y, NULL);
- fds->tex_velocity_z = GPU_texture_create_3d(
- fds->res[0], fds->res[1], fds->res[2], GPU_R16F, vel_z, NULL);
+ fds->tex_velocity_x = GPU_texture_create_3d(UNPACK3(fds->res), GPU_R16F, vel_x, NULL);
+ fds->tex_velocity_y = GPU_texture_create_3d(UNPACK3(fds->res), GPU_R16F, vel_y, NULL);
+ fds->tex_velocity_z = GPU_texture_create_3d(UNPACK3(fds->res), GPU_R16F, vel_z, NULL);
}
}
#endif /* WITH_FLUID */
}
-/* TODO Unify with the other GPU_free_smoke. */
-void GPU_free_smoke_velocity(FluidModifierData *fmd)
+/* TODO Unify with the other DRW_smoke_free. */
+void DRW_smoke_free_velocity(FluidModifierData *fmd)
{
if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
if (fmd->domain->tex_velocity_x) {
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 9d8050504ab..3184d6155d2 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1292,13 +1292,10 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass
}
static void drw_shgroup_material_texture(DRWShadingGroup *grp,
- GPUMaterialTexture *tex,
+ GPUTexture *gputex,
const char *name,
- eGPUSamplerState state,
- int textarget)
+ eGPUSamplerState state)
{
- GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget);
-
DRW_shgroup_uniform_texture_ex(grp, name, gputex, state);
GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images);
@@ -1314,15 +1311,16 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &textures) {
if (tex->ima) {
/* Image */
+ GPUTexture *gputex;
if (tex->tiled_mapping_name[0]) {
- drw_shgroup_material_texture(
- grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D_ARRAY);
- drw_shgroup_material_texture(
- grp, tex, tex->tiled_mapping_name, tex->sampler_state, GL_TEXTURE_1D_ARRAY);
+ gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL);
+ drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
+ gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL);
+ drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
}
else {
- drw_shgroup_material_texture(
- grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D);
+ gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL);
+ drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
}
}
else if (tex->colorband) {
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index b6f51ada5a1..91cbc03e5a4 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -446,6 +446,7 @@ void DRW_state_reset(void)
DRW_state_reset_ex(DRW_STATE_DEFAULT);
GPU_texture_unbind_all();
+ GPU_uniformbuffer_unbind_all();
/* Should stay constant during the whole rendering. */
GPU_point_size(5);
@@ -669,8 +670,7 @@ BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
DST.batch = geom;
- GPU_batch_program_set_no_use(
- geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+ GPU_batch_set_shader_no_bind(geom, shgroup->shader);
geom->program_in_use = true; /* XXX hacking #GPUBatch */
@@ -773,10 +773,11 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
&shgroup->pass_handle);
- printf("Pass : %s, Shader : %s, Block : %s\n",
+ printf("Pass : %s, Shader : %s, Block : %s, Binding %d\n",
parent_pass->name,
shgroup->shader->name,
- blockname);
+ blockname,
+ binding);
}
}
# endif
@@ -1106,6 +1107,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
/* Unbinding can be costly. Skip in normal condition. */
if (G.debug & G_DEBUG_GPU) {
GPU_texture_unbind_all();
+ GPU_uniformbuffer_unbind_all();
}
}
GPU_shader_bind(shgroup->shader);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 0bb20631537..fec234c5015 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -430,7 +430,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
const char *geom,
const char *frag_lib,
const char *defines,
- bool deferred)
+ bool deferred,
+ GPUMaterialEvalCallbackFn callback)
{
GPUMaterial *mat = NULL;
if (DRW_state_is_image_render() || !deferred) {
@@ -450,7 +451,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
geom,
frag_lib,
defines,
- wo->id.name);
+ wo->id.name,
+ callback);
}
if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
@@ -470,7 +472,8 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
const char *geom,
const char *frag_lib,
const char *defines,
- bool deferred)
+ bool deferred,
+ GPUMaterialEvalCallbackFn callback)
{
GPUMaterial *mat = NULL;
if (DRW_state_is_image_render() || !deferred) {
@@ -490,7 +493,8 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
geom,
frag_lib,
defines,
- ma->id.name);
+ ma->id.name,
+ callback);
}
if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index 84c8d0f861f..ee5561e1e38 100644
--- a/source/blender/draw/intern/draw_select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -395,7 +395,7 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
int center_x = width / 2;
int center_y = height / 2;
- /* Manhatten distance in keeping with other screen-based selection. */
+ /* Manhattan distance in keeping with other screen-based selection. */
*dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y));
/* Indices start at 1 here. */
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
index 3c470f802ec..b42700b2c7e 100644
--- a/source/blender/draw/intern/draw_view.c
+++ b/source/blender/draw/intern/draw_view.c
@@ -184,8 +184,7 @@ void DRW_draw_cursor(void)
GPUBatch *cursor_batch = DRW_cache_cursor_get(is_aligned);
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR);
- GPU_batch_program_set(
- cursor_batch, GPU_shader_get_program(shader), GPU_shader_get_interface(shader));
+ GPU_batch_set_shader(cursor_batch, shader);
GPU_batch_draw(cursor_batch);
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index ffff631e34b..8684d82f228 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -95,7 +95,7 @@ void hair_get_interp_attrs(
* For final drawing, the vertex index and the number of vertex per segment
*/
-#ifndef HAIR_PHASE_SUBDIV
+#if !defined(HAIR_PHASE_SUBDIV) && defined(GPU_VERTEX_SHADER)
int hair_get_strand_id(void)
{
return gl_VertexID / (hairStrandsRes * hairThicknessRes);
@@ -206,4 +206,24 @@ vec3 hair_get_strand_pos(void)
return texelFetch(hairPointBuffer, id).point_position;
}
+vec2 hair_get_barycentric(void)
+{
+ /* To match cycles without breaking into individual segment we encode if we need to invert
+ * the first component into the second component. We invert if the barycentricTexCo.y
+ * is NOT 0.0 or 1.0. */
+ int id = hair_get_base_id();
+ return vec2(float((id % 2) == 1), float(((id % 4) % 3) > 0));
+}
+
#endif
+
+/* To be fed the result of hair_get_barycentric from vertex shader. */
+vec2 hair_resolve_barycentric(vec2 vert_barycentric)
+{
+ if (fract(vert_barycentric.y) != 0.0) {
+ return vec2(vert_barycentric.x, 0.0);
+ }
+ else {
+ return vec2(1.0 - vert_barycentric.x, 0.0);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 095bc64a19e..a55d2cd8c1a 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -22,6 +22,16 @@ layout(std140) uniform viewBlock
vec4 CameraTexCoFactors;
};
+#define ViewNear (ViewVecs[0].w)
+#define ViewFar (ViewVecs[1].w)
+
+#define cameraForward ViewMatrixInverse[2].xyz
+#define cameraPos ViewMatrixInverse[3].xyz
+#define cameraVec \
+ ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
+#define viewCameraVec \
+ ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0))
+
#ifdef world_clip_planes_calc_clip_distance
# undef world_clip_planes_calc_clip_distance
# define world_clip_planes_calc_clip_distance(p) \
@@ -104,10 +114,13 @@ uniform int resourceId;
/* Use this to declare and pass the value if
* the fragment shader uses the resource_id. */
-# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
-# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom;
-# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
-# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id;
+# ifdef USE_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING flat out int resourceIDGeom;
+# define PASS_RESOURCE_ID resourceIDGeom = resource_id;
+# else
+# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# endif
#endif
/* If used in a fragment / geometry shader, we pass
@@ -118,7 +131,7 @@ uniform int resourceId;
flat in int resourceIDGeom[];
# define resource_id resourceIDGeom
-# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i];
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
#endif
#ifdef GPU_FRAGMENT_SHADER
@@ -171,9 +184,12 @@ uniform mat4 ModelMatrixInverse;
* Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
* ViewMatrix * transpose(ModelMatrixInverse)
**/
-#define normal_object_to_view(n) (mat3(ViewMatrix) * (transpose(mat3(ModelMatrixInverse)) * n))
-#define normal_object_to_world(n) (transpose(mat3(ModelMatrixInverse)) * n)
-#define normal_world_to_object(n) (transpose(mat3(ModelMatrix)) * n)
+#define NormalMatrix transpose(mat3(ModelMatrixInverse))
+#define NormalMatrixInverse transpose(mat3(ModelMatrix))
+
+#define normal_object_to_view(n) (mat3(ViewMatrix) * (NormalMatrix * n))
+#define normal_object_to_world(n) (NormalMatrix * n)
+#define normal_world_to_object(n) (NormalMatrixInverse * n)
#define normal_world_to_view(n) (mat3(ViewMatrix) * n)
#define normal_view_to_world(n) (mat3(ViewMatrixInverse) * n)
@@ -199,3 +215,78 @@ uniform mat4 ModelMatrixInverse;
#define DRW_BASE_FROM_DUPLI (1 << 2)
#define DRW_BASE_FROM_SET (1 << 3)
#define DRW_BASE_ACTIVE (1 << 4)
+
+/* ---- Opengl Depth conversion ---- */
+
+float linear_depth(bool is_persp, float z, float zf, float zn)
+{
+ if (is_persp) {
+ return (zn * zf) / (z * (zn - zf) + zf);
+ }
+ else {
+ return (z * 2.0 - 1.0) * zf;
+ }
+}
+
+float buffer_depth(bool is_persp, float z, float zf, float zn)
+{
+ if (is_persp) {
+ return (zf * (zn - z)) / (z * (zn - zf));
+ }
+ else {
+ return (z / (zf * 2.0)) + 0.5;
+ }
+}
+
+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;
+ }
+}
+
+float get_depth_from_view_z(float z)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ float d = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
+ return d * 0.5 + 0.5;
+ }
+ else {
+ return (z - ViewVecs[0].z) / ViewVecs[1].z;
+ }
+}
+
+vec2 get_uvs_from_view(vec3 view)
+{
+ vec4 ndc = ProjectionMatrix * vec4(view, 1.0);
+ return (ndc.xy / ndc.w) * 0.5 + 0.5;
+}
+
+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;
+ }
+}
+
+vec3 get_world_space_from_depth(vec2 uvcoords, float depth)
+{
+ return (ViewMatrixInverse * vec4(get_view_space_from_depth(uvcoords, depth), 1.0)).xyz;
+}
+
+vec3 get_view_vector_from_screen_uv(vec2 uv)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return normalize(vec3(ViewVecs[0].xy + uv * ViewVecs[1].xy, 1.0));
+ }
+ else {
+ return vec3(0.0, 0.0, 1.0);
+ }
+}
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index b759277572c..d78c543f94b 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -76,9 +76,9 @@ static int kill_selection(Object *obedit, int ins);
/** \name Internal Utilities
* \{ */
-static wchar_t findaccent(wchar_t char1, uint code)
+static char32_t findaccent(char32_t char1, uint code)
{
- wchar_t new = 0;
+ char32_t new = 0;
if (char1 == 'a') {
if (code == '`') {
@@ -682,7 +682,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
cu->strinfo = MEM_callocN((nchars + 4) * sizeof(CharInfo), "strinfo");
cu->len = 0;
- cu->len_wchar = nchars - 1;
+ cu->len_char32 = nchars - 1;
cu->pos = 0;
s = cu->str;
@@ -703,7 +703,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
}
}
- cu->pos = cu->len_wchar;
+ cu->pos = cu->len_char32;
*s = '\0';
WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, obedit);
@@ -1661,7 +1661,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
uintptr_t ascii = event->ascii;
int alt = event->alt, shift = event->shift, ctrl = event->ctrl;
int event_type = event->type, event_val = event->val;
- wchar_t inserted_text[2] = {0};
+ char32_t inserted_text[2] = {0};
if (RNA_struct_property_is_set(op->ptr, "text")) {
return insert_text_exec(C, op);
@@ -1733,7 +1733,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* store as utf8 in RNA string */
char inserted_utf8[8] = {0};
- BLI_strncpy_wchar_as_utf8(inserted_utf8, inserted_text, sizeof(inserted_utf8));
+ BLI_str_utf32_as_utf8(inserted_utf8, inserted_text, sizeof(inserted_utf8));
RNA_string_set(op->ptr, "text", inserted_utf8);
}
@@ -1867,7 +1867,7 @@ void ED_curve_editfont_make(Object *obedit)
{
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
- int len_wchar;
+ int len_char32;
if (ef == NULL) {
ef = cu->editfont = MEM_callocN(sizeof(EditFont), "editfont");
@@ -1876,10 +1876,10 @@ void ED_curve_editfont_make(Object *obedit)
ef->textbufinfo = MEM_callocN((MAXTEXT + 4) * sizeof(CharInfo), "texteditbufinfo");
}
- /* Convert the original text to wchar_t */
- len_wchar = BLI_str_utf8_as_utf32(ef->textbuf, cu->str, MAXTEXT + 4);
- BLI_assert(len_wchar == cu->len_wchar);
- ef->len = len_wchar;
+ /* Convert the original text to chat32_t. */
+ len_char32 = BLI_str_utf8_as_utf32(ef->textbuf, cu->str, MAXTEXT + 4);
+ BLI_assert(len_char32 == cu->len_char32);
+ ef->len = len_char32;
BLI_assert(ef->len >= 0);
memcpy(ef->textbufinfo, cu->strinfo, ef->len * sizeof(CharInfo));
@@ -1908,7 +1908,7 @@ void ED_curve_editfont_load(Object *obedit)
MEM_freeN(cu->str);
/* Calculate the actual string length in UTF-8 variable characters */
- cu->len_wchar = ef->len;
+ cu->len_char32 = ef->len;
cu->len = BLI_str_utf32_as_utf8_len(ef->textbuf);
/* Alloc memory for UTF-8 variable char length string */
@@ -1920,8 +1920,8 @@ void ED_curve_editfont_load(Object *obedit)
if (cu->strinfo) {
MEM_freeN(cu->strinfo);
}
- cu->strinfo = MEM_callocN((cu->len_wchar + 4) * sizeof(CharInfo), "texteditinfo");
- memcpy(cu->strinfo, ef->textbufinfo, cu->len_wchar * sizeof(CharInfo));
+ cu->strinfo = MEM_callocN((cu->len_char32 + 4) * sizeof(CharInfo), "texteditinfo");
+ memcpy(cu->strinfo, ef->textbufinfo, cu->len_char32 * sizeof(CharInfo));
/* Other vars */
cu->pos = ef->pos;
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index 71a364c60d7..033673a99a8 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -29,7 +29,6 @@
#include "ED_view3d.h"
#include "GPU_batch.h"
-#include "GPU_glew.h"
#include "GPU_immediate.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 6f700f6c4b8..3aec1db2587 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -200,7 +200,7 @@ typedef struct tGPsdata {
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
-#define MIN_MANHATTEN_PX (U.gp_manhattendist)
+#define MIN_MANHATTAN_PX (U.gp_manhattandist)
/* minimum length of new segment before new point can be added */
#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
@@ -297,7 +297,7 @@ static bool annotation_stroke_filtermval(tGPsdata *p, const float mval[2], float
return false;
}
- if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) {
+ if ((dx > MIN_MANHATTAN_PX) && (dy > MIN_MANHATTAN_PX)) {
return true;
}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 96b0296a7de..348fb614977 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -861,6 +861,154 @@ void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
INT_MAX);
}
+/* ********************* Clean Duplicated Frames ************************** */
+static bool gpencil_frame_is_equal(bGPDframe *gpf_a, bGPDframe *gpf_b)
+{
+ if ((gpf_a == NULL) || (gpf_b == NULL)) {
+ return false;
+ }
+ /* If the number of strokes is different, cannot be equal. */
+ int totstrokes_a = BLI_listbase_count(&gpf_a->strokes);
+ int totstrokes_b = BLI_listbase_count(&gpf_b->strokes);
+ if ((totstrokes_a == 0) || (totstrokes_b == 0) || (totstrokes_a != totstrokes_b)) {
+ return false;
+ }
+ /* Loop all strokes and check. */
+ bGPDstroke *gps_a = gpf_a->strokes.first;
+ bGPDstroke *gps_b = gpf_b->strokes.first;
+ for (int i = 0; i < totstrokes_a; i++) {
+ /* If the number of points is different, cannot be equal. */
+ if (gps_a->totpoints != gps_b->totpoints) {
+ return false;
+ }
+ /* Check other variables. */
+ if (!equals_v4v4(gps_a->vert_color_fill, gps_b->vert_color_fill)) {
+ return false;
+ }
+ if (gps_a->thickness != gps_b->thickness) {
+ return false;
+ }
+ if (gps_a->mat_nr != gps_b->mat_nr) {
+ return false;
+ }
+ if (gps_a->caps[0] != gps_b->caps[0]) {
+ return false;
+ }
+ if (gps_a->caps[1] != gps_b->caps[1]) {
+ return false;
+ }
+ if (gps_a->hardeness != gps_b->hardeness) {
+ return false;
+ }
+ if (!equals_v2v2(gps_a->aspect_ratio, gps_b->aspect_ratio)) {
+ return false;
+ }
+ if (gps_a->uv_rotation != gps_b->uv_rotation) {
+ return false;
+ }
+ if (!equals_v2v2(gps_a->uv_translation, gps_b->uv_translation)) {
+ return false;
+ }
+ if (gps_a->uv_scale != gps_b->uv_scale) {
+ return false;
+ }
+
+ /* Loop points and check if equals or not. */
+ for (int p = 0; p < gps_a->totpoints; p++) {
+ bGPDspoint *pt_a = &gps_a->points[p];
+ bGPDspoint *pt_b = &gps_b->points[p];
+ if (!equals_v3v3(&pt_a->x, &pt_b->x)) {
+ return false;
+ }
+ if (pt_a->pressure != pt_b->pressure) {
+ return false;
+ }
+ if (pt_a->strength != pt_b->strength) {
+ return false;
+ }
+ if (pt_a->uv_fac != pt_b->uv_fac) {
+ return false;
+ }
+ if (pt_a->uv_rot != pt_b->uv_rot) {
+ return false;
+ }
+ if (!equals_v4v4(pt_a->vert_color, pt_b->vert_color)) {
+ return false;
+ }
+ }
+
+ /* Look at next pair of strokes. */
+ gps_a = gps_a->next;
+ gps_b = gps_b->next;
+ }
+
+ return true;
+}
+
+static int gpencil_frame_clean_duplicate_exec(bContext *C, wmOperator *op)
+{
+#define SELECTED 1
+
+ bool changed = false;
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* Only editable and visible layers are considered. */
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->frames.first != NULL)) {
+ bGPDframe *gpf = gpl->frames.first;
+
+ if ((type == SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+
+ while (gpf != NULL) {
+ if (gpencil_frame_is_equal(gpf, gpf->next)) {
+ /* Remove frame. */
+ BKE_gpencil_layer_frame_delete(gpl, gpf->next);
+ /* Tag for recalc. */
+ changed = true;
+ }
+ else {
+ gpf = gpf->next;
+ }
+ }
+ }
+ }
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_frame_clean_duplicate(wmOperatorType *ot)
+{
+ static const EnumPropertyItem clean_type[] = {
+ {0, "ALL", 0, "All Frames", ""},
+ {1, "SELECTED", 0, "Selected Frames", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Clean Duplicated Frames";
+ ot->idname = "GPENCIL_OT_frame_clean_duplicate";
+ ot->description = "Remove any duplicated frame";
+
+ /* callbacks */
+ ot->exec = gpencil_frame_clean_duplicate_exec;
+ ot->poll = gpencil_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", clean_type, 0, "Type", "");
+}
+
/* *********************** Hide Layers ******************************** */
static int gpencil_hide_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 286efeeff01..29ae38fdbd8 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -94,6 +94,8 @@
/** \name Stroke Edit Mode Management
* \{ */
+static void gpencil_flip_stroke(bGPDstroke *gps);
+
/* poll callback for all stroke editing operators */
static bool gpencil_stroke_edit_poll(bContext *C)
{
@@ -1126,6 +1128,11 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
pt->flag |= GP_SPOINT_SELECT;
}
+ /* Flip stroke if it was only one point to consider extrude point as last point. */
+ if (gps->totpoints == 2) {
+ gpencil_flip_stroke(gps);
+ }
+
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 517225e5a81..d7525c3c6a5 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -416,10 +416,10 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf)
/* create a image to see result of template */
if (ibuf->rect_float) {
- GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
+ GPU_offscreen_read_pixels(offscreen, GPU_DATA_FLOAT, ibuf->rect_float);
}
else if (ibuf->rect) {
- GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
+ GPU_offscreen_read_pixels(offscreen, GPU_DATA_UNSIGNED_BYTE, ibuf->rect);
}
if (ibuf->rect_float && ibuf->rect) {
IMB_rect_from_float(ibuf);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index bd697dbc768..68424839ab0 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -485,6 +485,7 @@ void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_frame_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot);
void GPENCIL_OT_frame_clean_loose(struct wmOperatorType *ot);
+void GPENCIL_OT_frame_clean_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
void GPENCIL_OT_bake_mesh_animation(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index efee05f7da3..3892f451e18 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -600,6 +600,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_frame_duplicate);
WM_operatortype_append(GPENCIL_OT_frame_clean_fill);
WM_operatortype_append(GPENCIL_OT_frame_clean_loose);
+ WM_operatortype_append(GPENCIL_OT_frame_clean_duplicate);
WM_operatortype_append(GPENCIL_OT_convert);
WM_operatortype_append(GPENCIL_OT_bake_mesh_animation);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index d3ff7f8a4d2..b61baf3d0b1 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -268,7 +268,7 @@ typedef struct tGPsdata {
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
-#define MIN_MANHATTEN_PX (U.gp_manhattendist)
+#define MIN_MANHATTEN_PX (U.gp_manhattandist)
/* minimum length of new segment before new point can be added */
#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index f206f5c832a..fb0d94f2307 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -695,7 +695,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
(tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
- const bool is_vertex_stroke = GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush);
if (tgpi->type == GP_STROKE_BOX) {
gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
@@ -1020,12 +1019,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
pt->time = 0.0f;
pt->flag = 0;
pt->uv_fac = tpt->uv_fac;
- if (is_vertex_stroke) {
- copy_v4_v4(pt->vert_color, tpt->vert_color);
- }
- else {
- zero_v4(pt->vert_color);
- }
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, tpt);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[i];
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index f77bb394567..d412c13aea2 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -2688,7 +2688,11 @@ void ED_gpencil_tag_scene_gpencil(Scene *scene)
void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke *gps)
{
- if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) {
+ const bool is_vertex = (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode != GP_BRUSH_MODE_MATERIAL)) ||
+ (!GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode == GP_BRUSH_MODE_VERTEXCOLOR));
+ if (is_vertex) {
copy_v3_v3(gps->vert_color_fill, brush->rgb);
gps->vert_color_fill[3] = brush->gpencil_settings->vertex_factor;
srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill);
@@ -2703,7 +2707,12 @@ void ED_gpencil_point_vertex_color_set(ToolSettings *ts,
bGPDspoint *pt,
tGPspoint *tpt)
{
- if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
+ const bool is_vertex = (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode != GP_BRUSH_MODE_MATERIAL)) ||
+ (!GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode == GP_BRUSH_MODE_VERTEXCOLOR));
+
+ if (is_vertex) {
if (tpt == NULL) {
copy_v3_v3(pt->vert_color, brush->rgb);
pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
@@ -2859,6 +2868,18 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
MaterialGPencilStyle *gp_style = material->gp_style;
+ const bool is_vertex_fill =
+ (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode != GP_BRUSH_MODE_MATERIAL)) ||
+ (!GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode == GP_BRUSH_MODE_VERTEXCOLOR));
+
+ const bool is_vertex_stroke =
+ (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode != GP_BRUSH_MODE_MATERIAL)) ||
+ (!GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) &&
+ (brush->gpencil_settings->brush_draw_mode == GP_BRUSH_MODE_VERTEXCOLOR));
+
int idx = gpd->runtime.sbuffer_used;
tGPspoint *tpt = (tGPspoint *)gpd->runtime.sbuffer + idx;
@@ -2868,14 +2889,14 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
srgb_to_linearrgb_v4(vertex_color, vertex_color);
/* Copy fill vertex color. */
- if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) {
+ if (is_vertex_fill) {
copy_v4_v4(gpd->runtime.vert_color_fill, vertex_color);
}
else {
copy_v4_v4(gpd->runtime.vert_color_fill, gp_style->fill_rgba);
}
/* Copy stroke vertex color. */
- if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
+ if (is_vertex_stroke) {
copy_v4_v4(tpt->vert_color, vertex_color);
}
else {
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 1eb22fb34e2..cfd92bf3113 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -24,6 +24,8 @@
#ifndef __BIF_GLUTIL_H__
#define __BIF_GLUTIL_H__
+#include "GPU_texture.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -66,9 +68,8 @@ void immDrawPixelsTex(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float xzoom,
float yzoom,
@@ -78,9 +79,8 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float clip_min_x,
float clip_min_y,
@@ -94,9 +94,8 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float scaleX,
float scaleY,
@@ -108,9 +107,8 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float scaleX,
float scaleY,
@@ -133,7 +131,7 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
void ED_draw_imbuf(struct ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
struct ColorManagedViewSettings *view_settings,
struct ColorManagedDisplaySettings *display_settings,
float zoom_x,
@@ -141,7 +139,7 @@ void ED_draw_imbuf(struct ImBuf *ibuf,
void ED_draw_imbuf_clipping(struct ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
struct ColorManagedViewSettings *view_settings,
struct ColorManagedDisplaySettings *display_settings,
float clip_min_x,
@@ -155,14 +153,14 @@ void ED_draw_imbuf_ctx(const struct bContext *C,
struct ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
float zoom_x,
float zoom_y);
void ED_draw_imbuf_ctx_clipping(const struct bContext *C,
struct ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
float clip_min_x,
float clip_min_y,
float clip_max_x,
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 2eaef5e82e0..455eee8580d 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -27,6 +27,10 @@
extern "C" {
#endif
+struct SpaceProperties;
+
+int ED_buttons_tabs_list(struct SpaceProperties *sbuts, int *context_tabs_array);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index 8c8f3e6f4a3..16d05a7793a 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -103,8 +103,12 @@ bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event
#define NUM_MODAL_INCREMENT_UP 18
#define NUM_MODAL_INCREMENT_DOWN 19
-bool user_string_to_number(
- bContext *C, const char *str, const struct UnitSettings *unit, int type, double *r_value);
+bool user_string_to_number(bContext *C,
+ const char *str,
+ const struct UnitSettings *unit,
+ int type,
+ const char *error_prefix,
+ double *r_value);
/** \} */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index e0bd1369a51..2c42f3a5071 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -101,7 +101,7 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
/* use for clamping popups within the screen */
#define UI_SCREEN_MARGIN 10
-/* uiBlock->dt and uiBut->dt */
+/** #uiBlock.emboss and #uiBut.emboss */
enum {
UI_EMBOSS = 0, /* use widget style for drawing */
UI_EMBOSS_NONE = 1, /* Nothing, only icon and/or text */
@@ -657,7 +657,7 @@ bool UI_popup_block_name_exists(const struct bScreen *screen, const char *name);
uiBlock *UI_block_begin(const struct bContext *C,
struct ARegion *region,
const char *name,
- short dt);
+ char emboss);
void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]);
void UI_block_end(const struct bContext *C, uiBlock *block);
void UI_block_draw(const struct bContext *C, struct uiBlock *block);
@@ -671,7 +671,7 @@ enum {
};
void UI_block_theme_style_set(uiBlock *block, char theme_style);
char UI_block_emboss_get(uiBlock *block);
-void UI_block_emboss_set(uiBlock *block, char dt);
+void UI_block_emboss_set(uiBlock *block, char emboss);
void UI_block_free(const struct bContext *C, uiBlock *block);
void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 12ff147b0a1..b28a6f530f6 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -52,7 +52,6 @@
#include "BKE_screen.h"
#include "BKE_unit.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -1487,7 +1486,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
continue;
}
}
- else if (but->dt != UI_EMBOSS_PULLDOWN) {
+ else if (but->emboss != UI_EMBOSS_PULLDOWN) {
continue;
}
@@ -2801,25 +2800,39 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
return str;
}
-static bool ui_set_but_string_eval_num_unit(bContext *C,
- uiBut *but,
- const char *str,
- double *r_value)
+/**
+ * Report a generic error prefix when evaluating a string with #BPY_execute_string_as_number
+ * as the Python error on it's own doesn't provide enough context.
+ */
+#define UI_NUMBER_EVAL_ERROR_PREFIX IFACE_("Error evaluating number, see Info editor for details")
+
+static bool ui_number_from_string_units(
+ bContext *C, const char *str, const int unit_type, const UnitSettings *unit, double *r_value)
{
+ return user_string_to_number(C, str, unit, unit_type, UI_NUMBER_EVAL_ERROR_PREFIX, r_value);
+}
+
+static bool ui_number_from_string_units_with_but(bContext *C,
+ const char *str,
+ const uiBut *but,
+ double *r_value)
+{
+ const int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
const UnitSettings *unit = but->block->unit;
- int type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
- return user_string_to_number(C, str, unit, type, r_value);
+ return ui_number_from_string_units(C, str, unit_type, unit, r_value);
}
static bool ui_number_from_string(bContext *C, const char *str, double *r_value)
{
+ bool ok;
#ifdef WITH_PYTHON
- return BPY_execute_string_as_number(C, NULL, str, true, r_value);
+ ok = BPY_execute_string_as_number(C, NULL, str, UI_NUMBER_EVAL_ERROR_PREFIX, r_value);
#else
UNUSED_VARS(C);
*r_value = atof(str);
- return true;
+ ok = true;
#endif
+ return ok;
}
static bool ui_number_from_string_factor(bContext *C, const char *str, double *r_value)
@@ -2853,7 +2866,7 @@ static bool ui_number_from_string_percentage(bContext *C, const char *str, doubl
return ui_number_from_string(C, str, r_value);
}
-bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *r_value)
+bool ui_but_string_eval_number(bContext *C, const uiBut *but, const char *str, double *r_value)
{
if (str[0] == '\0') {
*r_value = 0.0;
@@ -2867,7 +2880,7 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double
if (ui_but_is_float(but)) {
if (ui_but_is_unit(but)) {
- return ui_set_but_string_eval_num_unit(C, but, str, r_value);
+ return ui_number_from_string_units_with_but(C, str, but, r_value);
}
if (subtype == PROP_FACTOR) {
return ui_number_from_string_factor(C, str, r_value);
@@ -3007,7 +3020,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
/* number editing */
double value;
- if (ui_but_string_set_eval_num(C, but, str, &value) == false) {
+ if (ui_but_string_eval_number(C, but, str, &value) == false) {
WM_report_banner_show();
return false;
}
@@ -3341,7 +3354,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
block->oldblock = oldblock;
}
-uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, short dt)
+uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, char emboss)
{
uiBlock *block;
wmWindow *window;
@@ -3352,7 +3365,7 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
block = MEM_callocN(sizeof(uiBlock), "uiBlock");
block->active = 1;
- block->dt = dt;
+ block->emboss = emboss;
block->evil_C = (void *)C; /* XXX */
if (scn) {
@@ -3391,12 +3404,12 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
char UI_block_emboss_get(uiBlock *block)
{
- return block->dt;
+ return block->emboss;
}
-void UI_block_emboss_set(uiBlock *block, char dt)
+void UI_block_emboss_set(uiBlock *block, char emboss)
{
- block->dt = dt;
+ block->emboss = emboss;
}
void UI_block_theme_style_set(uiBlock *block, char theme_style)
@@ -3776,7 +3789,7 @@ static uiBut *ui_def_but(uiBlock *block,
but->tip = tip;
but->disabled_info = block->lockstr;
- but->dt = block->dt;
+ but->emboss = block->emboss;
but->pie_dir = UI_RADIAL_NONE;
but->block = block; /* pointer back, used for frontbuffer status, and picker */
@@ -4309,7 +4322,7 @@ static uiBut *ui_def_but_rna(uiBlock *block,
}
if (type == UI_BTYPE_MENU) {
- if (but->dt == UI_EMBOSS_PULLDOWN) {
+ if (but->emboss == UI_EMBOSS_PULLDOWN) {
ui_but_submenu_enable(block, but);
}
}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index a08c5c45b6f..aaa5e1c0cf1 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -407,7 +407,7 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
"'%s').label",
idname);
char *expr_result = NULL;
- if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
+ if (BPY_execute_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
STRNCPY(drawstr, expr_result);
MEM_freeN(expr_result);
}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index cc5d21c3df3..df11a78e657 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -773,9 +773,8 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
(float)rect->ymin,
ibuf->x,
ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
+ GPU_RGBA8,
+ false,
ibuf->rect,
1.0f,
1.0f,
@@ -2257,12 +2256,12 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
/* Also add the last points on the right and bottom edges to close off the fill polygon. */
bool add_left_tri = profile->view_rect.xmin < 0.0f;
bool add_bottom_tri = profile->view_rect.ymin < 0.0f;
- uint tot_points = (uint)PROF_N_TABLE(profile->path_len) + 1 + add_left_tri + add_bottom_tri;
+ uint tot_points = (uint)PROF_TABLE_LEN(profile->path_len) + 1 + add_left_tri + add_bottom_tri;
uint tot_triangles = tot_points - 2;
/* Create array of the positions of the table's points. */
float(*table_coords)[2] = MEM_mallocN(sizeof(*table_coords) * tot_points, "table x coords");
- for (i = 0; i < (uint)PROF_N_TABLE(profile->path_len);
+ for (i = 0; i < (uint)PROF_TABLE_LEN(profile->path_len);
i++) { /* Only add the points from the table here. */
table_coords[i][0] = pts[i].x;
table_coords[i][1] = pts[i].y;
@@ -2545,9 +2544,8 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
rect.ymin + 1,
drawibuf->x,
drawibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_LINEAR,
+ GPU_RGBA8,
+ true,
drawibuf->rect,
1.0f,
1.0f,
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 93b052b3b69..5da82b5be9c 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -39,8 +39,6 @@
#include "RNA_access.h"
-#include "GPU_glew.h"
-
#include "UI_interface.h"
#include "IMB_colormanagement.h"
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 88ad5d8fec1..6f76da0317c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2364,7 +2364,7 @@ static void ui_but_paste_numeric_value(bContext *C,
{
double value;
- if (ui_but_string_set_eval_num(C, but, buf_paste, &value)) {
+ if (ui_but_string_eval_number(C, but, buf_paste, &value)) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
data->value = value;
ui_but_string_set(C, but, buf_paste);
@@ -4387,7 +4387,7 @@ static int ui_do_but_TEX(
if (ELEM(event->type, EVT_PADENTER, EVT_RETKEY) && (!UI_but_is_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
- else if (but->dt == UI_EMBOSS_NONE && !event->ctrl) {
+ else if (but->emboss == UI_EMBOSS_NONE && !event->ctrl) {
/* pass */
}
else {
@@ -7126,7 +7126,7 @@ static int ui_do_but_CURVEPROFILE(
dist_min_sq = square_f(U.dpi_fac * 8.0f); /* 8 pixel radius from each table point. */
/* Loop through the path's high resolution table and find what's near the click. */
- for (int i = 1; i <= PROF_N_TABLE(profile->path_len); i++) {
+ for (int i = 1; i <= PROF_TABLE_LEN(profile->path_len); i++) {
copy_v2_v2(f_xy_prev, f_xy);
BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[i].x);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 586f5e07997..a7b7bad2fe6 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1517,18 +1517,8 @@ static void icon_draw_rect(float x,
immUniform1f("factor", desaturate);
}
- immDrawPixelsTex(&state,
- draw_x,
- draw_y,
- draw_w,
- draw_h,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
- rect,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTex(
+ &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col);
if (ima) {
IMB_freeImBuf(ima);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 249134c6abf..5ff2d76f7c8 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -233,8 +233,8 @@ struct uiBut {
const char *disabled_info;
BIFIconID icon;
- /** drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the block */
- char dt;
+ /** emboss: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the #uiBlock.emboss */
+ char emboss;
/** direction in a pie menu, used for collision detection (RadialDirection) */
signed char pie_dir;
/** could be made into a single flag */
@@ -405,8 +405,8 @@ struct uiBlock {
char direction;
/** UI_BLOCK_THEME_STYLE_* */
char theme_style;
- /** drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied to buttons */
- char dt;
+ /** UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied to #uiBut.emboss */
+ char emboss;
bool auto_open;
char _pad[5];
double auto_open_last;
@@ -517,10 +517,10 @@ extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_N
extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size);
extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
extern bool ui_but_string_set(struct bContext *C, uiBut *but, const char *str) ATTR_NONNULL();
-extern bool ui_but_string_set_eval_num(struct bContext *C,
- uiBut *but,
- const char *str,
- double *value) ATTR_NONNULL();
+extern bool ui_but_string_eval_number(struct bContext *C,
+ const uiBut *but,
+ const char *str,
+ double *value) ATTR_NONNULL();
extern int ui_but_string_get_max_length(uiBut *but);
/* Clear & exit the active button's string. */
extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index b707aaa0ee9..e82a42d9ad7 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -674,7 +674,7 @@ static void ui_item_array(uiLayout *layout,
/* show checkboxes for rna on a non-emboss block (menu for eg) */
if (type == PROP_BOOLEAN &&
- ELEM(layout->root->block->dt, UI_EMBOSS_NONE, UI_EMBOSS_PULLDOWN)) {
+ ELEM(layout->root->block->emboss, UI_EMBOSS_NONE, UI_EMBOSS_PULLDOWN)) {
boolarr = MEM_callocN(sizeof(bool) * len, __func__);
RNA_property_boolean_get_array(ptr, prop, boolarr);
}
@@ -2330,7 +2330,7 @@ void uiItemFullR(uiLayout *layout,
/* Mark non-embossed textfields inside a listbox. */
if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) &&
- (but->dt & UI_EMBOSS_NONE)) {
+ (but->emboss & UI_EMBOSS_NONE)) {
UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
}
@@ -3828,7 +3828,7 @@ static void ui_litem_layout_radial(uiLayout *litem)
bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
/* enable drawing as pie item if supported by widget */
if (ui_item_is_radial_drawable(bitem)) {
- bitem->but->dt = UI_EMBOSS_RADIAL;
+ bitem->but->emboss = UI_EMBOSS_RADIAL;
bitem->but->drawflag |= UI_BUT_ICON_LEFT;
}
}
@@ -5036,7 +5036,7 @@ float uiLayoutGetUnitsY(uiLayout *layout)
int uiLayoutGetEmboss(uiLayout *layout)
{
if (layout->emboss == UI_EMBOSS_UNDEFINED) {
- return layout->root->block->dt;
+ return layout->root->block->emboss;
}
return layout->emboss;
}
@@ -5411,7 +5411,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
}
if (layout->emboss != UI_EMBOSS_UNDEFINED) {
- but->dt = layout->emboss;
+ but->emboss = layout->emboss;
}
}
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 4634f4b95c9..10b219202e5 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -90,7 +90,7 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
if (but->flag & UI_SCROLLED) {
return false;
}
- if ((but->type == UI_BTYPE_TEXT) && (but->dt == UI_EMBOSS_NONE) && !labeledit) {
+ if ((but->type == UI_BTYPE_TEXT) && (but->emboss == UI_EMBOSS_NONE) && !labeledit) {
return false;
}
if ((but->type == UI_BTYPE_LISTROW) && labeledit) {
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 46814e11b9e..7c64e4c2709 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -433,7 +433,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
expr_result = BLI_strdup(has_valid_context_error);
}
- else if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
+ else if (BPY_execute_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
if (STREQ(expr_result, "")) {
MEM_freeN(expr_result);
expr_result = NULL;
@@ -490,7 +490,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
expr_result = BLI_strdup(has_valid_context_error);
}
- else if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
+ else if (BPY_execute_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
if (STREQ(expr_result, ".")) {
MEM_freeN(expr_result);
expr_result = NULL;
@@ -594,7 +594,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
shortcut = BLI_strdup(has_valid_context_error);
}
- else if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
+ else if (BPY_execute_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) {
if (expr_result != 0) {
wmKeyMap *keymap = (wmKeyMap *)expr_result;
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
@@ -659,7 +659,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
/* pass */
}
else if (BPY_execute_string_as_string_and_size(
- C, expr_imports, expr, true, &expr_result, &expr_result_len)) {
+ C, expr_imports, expr, __func__, &expr_result, &expr_result_len)) {
/* pass. */
}
}
@@ -736,7 +736,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
/* pass */
}
- else if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
+ else if (BPY_execute_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) {
if (expr_result != 0) {
{
uiTooltipField *field = text_field_add(data,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index c9c460c6a72..62e53513927 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1356,7 +1356,7 @@ static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
static int ui_but_draw_menu_icon(const uiBut *but)
{
- return (but->flag & UI_BUT_ICON_SUBMENU) && (but->dt == UI_EMBOSS_PULLDOWN);
+ return (but->flag & UI_BUT_ICON_SUBMENU) && (but->emboss == UI_EMBOSS_PULLDOWN);
}
/* icons have been standardized... and this call draws in untransformed coordinates */
@@ -1417,7 +1417,7 @@ static void widget_draw_icon(
but->str && but->str[0] == '\0') {
xs = rect->xmin + 2.0f * ofs;
}
- else if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL) {
+ else if (but->emboss == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL) {
xs = rect->xmin + 2.0f * ofs;
}
else {
@@ -2375,7 +2375,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
/* pass (even if its a menu toolbar) */
}
else if (ui_block_is_pie_menu(but->block)) {
- if (but->dt == UI_EMBOSS_RADIAL) {
+ if (but->emboss == UI_EMBOSS_RADIAL) {
rect->xmin += 0.3f * U.widget_unit;
}
}
@@ -4501,7 +4501,7 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
uiWidgetType *wt = NULL;
/* handle menus separately */
- if (but->dt == UI_EMBOSS_PULLDOWN) {
+ if (but->emboss == UI_EMBOSS_PULLDOWN) {
switch (but->type) {
case UI_BTYPE_LABEL:
widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
@@ -4514,7 +4514,7 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
break;
}
}
- else if (but->dt == UI_EMBOSS_NONE) {
+ else if (but->emboss == UI_EMBOSS_NONE) {
/* "nothing" */
switch (but->type) {
case UI_BTYPE_LABEL:
@@ -4525,11 +4525,11 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
break;
}
}
- else if (but->dt == UI_EMBOSS_RADIAL) {
+ else if (but->emboss == UI_EMBOSS_RADIAL) {
wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
}
else {
- BLI_assert(but->dt == UI_EMBOSS);
+ BLI_assert(but->emboss == UI_EMBOSS);
switch (but->type) {
case UI_BTYPE_LABEL:
@@ -4778,7 +4778,7 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
}
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
- if (but->dt != UI_EMBOSS_PULLDOWN) {
+ if (but->emboss != UI_EMBOSS_PULLDOWN) {
disabled = true;
}
}
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 3786ed2789c..12ce358a501 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -753,8 +753,7 @@ void ED_mask_draw_region(
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(
- &state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL);
+ immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GL_R16F, false, buffer, 1.0f, 1.0f, NULL);
GPU_matrix_pop();
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 347f6806d13..1f411617c68 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1628,9 +1628,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
plane_from_point_normal_v3(plane, v1, plane);
}
- /* First use bvh tree to find faces, knife edges, and knife verts that might
+ /* First use BVH tree to find faces, knife edges, and knife verts that might
* intersect the cut plane with rays v1-v3 and v2-v4.
- * This deduplicates the candidates before doing more expensive intersection tests. */
+ * This de-duplicates the candidates before doing more expensive intersection tests. */
tree = BKE_bmbvh_tree_get(kcd->bmbvh);
results = BLI_bvhtree_intersect_plane(tree, plane, &tot);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 1ea25353598..d2e9b57e950 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -205,7 +205,7 @@ static BMElem *edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint
/* -------------------------------------------------------------------- */
/** \name Find Nearest Vert/Edge/Face
*
- * \note Screen-space manhatten distances are used here,
+ * \note Screen-space manhattan distances are used here,
* since its faster and good enough for the purpose of selection.
*
* \note \a dist_bias is used so we can bias against selected items.
@@ -415,7 +415,7 @@ struct NearestEdgeUserData_Hit {
int index;
BMEdge *edge;
- /* edges only, un-biased manhatten distance to which ever edge we pick
+ /* edges only, un-biased manhattan distance to which ever edge we pick
* (not used for choosing) */
float dist_center;
};
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index baa24ab2f4e..ae1aae27b7f 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -60,8 +60,6 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "GPU_draw.h" /* GPU_free_image */
-
#include "WM_api.h"
#include "WM_types.h"
@@ -530,7 +528,7 @@ static void multiresbake_freejob(void *bkv)
/* delete here, since this delete will be called from main thread */
for (link = data->images.first; link; link = link->next) {
Image *ima = (Image *)link->data;
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
}
MEM_freeN(data->ob_image.array);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index c4cb21a67f3..926a47b1ec8 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -68,8 +68,6 @@
#include "ED_screen.h"
#include "ED_uvedit.h"
-#include "GPU_draw.h"
-
#include "object_intern.h"
/* prototypes */
@@ -308,7 +306,7 @@ static void refresh_images(BakeImages *bake_images)
Image *ima = bake_images->data[i].image;
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
if (tile->ok == IMA_OK_LOADED) {
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
DEG_id_tag_update(&ima->id, 0);
break;
}
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 8981851394d..28f58a34814 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -72,7 +72,6 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 673df69bf9b..3d3936523f9 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -79,7 +79,6 @@
#include "RNA_define.h"
#include "GPU_framebuffer.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "render_intern.h"
@@ -351,7 +350,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
G.f &= ~G_FLAG_RENDER_VIEWPORT;
gp_rect = MEM_mallocN(sizex * sizey * sizeof(uchar) * 4, "offscreen rect");
- GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
+ GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UNSIGNED_BYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 19e4f652963..85fc6927063 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -82,7 +82,6 @@
#include "BIF_glutil.h"
-#include "GPU_glew.h"
#include "GPU_shader.h"
#include "RE_engine.h"
@@ -632,18 +631,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- fx,
- fy,
- rres.rectx,
- rres.recty,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
- rect_byte,
- 1.0f,
- 1.0f,
- NULL);
+ immDrawPixelsTex(
+ &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL);
MEM_freeN(rect_byte);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 5c3b1944164..07a122c7094 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -95,9 +95,8 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float scaleX,
float scaleY,
@@ -115,21 +114,30 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y));
float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- if (type != GL_FLOAT) {
- BLI_assert(type == GL_UNSIGNED_BYTE);
- type = GL_UNSIGNED_BYTE;
+ if (ELEM(gpu_format, GPU_RGBA8, GPU_RGBA16F)) {
+ components = 4;
+ }
+ else if (ELEM(gpu_format, GPU_RGB16F)) {
+ components = 3;
+ }
+ else if (ELEM(gpu_format, GPU_R8, GPU_R16F)) {
+ components = 1;
+ }
+ else {
+ BLI_assert(!"Incompatible format passed to immDrawPixels");
+ return;
}
- eGPUTextureFormat gpu_format = (type == GL_FLOAT) ? GPU_RGBA16F : GPU_RGBA8;
- eGPUDataFormat gpu_data = (type == GL_FLOAT) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
- GPUTexture *texture = GPU_texture_create_nD(
- tex_w, tex_h, 0, 2, NULL, gpu_format, gpu_data, 0, false, NULL);
+ const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
+ eGPUDataFormat gpu_data = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
+ size_t stride = components * ((use_float_data) ? sizeof(float) : sizeof(uchar));
- /* TODO replace GL_NEAREST/LINEAR in callers. */
- GPU_texture_filter_mode(texture, (zoomfilter == GL_LINEAR));
- GPU_texture_wrap_mode(texture, false, true);
+ GPUTexture *tex = GPU_texture_create_2d(tex_w, tex_h, gpu_format, NULL, NULL);
- GPU_texture_bind(texture, 0);
+ GPU_texture_filter_mode(tex, use_filter);
+ GPU_texture_wrap_mode(tex, false, true);
+
+ GPU_texture_bind(tex, 0);
/* setup seamless 2=on, 0=off */
seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0;
@@ -140,20 +148,6 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
nsubparts_x = (img_w + (offset_x - 1)) / (offset_x);
nsubparts_y = (img_h + (offset_y - 1)) / (offset_y);
- if (format == GL_RGBA) {
- components = 4;
- }
- else if (format == GL_RGB) {
- components = 3;
- }
- else if (format == GL_RED) {
- components = 1;
- }
- else {
- BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled");
- return;
- }
-
/* optional */
/* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
* it does not need color.
@@ -199,26 +193,32 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
{
int src_y = subpart_y * offset_y;
int src_x = subpart_x * offset_x;
- size_t stride = components * ((type == GL_FLOAT) ? sizeof(float) : sizeof(uchar));
#define DATA(_y, _x) ((char *)rect + stride * ((size_t)(_y)*img_w + (_x)))
{
void *data = DATA(src_y, src_x);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, type, data);
+ GPU_texture_update_sub(tex, gpu_data, data, 0, 0, 0, subpart_w, subpart_h, 0);
}
/* Add an extra border of pixels so linear interpolation looks ok
* at edges of full image. */
if (subpart_w < tex_w) {
void *data = DATA(src_y, src_x + subpart_w - 1);
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, type, data);
+ int offset[2] = {subpart_w, 0};
+ int extent[2] = {1, subpart_h};
+ GPU_texture_update_sub(tex, gpu_data, data, UNPACK2(offset), 0, UNPACK2(extent), 0);
}
if (subpart_h < tex_h) {
void *data = DATA(src_y + subpart_h - 1, src_x);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, type, data);
+ int offset[2] = {0, subpart_h};
+ int extent[2] = {subpart_w, 1};
+ GPU_texture_update_sub(tex, gpu_data, data, UNPACK2(offset), 0, UNPACK2(extent), 0);
}
+
if (subpart_w < tex_w && subpart_h < tex_h) {
void *data = DATA(src_y + subpart_h - 1, src_x + subpart_w - 1);
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, type, data);
+ int offset[2] = {subpart_w, subpart_h};
+ int extent[2] = {1, 1};
+ GPU_texture_update_sub(tex, gpu_data, data, UNPACK2(offset), 0, UNPACK2(extent), 0);
}
#undef DATA
}
@@ -253,8 +253,8 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
immUnbindProgram();
}
- GPU_texture_unbind(texture);
- GPU_texture_free(texture);
+ GPU_texture_unbind(tex);
+ GPU_texture_free(tex);
/* Restore default. */
GPU_unpack_row_length_set(0);
@@ -265,9 +265,8 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float scaleX,
float scaleY,
@@ -280,9 +279,8 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
y,
img_w,
img_h,
- format,
- type,
- zoomfilter,
+ gpu_format,
+ use_filter,
rect,
scaleX,
scaleY,
@@ -300,9 +298,8 @@ void immDrawPixelsTex(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float xzoom,
float yzoom,
@@ -313,9 +310,8 @@ void immDrawPixelsTex(IMMDrawPixelsTexState *state,
y,
img_w,
img_h,
- format,
- type,
- zoomfilter,
+ gpu_format,
+ use_filter,
rect,
1.0f,
1.0f,
@@ -333,9 +329,8 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
float y,
int img_w,
int img_h,
- int format,
- int type,
- int zoomfilter,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
void *rect,
float clip_min_x,
float clip_min_y,
@@ -350,9 +345,8 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
y,
img_w,
img_h,
- format,
- type,
- zoomfilter,
+ gpu_format,
+ use_filter,
rect,
1.0f,
1.0f,
@@ -371,7 +365,7 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
void ED_draw_imbuf_clipping(ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
ColorManagedViewSettings *view_settings,
ColorManagedDisplaySettings *display_settings,
float clip_min_x,
@@ -421,13 +415,13 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
if (ok) {
if (ibuf->rect_float) {
- int format = 0;
+ eGPUTextureFormat format = 0;
if (ibuf->channels == 3) {
- format = GL_RGB;
+ format = GPU_RGB16F;
}
else if (ibuf->channels == 4) {
- format = GL_RGBA;
+ format = GPU_RGBA16F;
}
else {
BLI_assert(!"Incompatible number of channels for GLSL display");
@@ -440,8 +434,7 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
ibuf->x,
ibuf->y,
format,
- GL_FLOAT,
- zoomfilter,
+ use_filter,
ibuf->rect_float,
clip_min_x,
clip_min_y,
@@ -459,9 +452,8 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
y,
ibuf->x,
ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- zoomfilter,
+ GPU_RGBA8,
+ use_filter,
ibuf->rect,
clip_min_x,
clip_min_y,
@@ -493,9 +485,8 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
y,
ibuf->x,
ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- zoomfilter,
+ GPU_RGBA8,
+ use_filter,
display_buffer,
clip_min_x,
clip_min_y,
@@ -513,7 +504,7 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
void ED_draw_imbuf(ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
ColorManagedViewSettings *view_settings,
ColorManagedDisplaySettings *display_settings,
float zoom_x,
@@ -522,7 +513,7 @@ void ED_draw_imbuf(ImBuf *ibuf,
ED_draw_imbuf_clipping(ibuf,
x,
y,
- zoomfilter,
+ use_filter,
view_settings,
display_settings,
0.0f,
@@ -537,7 +528,7 @@ void ED_draw_imbuf_ctx_clipping(const bContext *C,
ImBuf *ibuf,
float x,
float y,
- int zoomfilter,
+ bool use_filter,
float clip_min_x,
float clip_min_y,
float clip_max_x,
@@ -553,7 +544,7 @@ void ED_draw_imbuf_ctx_clipping(const bContext *C,
ED_draw_imbuf_clipping(ibuf,
x,
y,
- zoomfilter,
+ use_filter,
view_settings,
display_settings,
clip_min_x,
@@ -565,9 +556,9 @@ void ED_draw_imbuf_ctx_clipping(const bContext *C,
}
void ED_draw_imbuf_ctx(
- const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter, float zoom_x, float zoom_y)
+ const bContext *C, ImBuf *ibuf, float x, float y, bool use_filter, float zoom_x, float zoom_y)
{
- ED_draw_imbuf_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y);
+ ED_draw_imbuf_ctx_clipping(C, ibuf, x, y, use_filter, 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y);
}
int ED_draw_imbuf_method(ImBuf *ibuf)
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 7983ac889ef..c17a34f97b9 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -475,7 +475,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
CTX_data_id_pointer_set(result, &obpose->id);
}
return 1;
- return -1; /* found but not available */
}
if (CTX_data_equals(member, "sequences")) {
Editing *ed = BKE_sequencer_editing_get(scene, false);
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 1608e842376..40a452a5363 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -619,7 +619,7 @@ void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uin
screen_preview_draw(screen, size_x, size_y);
- GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, r_rect);
+ GPU_offscreen_read_pixels(offscreen, GPU_DATA_UNSIGNED_BYTE, r_rect);
GPU_offscreen_unbind(offscreen, true);
GPU_offscreen_free(offscreen);
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index d0082769575..da39fbcf0ce 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -56,7 +56,6 @@
#include "DEG_depsgraph.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 7ee3d991eb7..34c9cac67c8 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -74,7 +74,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -182,7 +181,7 @@ void imapaint_image_update(
int h = imapaintpartial.y2 - imapaintpartial.y1;
if (w && h) {
/* Testing with partial update in uv editor too */
- GPU_paint_update_image(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
+ BKE_image_update_gputexture(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
}
}
}
@@ -1164,9 +1163,9 @@ void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob
BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
if (U.glreslimit != 0) {
- GPU_free_images(bmain);
+ BKE_image_free_all_gputextures(bmain);
}
- GPU_paint_set_mipmap(bmain, 0);
+ BKE_image_paint_set_mipmap(bmain, 0);
toggle_paint_cursor(scene, true);
@@ -1189,9 +1188,9 @@ void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob)
ob->mode &= ~OB_MODE_TEXTURE_PAINT;
if (U.glreslimit != 0) {
- GPU_free_images(bmain);
+ BKE_image_free_all_gputextures(bmain);
}
- GPU_paint_set_mipmap(bmain, 1);
+ BKE_image_paint_set_mipmap(bmain, 1);
toggle_paint_cursor(scene, false);
Mesh *me = BKE_mesh_from_object(ob);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index a7f09390a3d..6d588d1450b 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -57,8 +57,6 @@
#include "UI_view2d.h"
-#include "GPU_draw.h"
-
#include "paint_intern.h"
/* Brush Painting for 2D image editor */
@@ -1784,7 +1782,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
if (final) {
if (s->image && !(s->sima && s->sima->lock)) {
- GPU_free_image(s->image);
+ BKE_image_free_gputextures(s->image);
}
/* compositor listener deals with updating */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 5af3a3f4241..5991032536b 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -100,8 +100,6 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "GPU_draw.h"
-
#include "IMB_colormanagement.h"
//#include "bmesh_tools.h"
@@ -6134,7 +6132,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
project_image_refresh_tagged(&ps);
for (a = 0; a < ps.image_tot; a++) {
- GPU_free_image(ps.projImages[a].ima);
+ BKE_image_free_gputextures(ps.projImages[a].ima);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 92beb396629..2c110e23ac0 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -196,7 +196,7 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
}
}
-static const float *sculpt_vertex_persistent_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index)
{
if (ss->persistent_base) {
return ss->persistent_base[index].co;
@@ -204,7 +204,7 @@ static const float *sculpt_vertex_persistent_co_get(SculptSession *ss, int index
return SCULPT_vertex_co_get(ss, index);
}
-static void sculpt_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3])
{
if (ss->persistent_base) {
copy_v3_v3(no, ss->persistent_base[index].no);
@@ -4341,9 +4341,9 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
float normal[3];
if (use_persistent_base) {
- sculpt_vertex_persistent_normal_get(ss, vi, normal);
+ SCULPT_vertex_persistent_normal_get(ss, vi, normal);
mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, sculpt_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
+ madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
}
else {
normal_short_to_float_v3(normal, orig_data.no);
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 4232be91034..39cab883100 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -85,7 +85,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
@@ -113,19 +112,8 @@ static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_s
return BLI_edgeset_haskey(cloth_sim->created_length_constraints, v1, v2);
}
-static void cloth_brush_add_length_constraint(SculptSession *ss,
- SculptClothSimulation *cloth_sim,
- const int v1,
- const int v2)
+static void cloth_brush_reallocate_constraints(SculptClothSimulation *cloth_sim)
{
- cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v1 = v1;
- cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v2 = v2;
- cloth_sim->length_constraints[cloth_sim->tot_length_constraints].length = len_v3v3(
- SCULPT_vertex_co_get(ss, v1), SCULPT_vertex_co_get(ss, v2));
-
- cloth_sim->tot_length_constraints++;
-
- /* Reallocation if the array capacity is exceeded. */
if (cloth_sim->tot_length_constraints >= cloth_sim->capacity_length_constraints) {
cloth_sim->capacity_length_constraints += CLOTH_LENGTH_CONSTRAINTS_BLOCK;
cloth_sim->length_constraints = MEM_reallocN_id(cloth_sim->length_constraints,
@@ -133,23 +121,112 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
sizeof(SculptClothLengthConstraint),
"length constraints");
}
+}
+
+static void cloth_brush_add_length_constraint(SculptSession *ss,
+ SculptClothSimulation *cloth_sim,
+ const int v1,
+ const int v2,
+ const bool use_persistent)
+{
+ SculptClothLengthConstraint *length_constraint =
+ &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
+
+ length_constraint->elem_index_a = v1;
+ length_constraint->elem_index_b = v2;
+
+ length_constraint->elem_position_a = cloth_sim->pos[v1];
+ length_constraint->elem_position_b = cloth_sim->pos[v2];
+
+ if (use_persistent) {
+ length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1),
+ SCULPT_vertex_persistent_co_get(ss, v2));
+ }
+ else {
+ length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1),
+ SCULPT_vertex_co_get(ss, v2));
+ }
+ length_constraint->strength = 1.0f;
+
+ cloth_sim->tot_length_constraints++;
+
+ /* Reallocation if the array capacity is exceeded. */
+ cloth_brush_reallocate_constraints(cloth_sim);
/* Add the constraint to the GSet to avoid creating it again. */
BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2);
}
+static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim,
+ const int v,
+ const float strength)
+{
+ SculptClothLengthConstraint *length_constraint =
+ &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
+
+ length_constraint->elem_index_a = v;
+ length_constraint->elem_index_b = v;
+
+ length_constraint->elem_position_a = cloth_sim->pos[v];
+ length_constraint->elem_position_b = cloth_sim->init_pos[v];
+
+ length_constraint->length = 0.0f;
+ length_constraint->strength = strength;
+
+ cloth_sim->tot_length_constraints++;
+
+ /* Reallocation if the array capacity is exceeded. */
+ cloth_brush_reallocate_constraints(cloth_sim);
+}
+
+static void cloth_brush_add_deformation_constraint(SculptClothSimulation *cloth_sim,
+ const int v,
+ const float strength)
+{
+ SculptClothLengthConstraint *length_constraint =
+ &cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
+
+ length_constraint->elem_index_a = v;
+ length_constraint->elem_index_b = v;
+
+ length_constraint->elem_position_a = cloth_sim->pos[v];
+ length_constraint->elem_position_b = cloth_sim->deformation_pos[v];
+
+ length_constraint->length = 0.0f;
+ length_constraint->strength = strength;
+
+ cloth_sim->tot_length_constraints++;
+
+ /* Reallocation if the array capacity is exceeded. */
+ cloth_brush_reallocate_constraints(cloth_sim);
+}
+
static void do_cloth_brush_build_constraints_task_cb_ex(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
PBVHVertexIter vd;
+ const bool use_persistent = brush != NULL && brush->flag & BRUSH_PERSISTENT;
+
+ /* Brush can be NULL in tools that use the solver without relying of constraints with deformation
+ * positions. */
+ const bool cloth_is_deform_brush = ss->cache != NULL && brush != NULL &&
+ SCULPT_is_cloth_deform_brush(brush);
+ float radius_squared = 0.0f;
+ if (cloth_is_deform_brush) {
+ radius_squared = ss->cache->initial_radius * ss->cache->initial_radius;
+ }
+
+ const float cloth_sim_radius_squared = data->cloth_sim_radius * data->cloth_sim_radius;
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (len_squared_v3v3(vd.co, data->cloth_sim_initial_location) <
- data->cloth_sim_radius * data->cloth_sim_radius) {
+ const float len_squared = len_squared_v3v3(vd.co, data->cloth_sim_initial_location);
+ if (len_squared < cloth_sim_radius_squared) {
SculptVertexNeighborIter ni;
int build_indices[CLOTH_MAX_CONSTRAINTS_PER_VERTEX];
@@ -162,6 +239,11 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ if (brush->cloth_constraint_softbody_strength > 0.0f) {
+ cloth_brush_add_softbody_constraint(
+ data->cloth_sim, vd.index, brush->cloth_constraint_softbody_strength);
+ }
+
/* As we don't know the order of the neighbor vertices, we create all possible combinations
* between the neighbor and the original vertex as length constraints. */
/* This results on a pattern that contains structural, shear and bending constraints for all
@@ -172,11 +254,16 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
if (c_i != c_j && !cloth_brush_sim_has_length_constraint(
data->cloth_sim, build_indices[c_i], build_indices[c_j])) {
cloth_brush_add_length_constraint(
- ss, data->cloth_sim, build_indices[c_i], build_indices[c_j]);
+ ss, data->cloth_sim, build_indices[c_i], build_indices[c_j], use_persistent);
}
}
}
}
+
+ if (cloth_is_deform_brush && len_squared < radius_squared) {
+ const float fade = BKE_brush_curve_strength(brush, sqrtf(len_squared), ss->cache->radius);
+ cloth_brush_add_deformation_constraint(data->cloth_sim, vd.index, fade);
+ }
}
BKE_pbvh_vertex_iter_end;
}
@@ -323,9 +410,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, offset, -fade);
break;
case BRUSH_CLOTH_DEFORM_GRAB:
- /* Grab writes the positions in the simulation directly without applying forces. */
- madd_v3_v3v3fl(
- cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade);
+ madd_v3_v3v3fl(cloth_sim->deformation_pos[vd.index],
+ orig_data.co,
+ ss->cache->grab_delta_symmetry,
+ fade);
zero_v3(force);
break;
case BRUSH_CLOTH_DEFORM_PINCH_POINT:
@@ -367,6 +455,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
}
static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
+ Brush *brush,
const float cloth_mass,
const float cloth_damping)
{
@@ -380,12 +469,20 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
"cloth length constraints");
cloth_sim->capacity_length_constraints = CLOTH_LENGTH_CONSTRAINTS_BLOCK;
- cloth_sim->acceleration = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim acceleration");
- cloth_sim->pos = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim pos");
- cloth_sim->prev_pos = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim prev pos");
- cloth_sim->init_pos = MEM_callocN(sizeof(float) * 3 * totverts, "cloth sim init pos");
- cloth_sim->length_constraint_tweak = MEM_callocN(sizeof(float) * totverts,
- "cloth sim length tweak");
+ cloth_sim->acceleration = MEM_calloc_arrayN(
+ totverts, 3 * sizeof(float), "cloth sim acceleration");
+ cloth_sim->pos = MEM_calloc_arrayN(totverts, 3 * sizeof(float), "cloth sim pos");
+ cloth_sim->prev_pos = MEM_calloc_arrayN(totverts, 3 * sizeof(float), "cloth sim prev pos");
+ cloth_sim->init_pos = MEM_calloc_arrayN(totverts, 3 * sizeof(float), "cloth sim init pos");
+ cloth_sim->length_constraint_tweak = MEM_calloc_arrayN(
+ totverts, sizeof(float), "cloth sim length tweak");
+
+ /* Brush can be NULL for tools that neeed the solver but don't rely on constraint to deformation
+ * positions. */
+ if (brush && SCULPT_is_cloth_deform_brush(brush)) {
+ cloth_sim->deformation_pos = MEM_calloc_arrayN(
+ totverts, 3 * sizeof(float), "cloth sim deformation positions");
+ }
cloth_sim->mass = cloth_mass;
cloth_sim->damping = cloth_damping;
@@ -484,11 +581,11 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
for (int i = 0; i < cloth_sim->tot_length_constraints; i++) {
const SculptClothLengthConstraint *constraint = &cloth_sim->length_constraints[i];
- const int v1 = constraint->v1;
- const int v2 = constraint->v2;
+ const int v1 = constraint->elem_index_a;
+ const int v2 = constraint->elem_index_b;
float v1_to_v2[3];
- sub_v3_v3v3(v1_to_v2, cloth_sim->pos[v2], cloth_sim->pos[v1]);
+ sub_v3_v3v3(v1_to_v2, constraint->elem_position_b, constraint->elem_position_a);
const float current_distance = len_v3(v1_to_v2);
float correction_vector[3];
float correction_vector_half[3];
@@ -524,8 +621,14 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
cloth_sim->init_pos[v2]) :
1.0f;
- madd_v3_v3fl(cloth_sim->pos[v1], correction_vector_half, 1.0f * mask_v1 * sim_factor_v1);
- madd_v3_v3fl(cloth_sim->pos[v2], correction_vector_half, -1.0f * mask_v2 * sim_factor_v2);
+ madd_v3_v3fl(cloth_sim->pos[v1],
+ correction_vector_half,
+ 1.0f * mask_v1 * sim_factor_v1 * constraint->strength);
+ if (v1 != v2) {
+ madd_v3_v3fl(cloth_sim->pos[v2],
+ correction_vector_half,
+ -1.0f * mask_v2 * sim_factor_v2 * constraint->strength);
+ }
}
}
}
@@ -649,10 +752,16 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* The simulation structure only needs to be created on the first symmetry pass. */
if (SCULPT_stroke_is_first_brush_step(ss->cache) || !ss->cache->cloth_sim) {
ss->cache->cloth_sim = cloth_brush_simulation_create(
- ss, brush->cloth_mass, brush->cloth_damping);
+ ss, brush, brush->cloth_mass, brush->cloth_damping);
+
+ const bool is_cloth_deform_brush = SCULPT_is_cloth_deform_brush(brush);
+
for (int i = 0; i < totverts; i++) {
copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
+ if (is_cloth_deform_brush) {
+ copy_v3_v3(ss->cache->cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
+ }
}
}
@@ -684,6 +793,7 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
MEM_SAFE_FREE(cloth_sim->acceleration);
MEM_SAFE_FREE(cloth_sim->length_constraints);
MEM_SAFE_FREE(cloth_sim->length_constraint_tweak);
+ MEM_SAFE_FREE(cloth_sim->deformation_pos);
MEM_SAFE_FREE(cloth_sim->init_pos);
MEM_SAFE_FREE(cloth_sim);
}
@@ -913,7 +1023,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
- ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, cloth_mass, cloth_damping);
+ ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, NULL, cloth_mass, cloth_damping);
copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));
const int totverts = SCULPT_vertex_count_get(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 59d82825740..878a08ceeb7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -80,7 +80,7 @@ typedef enum eSculptColorFilterTypes {
COLOR_FILTER_SMOOTH,
} eSculptColorFilterTypes;
-EnumPropertyItem prop_color_filter_types[] = {
+static EnumPropertyItem prop_color_filter_types[] = {
{COLOR_FILTER_FILL, "FILL", 0, "Fill", "Fill with a specific color"},
{COLOR_FILTER_HUE, "HUE", 0, "Hue", "Change hue"},
{COLOR_FILTER_SATURATION, "SATURATION", 0, "Saturation", "Change saturation"},
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index f834ab7b179..47e6fb55d81 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -98,6 +98,9 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
+
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
/* Storage */
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index b52036d753c..bc3f8537289 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -47,7 +47,6 @@
#include "paint_intern.h"
#include "sculpt_intern.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 16256f6c97e..5885d3dcbb0 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -101,7 +101,7 @@ static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
/************************* Creating the Path ************************/
-static int buttons_context_path_scene(ButsContextPath *path)
+static bool buttons_context_path_scene(ButsContextPath *path)
{
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -162,14 +162,14 @@ static int buttons_context_path_world(ButsContextPath *path)
return 0;
}
-static int buttons_context_path_linestyle(ButsContextPath *path, wmWindow *window)
+static bool buttons_context_path_linestyle(ButsContextPath *path, wmWindow *window)
{
FreestyleLineStyle *linestyle;
PointerRNA *ptr = &path->ptr[path->len - 1];
/* if we already have a (pinned) linestyle, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_FreestyleLineStyle)) {
- return 1;
+ return true;
}
/* if we have a view layer, use the lineset's linestyle */
if (buttons_context_path_view_layer(path, window)) {
@@ -178,24 +178,24 @@ static int buttons_context_path_linestyle(ButsContextPath *path, wmWindow *windo
if (linestyle) {
RNA_id_pointer_create(&linestyle->id, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
/* no path to a linestyle possible */
- return 0;
+ return false;
}
-static int buttons_context_path_object(ButsContextPath *path)
+static bool buttons_context_path_object(ButsContextPath *path)
{
PointerRNA *ptr = &path->ptr[path->len - 1];
/* if we already have a (pinned) object, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Object)) {
- return 1;
+ return true;
}
if (!RNA_struct_is_a(ptr->type, &RNA_ViewLayer)) {
- return 0;
+ return false;
}
ViewLayer *view_layer = ptr->data;
@@ -205,58 +205,58 @@ static int buttons_context_path_object(ButsContextPath *path)
RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
/* no path to a object possible */
- return 0;
+ return false;
}
-static int buttons_context_path_data(ButsContextPath *path, int type)
+static bool buttons_context_path_data(ButsContextPath *path, int type)
{
Object *ob;
PointerRNA *ptr = &path->ptr[path->len - 1];
/* if we already have a data, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Curve) &&
(type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Light) && (type == -1 || type == OB_LAMP)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (type == -1 || type == OB_LIGHTPROBE)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Hair) && (type == -1 || type == OB_HAIR)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (type == -1 || type == OB_POINTCLOUD)) {
- return 1;
+ return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (type == -1 || type == OB_VOLUME)) {
- return 1;
+ return true;
}
/* try to get an object in the path, no pinning supported here */
if (buttons_context_path_object(path)) {
@@ -266,15 +266,15 @@ static int buttons_context_path_data(ButsContextPath *path, int type)
RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
/* no path to data possible */
- return 0;
+ return false;
}
-static int buttons_context_path_modifier(ButsContextPath *path)
+static bool buttons_context_path_modifier(ButsContextPath *path)
{
Object *ob;
@@ -291,14 +291,14 @@ static int buttons_context_path_modifier(ButsContextPath *path)
OB_HAIR,
OB_POINTCLOUD,
OB_VOLUME)) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
-static int buttons_context_path_shaderfx(ButsContextPath *path)
+static bool buttons_context_path_shaderfx(ButsContextPath *path)
{
Object *ob;
@@ -306,14 +306,14 @@ static int buttons_context_path_shaderfx(ButsContextPath *path)
ob = path->ptr[path->len - 1].data;
if (ob && ELEM(ob->type, OB_GPENCIL)) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
-static int buttons_context_path_material(ButsContextPath *path)
+static bool buttons_context_path_material(ButsContextPath *path)
{
Object *ob;
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -321,7 +321,7 @@ static int buttons_context_path_material(ButsContextPath *path)
/* if we already have a (pinned) material, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Material)) {
- return 1;
+ return true;
}
/* if we have an object, use the object material slot */
if (buttons_context_path_object(path)) {
@@ -331,15 +331,15 @@ static int buttons_context_path_material(ButsContextPath *path)
ma = BKE_object_material_get(ob, ob->actcol);
RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
/* no path to a material possible */
- return 0;
+ return false;
}
-static int buttons_context_path_bone(ButsContextPath *path)
+static bool buttons_context_path_bone(ButsContextPath *path)
{
bArmature *arm;
EditBone *edbo;
@@ -353,29 +353,29 @@ static int buttons_context_path_bone(ButsContextPath *path)
edbo = arm->act_edbone;
RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
else {
if (arm->act_bone) {
RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
}
/* no path to a bone possible */
- return 0;
+ return false;
}
-static int buttons_context_path_pose_bone(ButsContextPath *path)
+static bool buttons_context_path_pose_bone(ButsContextPath *path)
{
PointerRNA *ptr = &path->ptr[path->len - 1];
/* if we already have a (pinned) PoseBone, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
- return 1;
+ return true;
}
/* if we have an armature, get the active bone */
@@ -384,7 +384,7 @@ static int buttons_context_path_pose_bone(ButsContextPath *path)
bArmature *arm = ob->data; /* path->ptr[path->len-1].data - works too */
if (ob->type != OB_ARMATURE || arm->edbo) {
- return 0;
+ return false;
}
if (arm->act_bone) {
@@ -392,16 +392,16 @@ static int buttons_context_path_pose_bone(ButsContextPath *path)
if (pchan) {
RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
}
/* no path to a bone possible */
- return 0;
+ return false;
}
-static int buttons_context_path_particle(ButsContextPath *path)
+static bool buttons_context_path_particle(ButsContextPath *path)
{
Object *ob;
ParticleSystem *psys;
@@ -409,7 +409,7 @@ static int buttons_context_path_particle(ButsContextPath *path)
/* if we already have (pinned) particle settings, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_ParticleSettings)) {
- return 1;
+ return true;
}
/* if we have an object, get the active particle system */
if (buttons_context_path_object(path)) {
@@ -420,15 +420,15 @@ static int buttons_context_path_particle(ButsContextPath *path)
RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
/* no path to a particle system possible */
- return 0;
+ return false;
}
-static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
+static bool buttons_context_path_brush(const bContext *C, ButsContextPath *path)
{
Scene *scene;
Brush *br = NULL;
@@ -436,7 +436,7 @@ static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
/* if we already have a (pinned) brush, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Brush)) {
- return 1;
+ return true;
}
/* if we have a scene, use the toolsettings brushes */
if (buttons_context_path_scene(path)) {
@@ -452,32 +452,32 @@ static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
path->len++;
- return 1;
+ return true;
}
}
/* no path to a brush possible */
- return 0;
+ return false;
}
-static int buttons_context_path_texture(const bContext *C,
- ButsContextPath *path,
- ButsContextTexture *ct)
+static bool buttons_context_path_texture(const bContext *C,
+ ButsContextPath *path,
+ ButsContextTexture *ct)
{
PointerRNA *ptr = &path->ptr[path->len - 1];
ID *id;
if (!ct) {
- return 0;
+ return false;
}
/* if we already have a (pinned) texture, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Texture)) {
- return 1;
+ return true;
}
if (!ct->user) {
- return 0;
+ return false;
}
id = ct->user->id;
@@ -502,7 +502,7 @@ static int buttons_context_path_texture(const bContext *C,
path->len++;
}
- return 1;
+ return true;
}
#ifdef WITH_FREESTYLE
@@ -531,7 +531,7 @@ static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *vie
}
#endif
-static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
+static bool buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
{
/* Note we don't use CTX_data here, instead we get it from the window.
* Otherwise there is a loop reading the context that we are setting. */
@@ -626,27 +626,27 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found = buttons_context_path_pose_bone(path);
break;
default:
- found = 0;
+ found = false;
break;
}
return found;
}
-static int buttons_shading_context(const bContext *C, int mainb)
+static bool buttons_shading_context(const bContext *C, int mainb)
{
wmWindow *window = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
Object *ob = OBACT(view_layer);
if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE)) {
- return 1;
+ return true;
}
if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA)) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static int buttons_shading_new_context(const bContext *C, int flag)
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 733f344fbc6..a062b178fc8 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -52,7 +52,9 @@
#include "buttons_intern.h" /* own include */
-/********************** context_menu operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Context Menu Operator
+ * \{ */
static int context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
@@ -67,17 +69,21 @@ static int context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
void BUTTONS_OT_context_menu(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Context Menu";
ot->description = "Display properties editor context_menu";
ot->idname = "BUTTONS_OT_context_menu";
- /* api callbacks */
+ /* Callbacks. */
ot->invoke = context_menu_invoke;
ot->poll = ED_operator_buttons_active;
}
-/********************** filebrowse operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name File Browse Operator
+ * \{ */
typedef struct FileBrowseOp {
PointerRNA ptr;
@@ -101,7 +107,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
str = RNA_string_get_alloc(op->ptr, path_prop, NULL, 0);
- /* add slash for directories, important for some properties */
+ /* Add slash for directories, important for some properties. */
if (RNA_property_subtype(fbo->prop) == PROP_DIRPATH) {
const bool is_relative = RNA_boolean_get(op->ptr, "relative_path");
id = fbo->ptr.owner_id;
@@ -110,7 +116,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
BLI_path_abs(path, id ? ID_BLEND_PATH(bmain, id) : BKE_main_blendfile_path(bmain));
if (BLI_is_dir(path)) {
- /* do this first so '//' isnt converted to '//\' on windows */
+ /* Do this first so '//' isnt converted to '//\' on windows. */
BLI_path_slash_ensure(path);
if (is_relative) {
BLI_strncpy(path, str, FILE_MAX);
@@ -139,7 +145,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
ED_undo_push(C, undostr);
}
- /* special, annoying exception, filesel on redo panel [#26618] */
+ /* Special annoying exception, filesel on redo panel [#26618]. */
{
wmOperator *redo_op = WM_operator_last_redo(C);
if (redo_op) {
@@ -187,8 +193,8 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
str = RNA_property_string_get_alloc(&ptr, prop, NULL, 0, NULL);
- /* useful yet irritating feature, Shift+Click to open the file
- * Alt+Click to browse a folder in the OS's browser */
+ /* Useful yet irritating feature, Shift+Click to open the file
+ * Alt+Click to browse a folder in the OS's browser. */
if (event->shift || event->alt) {
wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
PointerRNA props_ptr;
@@ -219,13 +225,13 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
fbo->is_userdef = is_userdef;
op->customdata = fbo;
- /* normally ED_fileselect_get_params would handle this but we need to because of stupid
- * user-prefs exception - campbell */
+ /* Normally ED_fileselect_get_params would handle this but we need to because of stupid
+ * user-prefs exception. - campbell */
if ((prop_relpath = RNA_struct_find_property(op->ptr, "relative_path"))) {
if (!RNA_property_is_set(op->ptr, prop_relpath)) {
bool is_relative = (U.flag & USER_RELPATHS) != 0;
- /* while we want to follow the defaults,
+ /* While we want to follow the defaults,
* we better not switch existing paths relative/absolute state. */
if (str[0]) {
is_relative = BLI_path_is_rel(str);
@@ -235,7 +241,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
is_relative = false;
}
- /* annoying exception!, if we're dealing with the user prefs, default relative to be off */
+ /* Annoying exception!, if we're dealing with the user prefs, default relative to be off. */
RNA_property_boolean_set(op->ptr, prop_relpath, is_relative);
}
}
@@ -250,21 +256,21 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void BUTTONS_OT_file_browse(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Accept";
ot->description =
"Open a file browser, Hold Shift to open the file, Alt to browse containing directory";
ot->idname = "BUTTONS_OT_file_browse";
- /* api callbacks */
+ /* Callbacks. */
ot->invoke = file_browse_invoke;
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
- /* conditional undo based on button flag */
+ /* Conditional undo based on button flag. */
ot->flag = 0;
- /* properties */
+ /* Properties. */
WM_operator_properties_filesel(ot,
0,
FILE_SPECIAL,
@@ -274,7 +280,7 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/* second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY */
+/* Second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY. */
void BUTTONS_OT_directory_browse(wmOperatorType *ot)
{
/* identifiers */
@@ -300,3 +306,5 @@ void BUTTONS_OT_directory_browse(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
}
+
+/** \} */
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 88c2c6e82b6..67efd8f4b8e 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -35,6 +35,7 @@
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
+#include "ED_buttons.h"
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h" /* To draw toolbar UI. */
@@ -49,8 +50,6 @@
#include "UI_resources.h"
-#include "GPU_glew.h"
-
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
@@ -139,6 +138,98 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *region)
WM_event_add_keymap_handler(&region->handlers, keymap);
}
+/**
+ * Fills an array with the tab context values for the properties editor. -1 signals a separator.
+ *
+ * \return The total number of items in the array returned.
+ */
+int ED_buttons_tabs_list(SpaceProperties *sbuts, int *context_tabs_array)
+{
+ int length = 0;
+ if (sbuts->pathflag & (1 << BCONTEXT_TOOL)) {
+ context_tabs_array[length] = BCONTEXT_TOOL;
+ length++;
+ }
+ if (length != 0) {
+ context_tabs_array[length] = -1;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_RENDER)) {
+ context_tabs_array[length] = BCONTEXT_RENDER;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_OUTPUT)) {
+ context_tabs_array[length] = BCONTEXT_OUTPUT;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_VIEW_LAYER)) {
+ context_tabs_array[length] = BCONTEXT_VIEW_LAYER;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_SCENE)) {
+ context_tabs_array[length] = BCONTEXT_SCENE;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_WORLD)) {
+ context_tabs_array[length] = BCONTEXT_WORLD;
+ length++;
+ }
+ if (length != 0) {
+ context_tabs_array[length] = -1;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_OBJECT)) {
+ context_tabs_array[length] = BCONTEXT_OBJECT;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_MODIFIER)) {
+ context_tabs_array[length] = BCONTEXT_MODIFIER;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_SHADERFX)) {
+ context_tabs_array[length] = BCONTEXT_SHADERFX;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_PARTICLE)) {
+ context_tabs_array[length] = BCONTEXT_PARTICLE;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_PHYSICS)) {
+ context_tabs_array[length] = BCONTEXT_PHYSICS;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_CONSTRAINT)) {
+ context_tabs_array[length] = BCONTEXT_CONSTRAINT;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_DATA)) {
+ context_tabs_array[length] = BCONTEXT_DATA;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_BONE)) {
+ context_tabs_array[length] = BCONTEXT_BONE;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_BONE_CONSTRAINT)) {
+ context_tabs_array[length] = BCONTEXT_BONE_CONSTRAINT;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_MATERIAL)) {
+ context_tabs_array[length] = BCONTEXT_MATERIAL;
+ length++;
+ }
+ if (length != 0) {
+ context_tabs_array[length] = -1;
+ length++;
+ }
+ if (sbuts->pathflag & (1 << BCONTEXT_TEXTURE)) {
+ context_tabs_array[length] = BCONTEXT_TEXTURE;
+ length++;
+ }
+
+ return length;
+}
+
static void buttons_main_region_layout_properties(const bContext *C,
SpaceProperties *sbuts,
ARegion *region)
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index d33f624063a..1d510d2989c 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -322,7 +322,7 @@ static void draw_movieclip_buffer(const bContext *C,
float zoomy)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
- int filter = GL_LINEAR;
+ bool use_filter = true;
int x, y;
/* find window pixel coordinates of origin */
@@ -340,10 +340,10 @@ static void draw_movieclip_buffer(const bContext *C,
/* non-scaled proxy shouldn't use filtering */
if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) {
- filter = GL_NEAREST;
+ use_filter = false;
}
- ED_draw_imbuf_ctx(C, ibuf, x, y, filter, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
+ ED_draw_imbuf_ctx(C, ibuf, x, y, use_filter, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
if (ibuf->planes == 32) {
GPU_blend(false);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 9c251fb619a..37d5f602291 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -56,7 +56,6 @@
#include "IMB_imbuf.h"
#include "GPU_framebuffer.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "WM_api.h"
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 8d14664c0fa..68e9f76abc5 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -300,9 +300,8 @@ static void file_draw_preview(uiBlock *block,
(float)yco,
imb->x,
imb->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
+ GPU_RGBA8,
+ false,
imb->rect,
scale,
scale,
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index a7fa7709c51..1038011e480 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -468,20 +468,19 @@ static void sima_draw_zbuf_pixels(
float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
/* Slowwww */
- int *recti = MEM_mallocN(rectx * recty * sizeof(int), "temp");
+ float *rectf = MEM_mallocN(rectx * recty * sizeof(float), "temp");
for (int a = rectx * recty - 1; a >= 0; a--) {
/* zbuffer values are signed, so we need to shift color range */
- recti[a] = rect[a] * 0.5f + 0.5f;
+ rectf[a] = rect[a] * 0.5f + 0.5f;
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(
- &state, x1, y1, rectx, recty, GL_RED, GL_INT, GL_NEAREST, recti, zoomx, zoomy, NULL);
+ immDrawPixelsTex(&state, x1, y1, rectx, recty, GPU_R16F, false, rectf, zoomx, zoomy, NULL);
- MEM_freeN(recti);
+ MEM_freeN(rectf);
}
static void sima_draw_zbuffloat_pixels(Scene *scene,
@@ -526,8 +525,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene,
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(
- &state, x1, y1, rectx, recty, GL_RED, GL_FLOAT, GL_NEAREST, rectf, zoomx, zoomy, NULL);
+ immDrawPixelsTex(&state, x1, y1, rectx, recty, GL_R16F, false, rectf, zoomx, zoomy, NULL);
MEM_freeN(rectf);
}
@@ -612,8 +610,7 @@ static void draw_image_buffer(const bContext *C,
/* If RGBA display with color management */
if ((sima_flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B | SI_SHOW_ALPHA)) == 0) {
- ED_draw_imbuf_ctx_clipping(
- C, ibuf, x, y, GL_NEAREST, 0, 0, clip_max_x, clip_max_y, zoomx, zoomy);
+ ED_draw_imbuf_ctx_clipping(C, ibuf, x, y, false, 0, 0, clip_max_x, clip_max_y, zoomx, zoomy);
}
else {
float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -649,9 +646,8 @@ static void draw_image_buffer(const bContext *C,
y,
ibuf->x,
ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
+ GPU_RGBA8,
+ false,
display_buffer,
0,
0,
@@ -780,18 +776,8 @@ static void draw_image_paint_helpers(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
- display_buffer,
- zoomx,
- zoomy,
- col);
+ immDrawPixelsTex(
+ &state, x, y, ibuf->x, ibuf->y, GPU_RGBA8, false, display_buffer, zoomx, zoomy, col);
GPU_blend(false);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 4e410d35df0..d05fe215840 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -69,7 +69,6 @@
#include "DEG_depsgraph.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -2769,7 +2768,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
ED_image_undo_push_end();
/* force GPU reupload, all image is invalid */
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -2860,7 +2859,7 @@ static int image_scale_exec(bContext *C, wmOperator *op)
ED_image_undo_push_end();
/* force GPU reupload, all image is invalid */
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
DEG_id_tag_update(&ima->id, 0);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index e0c44c3a0ba..27b84307f7d 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -60,8 +60,6 @@
#include "ED_undo.h"
#include "ED_util.h"
-#include "GPU_draw.h"
-
#include "WM_api.h"
static CLG_LogRef LOG = {"ed.image.undo"};
@@ -295,7 +293,8 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
}
- GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */
+ BKE_image_free_gputextures(
+ image); /* force OpenGL reload (maybe partial update will operate better?) */
if (ibuf->rect_float) {
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
}
@@ -570,7 +569,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
if (changed) {
BKE_image_mark_dirty(image, ibuf);
- GPU_free_image(image); /* force OpenGL reload */
+ BKE_image_free_gputextures(image); /* force OpenGL reload */
if (ibuf->rect_float) {
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 695214bcc2f..4203eac16c4 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3676,9 +3676,8 @@ void draw_nodespace_back_pix(const bContext *C,
y,
ibuf->x,
ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
+ GPU_RGBA8,
+ false,
display_buffer,
snode->zoom,
snode->zoom,
@@ -3691,12 +3690,12 @@ void draw_nodespace_back_pix(const bContext *C,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- ED_draw_imbuf_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom);
+ ED_draw_imbuf_ctx(C, ibuf, x, y, false, snode->zoom, snode->zoom);
GPU_blend(false);
}
else {
- ED_draw_imbuf_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom);
+ ED_draw_imbuf_ctx(C, ibuf, x, y, false, snode->zoom, snode->zoom);
}
if (cache_handle) {
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 22b549cbd5d..52bd4d68649 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -947,9 +947,8 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
draw_rect.ymin,
preview->xsize,
preview->ysize,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_LINEAR,
+ GPU_RGBA8,
+ true,
preview->rect,
scale,
scale,
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 7af64e75656..3c927dbf25f 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -1697,6 +1697,8 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
}
+ do_tag_update |= ED_node_is_simulation(snode);
+
snode_notify(C, snode);
if (do_tag_update) {
snode_dag_update(C, snode);
@@ -1739,6 +1741,8 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
+ do_tag_update |= ED_node_is_simulation(snode);
+
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index e5409271f7c..0a4607d2869 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -664,6 +664,8 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
}
ntree->is_updating = false;
+ do_tag_update |= ED_node_is_simulation(snode);
+
ntreeUpdateTree(bmain, ntree);
snode_notify(C, snode);
if (do_tag_update) {
@@ -1064,6 +1066,8 @@ static int cut_links_exec(bContext *C, wmOperator *op)
}
}
+ do_tag_update |= ED_node_is_simulation(snode);
+
if (found) {
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 995e980aba0..7863d2b724d 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1599,7 +1599,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
- /* Format needs to be created prior to any immBindProgram call.
+ /* Format needs to be created prior to any immBindShader call.
* Do it here because OCIO binds it's own shader. */
eGPUTextureFormat format;
eGPUDataFormat data;
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 3fbc31d5240..8be7c7b4fb6 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -666,74 +666,6 @@ int seq_effect_find_selected(Scene *scene,
/** \name Delete Utilities
* \{ */
-static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
-{
- Sequence *seq1, *seq2, *seq3;
-
- /* Try to find a replacement input sequence, and flag for later deletion if
- * no replacement can be found. */
-
- if (!seq) {
- return NULL;
- }
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- return ((seq->flag & SELECT) ? NULL : seq);
- }
- if (!(seq->flag & SELECT)) {
- /* Try to find replacement for effect inputs. */
- seq1 = del_seq_find_replace_recurs(scene, seq->seq1);
- seq2 = del_seq_find_replace_recurs(scene, seq->seq2);
- seq3 = del_seq_find_replace_recurs(scene, seq->seq3);
-
- if (seq1 == seq->seq1 && seq2 == seq->seq2 && seq3 == seq->seq3) {
- /* Pass. */
- }
- else if (seq1 || seq2 || seq3) {
- seq->seq1 = (seq1) ? seq1 : (seq2) ? seq2 : seq3;
- seq->seq2 = (seq2) ? seq2 : (seq1) ? seq1 : seq3;
- seq->seq3 = (seq3) ? seq3 : (seq1) ? seq1 : seq2;
-
- BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1);
- }
- else {
- seq->flag |= SELECT; /* Mark for delete. */
- }
- }
-
- if (seq->flag & SELECT) {
- if ((seq1 = del_seq_find_replace_recurs(scene, seq->seq1))) {
- return seq1;
- }
- if ((seq2 = del_seq_find_replace_recurs(scene, seq->seq2))) {
- return seq2;
- }
- if ((seq3 = del_seq_find_replace_recurs(scene, seq->seq3))) {
- return seq3;
- }
- return NULL;
- }
- return seq;
-}
-
-static void del_seq_clear_modifiers_recurs(Scene *scene, Sequence *deleting_sequence)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *current_sequence;
-
- SEQP_BEGIN (ed, current_sequence) {
- if (!(current_sequence->flag & SELECT) && current_sequence != deleting_sequence) {
- SequenceModifierData *smd;
-
- for (smd = current_sequence->modifiers.first; smd; smd = smd->next) {
- if (smd->mask_sequence == deleting_sequence) {
- smd->mask_sequence = NULL;
- }
- }
- }
- }
- SEQ_END;
-}
-
static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall)
{
Sequence *seq, *seqn;
@@ -2584,61 +2516,18 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq;
- MetaStack *ms;
- bool nothing_selected = true;
- BKE_sequencer_prefetch_stop(scene);
-
- seq = BKE_sequencer_active_get(scene);
- if (seq && seq->flag & SELECT) { /* Avoid a loop since this is likely to be selected. */
- nothing_selected = false;
- }
- else {
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT) {
- nothing_selected = false;
- break;
- }
- }
- }
-
- if (nothing_selected) {
- return OPERATOR_FINISHED;
- }
-
- /* For effects and modifiers, try to find a replacement input. */
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (!(seq->flag & SELECT)) {
- if ((seq->type & SEQ_TYPE_EFFECT)) {
- del_seq_find_replace_recurs(scene, seq);
- }
- }
- else {
- del_seq_clear_modifiers_recurs(scene, seq);
+ SEQP_BEGIN (scene->ed, seq) {
+ if (seq->flag & SELECT) {
+ BKE_sequencer_flag_for_removal(scene, ed->seqbasep, seq);
}
}
-
- /* Delete all selected strips. */
- recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0);
-
- /* Update lengths, etc. */
- seq = ed->seqbasep->first;
- while (seq) {
- BKE_sequence_calc(scene, seq);
- seq = seq->next;
- }
-
- /* Free parent metas. */
- ms = ed->metastack.last;
- while (ms) {
- BKE_sequence_calc(scene, ms->parseq);
- ms = ms->prev;
- }
+ SEQ_END;
+ BKE_sequencer_remove_flagged_sequences(scene, ed->seqbasep);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
-
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 2e170126574..d78c58c0c64 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1474,6 +1474,7 @@ static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
uiLayout *col;
if (!mball || !(mball->lastelem)) {
+ uiItemL(layout, IFACE_("Nothing selected"), ICON_NONE);
return;
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index cc5f7deb418..411b18717bf 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -36,6 +36,7 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -74,7 +75,6 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
-#include "GPU_draw.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
@@ -1617,7 +1617,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region)
view3d_draw_view(C, region);
DRW_cache_free_old_batches(bmain);
- GPU_free_images_old(bmain);
+ BKE_image_free_old_gputextures(bmain);
GPU_pass_cache_garbage_collect();
/* XXX This is in order to draw UI batches with the DRW
@@ -1707,7 +1707,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
{
/* free images which can have changed on frame-change
* warning! can be slow so only free animated images - campbell */
- GPU_free_images_anim(G.main); /* XXX :((( */
+ BKE_image_free_anim_gputextures(G.main); /* XXX :((( */
}
GPU_matrix_push_projection();
@@ -1954,10 +1954,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
NULL);
if (ibuf->rect_float) {
- GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
+ GPU_offscreen_read_pixels(ofs, GPU_DATA_FLOAT, ibuf->rect_float);
}
else if (ibuf->rect) {
- GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
+ GPU_offscreen_read_pixels(ofs, GPU_DATA_UNSIGNED_BYTE, ibuf->rect);
}
/* unbind */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index fc763d91e3d..2c8ea396a99 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -97,7 +97,6 @@
#include "UI_interface.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 66efa5b5de3..ff9673a4262 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -50,7 +50,6 @@
#include "UI_resources.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 2bda04ad811..bbd18b4bdaf 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -81,6 +81,7 @@ typedef struct TransSnap {
bool snap_self;
bool peel;
bool snap_spatial_grid;
+ bool use_backface_culling;
char status;
/* Snapped Element Type (currently for objects only). */
char snapElem;
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index e4960e1ec71..2e0f7a3a113 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1026,8 +1026,10 @@ static void mesh_customdatacorrect_free_cb(struct TransInfo *UNUSED(t),
# define FACE_SUBSTITUTE_INDEX INT_MIN
-/* Search for a neighboring face with area and preferably without selected vertex.
- * Used to replace arealess faces in customdata correction. */
+/**
+ * Search for a neighboring face with area and preferably without selected vertex.
+ * Used to replace area-less faces in custom-data correction.
+ */
static BMFace *mesh_customdatacorrect_find_best_face_substitute(BMFace *f)
{
BMFace *best_face = NULL;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 2943c3cb8ea..a700dd320b7 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -37,6 +37,7 @@
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_object.h"
+#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "RNA_access.h"
@@ -100,6 +101,24 @@ int BIF_snappingSupported(Object *obedit)
}
#endif
+static bool snap_use_backface_culling(const TransInfo *t)
+{
+ BLI_assert(t->spacetype == SPACE_VIEW3D);
+ View3D *v3d = t->view;
+ if ((v3d->shading.type == OB_SOLID) && (v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)) {
+ return true;
+ }
+ if (v3d->shading.type == OB_RENDER &&
+ (t->scene->display.shading.flag & V3D_SHADING_BACKFACE_CULLING) &&
+ BKE_scene_uses_blender_workbench(t->scene)) {
+ return true;
+ }
+ if (t->settings->snap_flag & SCE_SNAP_BACKFACE_CULLING) {
+ return true;
+ }
+ return false;
+}
+
bool validSnap(const TransInfo *t)
{
return (t->tsnap.status & (POINT_INIT | TARGET_INIT)) == (POINT_INIT | TARGET_INIT) ||
@@ -315,8 +334,7 @@ void applyProject(TransInfo *t)
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
.use_occlusion_test = false,
- .use_backface_culling = (t->scene->toolsettings->snap_flag &
- SCE_SNAP_BACKFACE_CULLING) != 0,
+ .use_backface_culling = t->tsnap.use_backface_culling,
},
mval_fl,
NULL,
@@ -601,6 +619,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
+ t->tsnap.use_backface_culling = snap_use_backface_culling(t);
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
t->scene, 0, t->region, t->view);
@@ -1120,13 +1139,12 @@ short snapObjectsTransform(
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
t->depsgraph,
- t->scene->toolsettings->snap_mode,
+ t->settings->snap_mode,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
- .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE,
- .use_backface_culling = (t->scene->toolsettings->snap_flag &
- SCE_SNAP_BACKFACE_CULLING) != 0,
+ .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
+ .use_backface_culling = t->tsnap.use_backface_culling,
},
mval,
target,
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 3c747a29361..384da6fb931 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -26,6 +26,8 @@
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_scene.h"
#include "BKE_unit.h"
@@ -277,8 +279,12 @@ static bool editstr_insert_at_cursor(NumInput *n, const char *buf, const int buf
return true;
}
-bool user_string_to_number(
- bContext *C, const char *str, const UnitSettings *unit, int type, double *r_value)
+bool user_string_to_number(bContext *C,
+ const char *str,
+ const UnitSettings *unit,
+ int type,
+ const char *error_prefix,
+ double *r_value)
{
#ifdef WITH_PYTHON
double unit_scale = BKE_scene_unit_scale(unit, type, 1.0);
@@ -288,10 +294,10 @@ bool user_string_to_number(
bUnit_ReplaceString(
str_unit_convert, sizeof(str_unit_convert), str, unit_scale, unit->system, type);
- return BPY_execute_string_as_number(C, NULL, str_unit_convert, true, r_value);
+ return BPY_execute_string_as_number(C, NULL, str_unit_convert, error_prefix, r_value);
}
- int success = BPY_execute_string_as_number(C, NULL, str, true, r_value);
+ int success = BPY_execute_string_as_number(C, NULL, str, error_prefix, r_value);
*r_value *= bUnit_PreferredInputUnitScalar(unit, type);
*r_value /= unit_scale;
return success;
@@ -573,7 +579,8 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Scene *sce = CTX_data_scene(C);
double val;
- int success = user_string_to_number(C, n->str, &sce->unit, n->unit_type[idx], &val);
+ int success = user_string_to_number(
+ C, n->str, &sce->unit, n->unit_type[idx], IFACE_("Numeric input evaluation"), &val);
if (success) {
n->val[idx] = (float)val;
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index abbb0aa330c..5ccc6e29026 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -117,6 +117,7 @@ void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
void UV_OT_rip(struct wmOperatorType *ot);
void UV_OT_stitch(struct wmOperatorType *ot);
+void UV_OT_smart_project(struct wmOperatorType *ot);
/* uvedit_path.c */
void UV_OT_shortest_path_pick(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index e2368ae6ba8..ad98321c458 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -2094,6 +2094,7 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_reset);
WM_operatortype_append(UV_OT_sphere_project);
WM_operatortype_append(UV_OT_unwrap);
+ WM_operatortype_append(UV_OT_smart_project);
WM_operatortype_append(UV_OT_reveal);
WM_operatortype_append(UV_OT_hide);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 6fcfb0e0bfc..2f30ef1caa6 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -35,7 +35,10 @@
#include "DNA_scene_types.h"
#include "BLI_alloca.h"
+#include "BLI_array.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLI_uvproject.h"
@@ -147,7 +150,13 @@ typedef struct UnwrapOptions {
/** Connectivity based on UV coordinates instead of seams. */
bool topology_from_uvs;
/** Only affect selected faces. */
- bool only_selected;
+ bool only_selected_faces;
+ /**
+ * Only affect selected UV's.
+ * \note Disable this for operations that don't run in the image-window.
+ * Unwrapping from the 3D view for example, where only 'only_selected_faces' should be used.
+ */
+ bool only_selected_uvs;
/** Fill holes to better preserve shape. */
bool fill_holes;
/** Correct for mapped image texture aspect ratio. */
@@ -299,7 +308,7 @@ static ParamHandle *construct_param_handle(const Scene *scene,
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
- (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
+ (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
continue;
}
@@ -307,10 +316,12 @@ static ParamHandle *construct_param_handle(const Scene *scene,
bool is_loopsel = false;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- is_loopsel = true;
- break;
+ if (options->only_selected_uvs &&
+ (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
+ continue;
}
+ is_loopsel = true;
+ break;
}
if (is_loopsel == false) {
continue;
@@ -382,7 +393,7 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
- (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
+ (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
continue;
}
@@ -390,10 +401,12 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
bool is_loopsel = false;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- is_loopsel = true;
- break;
+ if (options->only_selected_uvs &&
+ (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
+ continue;
}
+ is_loopsel = true;
+ break;
}
if (is_loopsel == false) {
continue;
@@ -571,7 +584,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
}
else {
if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) ||
- (options->only_selected && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) {
+ (options->only_selected_faces && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) {
continue;
}
}
@@ -671,7 +684,8 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
const UnwrapOptions options = {
.topology_from_uvs = true,
.fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
- .only_selected = true,
+ .only_selected_faces = true,
+ .only_selected_uvs = true,
.correct_aspect = true,
};
@@ -933,7 +947,8 @@ static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
{
const UnwrapOptions options = {
.topology_from_uvs = true,
- .only_selected = false,
+ .only_selected_faces = false,
+ .only_selected_uvs = true,
.fill_holes = false,
.correct_aspect = false,
};
@@ -975,7 +990,8 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
const UnwrapOptions options = {
.topology_from_uvs = true,
- .only_selected = true,
+ .only_selected_faces = true,
+ .only_selected_uvs = true,
.fill_holes = false,
.correct_aspect = true,
};
@@ -1040,7 +1056,8 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
const UnwrapOptions options = {
.topology_from_uvs = true,
- .only_selected = true,
+ .only_selected_faces = true,
+ .only_selected_uvs = true,
.fill_holes = false,
.correct_aspect = true,
};
@@ -1114,7 +1131,8 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
const UnwrapOptions options = {
.topology_from_uvs = false,
- .only_selected = false,
+ .only_selected_faces = false,
+ .only_selected_uvs = true,
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
@@ -1471,18 +1489,21 @@ static void correct_uv_aspect(Object *ob, BMEditMesh *em)
/** \name UV Map Clip & Correct
* \{ */
-static void uv_map_clip_correct_properties(wmOperatorType *ot)
+static void uv_map_clip_correct_properties_ex(wmOperatorType *ot, bool clip_to_bounds)
{
RNA_def_boolean(ot->srna,
"correct_aspect",
1,
"Correct Aspect",
"Map UVs taking image aspect ratio into account");
- RNA_def_boolean(ot->srna,
- "clip_to_bounds",
- 0,
- "Clip to Bounds",
- "Clip UV coordinates to bounds after unwrapping");
+ /* Optional, since not all unwrapping types need to be clipped. */
+ if (clip_to_bounds) {
+ RNA_def_boolean(ot->srna,
+ "clip_to_bounds",
+ 0,
+ "Clip to Bounds",
+ "Clip UV coordinates to bounds after unwrapping");
+ }
RNA_def_boolean(ot->srna,
"scale_to_bounds",
0,
@@ -1490,6 +1511,11 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
"Scale UV coordinates to bounds after unwrapping");
}
+static void uv_map_clip_correct_properties(wmOperatorType *ot)
+{
+ uv_map_clip_correct_properties_ex(ot, true);
+}
+
static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
{
BMFace *efa;
@@ -1498,7 +1524,8 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
MLoopUV *luv;
float dx, dy, min[2], max[2];
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
- const bool clip_to_bounds = RNA_boolean_get(op->ptr, "clip_to_bounds");
+ const bool clip_to_bounds = (RNA_struct_find_property(op->ptr, "clip_to_bounds") &&
+ RNA_boolean_get(op->ptr, "clip_to_bounds"));
const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
INIT_MINMAX2(min, max);
@@ -1635,7 +1662,8 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
if (scene->toolsettings->edge_mode_live_unwrap) {
const UnwrapOptions options = {
.topology_from_uvs = false,
- .only_selected = false,
+ .only_selected_faces = false,
+ .only_selected_uvs = true,
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
@@ -1670,7 +1698,8 @@ static int unwrap_exec(bContext *C, wmOperator *op)
const UnwrapOptions options = {
.topology_from_uvs = false,
- .only_selected = true,
+ .only_selected_faces = true,
+ .only_selected_uvs = true,
.fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
.correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
};
@@ -1829,6 +1858,365 @@ void UV_OT_unwrap(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Smart UV Project Operator
+ * \{ */
+
+/* Ignore all areas below this, as the UV's get zeroed. */
+static const float smart_uv_project_area_ignore = 1e-12f;
+
+typedef struct ThickFace {
+ float area;
+ BMFace *efa;
+} ThickFace;
+
+static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p)
+{
+
+ const ThickFace *tf_a = (ThickFace *)tf_a_p;
+ const ThickFace *tf_b = (ThickFace *)tf_b_p;
+
+ /* Ignore the area of small faces.
+ * Also, order checks so `!isfinite(...)` values are counted as zero area. */
+ if (!((tf_a->area > smart_uv_project_area_ignore) ||
+ (tf_b->area > smart_uv_project_area_ignore))) {
+ return 0;
+ }
+
+ if (tf_a->area < tf_b->area) {
+ return 1;
+ }
+ else if (tf_a->area > tf_b->area) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static uint smart_uv_project_calculate_project_normals(const ThickFace *thick_faces,
+ const uint thick_faces_len,
+ BMesh *bm,
+ const float project_angle_limit_half_cos,
+ const float project_angle_limit_cos,
+ const float area_weight,
+ float (**r_project_normal_array)[3])
+{
+ if (UNLIKELY(thick_faces_len == 0)) {
+ *r_project_normal_array = NULL;
+ return 0;
+ }
+
+ const float *project_normal = thick_faces[0].efa->no;
+
+ const ThickFace **project_thick_faces = NULL;
+ BLI_array_declare(project_thick_faces);
+
+ float(*project_normal_array)[3] = NULL;
+ BLI_array_declare(project_normal_array);
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
+
+ while (true) {
+ for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
+ if (BM_elem_flag_test(thick_faces[f_index].efa, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ if (dot_v3v3(thick_faces[f_index].efa->no, project_normal) > project_angle_limit_half_cos) {
+ BLI_array_append(project_thick_faces, &thick_faces[f_index]);
+ BM_elem_flag_set(thick_faces[f_index].efa, BM_ELEM_TAG, true);
+ }
+ }
+
+ float average_normal[3] = {0.0f, 0.0f, 0.0f};
+
+ if (area_weight <= 0.0f) {
+ for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
+ f_proj_index++) {
+ const ThickFace *tf = project_thick_faces[f_proj_index];
+ add_v3_v3(average_normal, tf->efa->no);
+ }
+ }
+ else if (area_weight >= 1.0f) {
+ for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
+ f_proj_index++) {
+ const ThickFace *tf = project_thick_faces[f_proj_index];
+ madd_v3_v3fl(average_normal, tf->efa->no, tf->area);
+ }
+ }
+ else {
+ for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
+ f_proj_index++) {
+ const ThickFace *tf = project_thick_faces[f_proj_index];
+ const float area_blend = (tf->area * area_weight) + (1.0f - area_weight);
+ madd_v3_v3fl(average_normal, tf->efa->no, area_blend);
+ }
+ }
+
+ /* Avoid NAN. */
+ if (normalize_v3(average_normal) != 0.0f) {
+ float(*normal)[3] = BLI_array_append_ret(project_normal_array);
+ copy_v3_v3(*normal, average_normal);
+ }
+
+ /* Find the most unique angle that points away from other normals. */
+ float anble_best = 1.0f;
+ uint angle_best_index = 0;
+
+ for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
+ if (BM_elem_flag_test(thick_faces[f_index].efa, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ float angle_test = -1.0f;
+ for (int p_index = 0; p_index < BLI_array_len(project_normal_array); p_index++) {
+ angle_test = max_ff(angle_test,
+ dot_v3v3(project_normal_array[p_index], thick_faces[f_index].efa->no));
+ }
+
+ if (angle_test < anble_best) {
+ anble_best = angle_test;
+ angle_best_index = f_index;
+ }
+ }
+
+ if (anble_best < project_angle_limit_cos) {
+ project_normal = thick_faces[angle_best_index].efa->no;
+ BLI_array_clear(project_thick_faces);
+ BLI_array_append(project_thick_faces, &thick_faces[angle_best_index]);
+ BM_elem_flag_enable(thick_faces[angle_best_index].efa, BM_ELEM_TAG);
+ }
+ else {
+ if (BLI_array_len(project_normal_array) >= 1) {
+ break;
+ }
+ }
+ }
+
+ BLI_array_free(project_thick_faces);
+ BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
+
+ *r_project_normal_array = project_normal_array;
+ return BLI_array_len(project_normal_array);
+}
+
+static int smart_project_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ /* May be NULL. */
+ View3D *v3d = CTX_wm_view3d(C);
+
+ const float project_angle_limit = RNA_float_get(op->ptr, "angle_limit");
+ const float island_margin = RNA_float_get(op->ptr, "island_margin");
+ const float area_weight = RNA_float_get(op->ptr, "area_weight");
+
+ const float project_angle_limit_cos = cosf(project_angle_limit);
+ const float project_angle_limit_half_cos = cosf(project_angle_limit / 2);
+
+ /* Memory arena for list links (cleared for each object). */
+ MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, v3d, &objects_len);
+
+ Object **objects_changed = MEM_mallocN(sizeof(*objects_changed) * objects_len, __func__);
+ uint object_changed_len = 0;
+
+ BMFace *efa;
+ BMIter iter;
+ uint ob_index;
+
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool changed = false;
+
+ const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ ThickFace *thick_faces = MEM_mallocN(sizeof(*thick_faces) * em->bm->totface, __func__);
+
+ uint thick_faces_len = 0;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
+ }
+ thick_faces[thick_faces_len].area = BM_face_calc_area(efa);
+ thick_faces[thick_faces_len].efa = efa;
+ thick_faces_len++;
+ }
+
+ qsort(thick_faces, thick_faces_len, sizeof(ThickFace), smart_uv_project_thickface_area_cmp_fn);
+
+ /* Remove all zero area faces. */
+ while ((thick_faces_len > 0) &&
+ !(thick_faces[thick_faces_len - 1].area > smart_uv_project_area_ignore)) {
+
+ /* Zero UV's so they don't overlap with other faces being unwrapped. */
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, thick_faces[thick_faces_len - 1].efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ zero_v2(luv->uv);
+ changed = true;
+ }
+
+ thick_faces_len -= 1;
+ }
+
+ float(*project_normal_array)[3] = NULL;
+ int project_normals_len = smart_uv_project_calculate_project_normals(
+ thick_faces,
+ thick_faces_len,
+ em->bm,
+ project_angle_limit_half_cos,
+ project_angle_limit_cos,
+ area_weight,
+ &project_normal_array);
+
+ if (project_normals_len == 0) {
+ MEM_freeN(thick_faces);
+ BLI_assert(project_normal_array == NULL);
+ continue;
+ }
+
+ /* After finding projection vectors, we find the uv positions. */
+ LinkNode **thickface_project_groups = MEM_callocN(
+ sizeof(*thickface_project_groups) * project_normals_len, __func__);
+
+ BLI_memarena_clear(arena);
+
+ for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
+ const float *f_normal = thick_faces[f_index].efa->no;
+
+ float angle_best = dot_v3v3(f_normal, project_normal_array[0]);
+ uint angle_best_index = 0;
+
+ for (int p_index = 1; p_index < project_normals_len; p_index++) {
+ const float angle_test = dot_v3v3(f_normal, project_normal_array[p_index]);
+ if (angle_test > angle_best) {
+ angle_best = angle_test;
+ angle_best_index = p_index;
+ }
+ }
+
+ BLI_linklist_prepend_arena(
+ &thickface_project_groups[angle_best_index], &thick_faces[f_index], arena);
+ }
+
+ for (int p_index = 0; p_index < project_normals_len; p_index++) {
+ if (thickface_project_groups[p_index] == NULL) {
+ continue;
+ }
+
+ float axis_mat[3][3];
+ axis_dominant_v3_to_m3_negate(axis_mat, project_normal_array[p_index]);
+
+ for (LinkNode *list = thickface_project_groups[p_index]; list; list = list->next) {
+ ThickFace *tf = list->link;
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, tf->efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ mul_v2_m3v3(luv->uv, axis_mat, l->v->co);
+ }
+ changed = true;
+ }
+ }
+
+ MEM_freeN(thick_faces);
+ MEM_freeN(project_normal_array);
+
+ /* No need to free the lists in 'thickface_project_groups' values as the 'arena' is used. */
+ MEM_freeN(thickface_project_groups);
+
+ if (changed) {
+ objects_changed[object_changed_len] = objects[ob_index];
+ object_changed_len += 1;
+ }
+ }
+
+ BLI_memarena_free(arena);
+
+ MEM_freeN(objects);
+
+ /* Pack islands & Stretch to UV bounds */
+ if (object_changed_len > 0) {
+
+ scene->toolsettings->uvcalc_margin = island_margin;
+ const UnwrapOptions options = {
+ .topology_from_uvs = true,
+ .only_selected_faces = true,
+ .only_selected_uvs = false,
+ .fill_holes = true,
+ .correct_aspect = false,
+ };
+
+ /* Depsgraph refresh functions are called here. */
+ uvedit_pack_islands_multi(scene, objects_changed, object_changed_len, &options, true, false);
+ uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
+ }
+
+ MEM_freeN(objects_changed);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_smart_project(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Smart UV Project";
+ ot->idname = "UV_OT_smart_project";
+ ot->description = "Projection unwraps the selected faces of mesh objects";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = smart_project_exec;
+ ot->poll = ED_operator_uvmap;
+ ot->invoke = WM_operator_props_popup_confirm;
+
+ /* properties */
+ prop = RNA_def_float_rotation(ot->srna,
+ "angle_limit",
+ 0,
+ NULL,
+ DEG2RADF(0.0f),
+ DEG2RADF(90.0f),
+ "Angle Limit",
+ "Lower for more projection groups, higher for less distortion",
+ DEG2RADF(0.0f),
+ DEG2RADF(89.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(66.0f));
+
+ RNA_def_float(ot->srna,
+ "island_margin",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Island Margin",
+ "Margin to reduce bleed from adjacent islands",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "area_weight",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Area Weight",
+ "Weight projections vector by faces with larger areas",
+ 0.0f,
+ 1.0f);
+
+ uv_map_clip_correct_properties_ex(ot, false);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Project UV From View Operator
* \{ */
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
index 2c226e330d7..3c2f022adb6 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
@@ -108,7 +108,7 @@ static int FrsMaterial_init(BPy_FrsMaterial *self, PyObject *args, PyObject *kwd
self->m = new FrsMaterial(*m);
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O&O&O&O&O&fi",
diff --git a/source/blender/freestyle/intern/python/BPy_Id.cpp b/source/blender/freestyle/intern/python/BPy_Id.cpp
index 4f61ba847f6..eb0eb661e3d 100644
--- a/source/blender/freestyle/intern/python/BPy_Id.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Id.cpp
@@ -75,7 +75,7 @@ static int Id_init(BPy_Id *self, PyObject *args, PyObject *kwds)
if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &Id_Type, &brother)) {
self->id = new Id(*(((BPy_Id *)brother)->id));
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args, kwds, "|ii", (char **)kwlist_2, &first, &second)) {
self->id = new Id(first, second);
}
diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp
index 510e823ba55..56f95b8ecbb 100644
--- a/source/blender/freestyle/intern/python/BPy_Operators.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp
@@ -365,8 +365,8 @@ static PyObject *Operators_sequential_split(BPy_Operators * /*self*/,
return NULL;
}
}
- else if (PyErr_Clear(),
- (f = 0.0f),
+ else if ((void)PyErr_Clear(),
+ (void)(f = 0.0f),
PyArg_ParseTupleAndKeywords(
args, kwds, "O!|f", (char **)kwlist_2, &UnaryPredicate0D_Type, &obj1, &f)) {
if (!((BPy_UnaryPredicate0D *)obj1)->up0D) {
@@ -484,8 +484,8 @@ static PyObject *Operators_recursive_split(BPy_Operators * /*self*/,
return NULL;
}
}
- else if (PyErr_Clear(),
- (f = 0.0f),
+ else if ((void)PyErr_Clear(),
+ (void)(f = 0.0f),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!O!|f",
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
index 5f5407e82e3..214385f74ad 100644
--- a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
+++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
@@ -110,7 +110,7 @@ static int StrokeAttribute_init(BPy_StrokeAttribute *self, PyObject *args, PyObj
self->sa = new StrokeAttribute(*(((BPy_StrokeAttribute *)obj1)->sa));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!f",
@@ -123,7 +123,7 @@ static int StrokeAttribute_init(BPy_StrokeAttribute *self, PyObject *args, PyObj
self->sa = new StrokeAttribute(
*(((BPy_StrokeAttribute *)obj1)->sa), *(((BPy_StrokeAttribute *)obj2)->sa), t);
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"ffffff",
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
index f59ae15ae01..2adcae13e6d 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -88,7 +88,7 @@ static int ViewShape_init(BPy_ViewShape *self, PyObject *args, PyObject *kwds)
self->py_ss = ((BPy_ViewShape *)obj)->py_ss;
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &SShape_Type, &obj)) {
BPy_SShape *py_ss = (BPy_SShape *)obj;
self->vs = new ViewShape(py_ss->ss);
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
index 6af80c4bfd9..81dd79ff270 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
@@ -95,7 +95,7 @@ static int CurvePoint_init(BPy_CurvePoint *self, PyObject *args, PyObject *kwds)
self->cp = new CurvePoint(*(((BPy_CurvePoint *)obj1)->cp));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!f",
@@ -107,7 +107,7 @@ static int CurvePoint_init(BPy_CurvePoint *self, PyObject *args, PyObject *kwds)
&t2d)) {
self->cp = new CurvePoint(((BPy_SVertex *)obj1)->sv, ((BPy_SVertex *)obj2)->sv, t2d);
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!f",
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
index 71a87c2c01e..c01f1f17000 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
@@ -72,7 +72,7 @@ static int SVertex_init(BPy_SVertex *self, PyObject *args, PyObject *kwds)
self->sv = new SVertex(*(((BPy_SVertex *)obj)->sv));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(
args, kwds, "O&O!", (char **)kwlist_2, convert_v3, v, &Id_Type, &obj)) {
Vec3r point_3d(v[0], v[1], v[2]);
diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
index b4c08714af0..519bd72db3b 100644
--- a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
@@ -107,7 +107,7 @@ static int StrokeVertex_init(BPy_StrokeVertex *self, PyObject *args, PyObject *k
self->sv = new StrokeVertex(*(((BPy_StrokeVertex *)obj1)->sv));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!f",
@@ -129,7 +129,7 @@ static int StrokeVertex_init(BPy_StrokeVertex *self, PyObject *args, PyObject *k
}
self->sv = new StrokeVertex(sv1, sv2, t3d);
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(
args, kwds, "O!", (char **)kwlist_3, &CurvePoint_Type, &obj1)) {
CurvePoint *cp = ((BPy_CurvePoint *)obj1)->cp;
@@ -139,8 +139,8 @@ static int StrokeVertex_init(BPy_StrokeVertex *self, PyObject *args, PyObject *k
}
self->sv = new StrokeVertex(cp);
}
- else if (PyErr_Clear(),
- (obj2 = 0),
+ else if ((void)PyErr_Clear(),
+ (void)(obj2 = 0),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!|O!",
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
index 8a09e7722ea..187ab94360a 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
@@ -81,7 +81,7 @@ static int FEdge_init(BPy_FEdge *self, PyObject *args, PyObject *kwds)
self->fe = new FEdge(*(((BPy_FEdge *)obj1)->fe));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!",
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
index fd434f9c4ef..788dfa78992 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
@@ -72,7 +72,7 @@ static int FrsCurve_init(BPy_FrsCurve *self, PyObject *args, PyObject *kwds)
self->c = new Curve(*(((BPy_FrsCurve *)obj)->c));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &Id_Type, &obj)) {
self->c = new Curve(*(((BPy_Id *)obj)->id));
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
index 3a25ddb0252..b31efe1f923 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
@@ -157,7 +157,8 @@ static PyObject *Stroke_resample(BPy_Stroke *self, PyObject *args, PyObject *kwd
return NULL;
}
}
- else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &f)) {
+ else if ((void)PyErr_Clear(),
+ PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &f)) {
if (self->s->Resample(f) < 0) {
PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex interval) failed");
return NULL;
diff --git a/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
index 285100193d3..9cdc344081e 100644
--- a/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
@@ -71,7 +71,7 @@ static int Chain_init(BPy_Chain *self, PyObject *args, PyObject *kwds)
self->c = new Chain(*(((BPy_Chain *)obj)->c));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &Id_Type, &obj)) {
self->c = new Chain(*(((BPy_Id *)obj)->id));
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
index 725daa80b5e..5db75c84608 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
@@ -75,7 +75,7 @@ static int FEdgeSharp_init(BPy_FEdgeSharp *self, PyObject *args, PyObject *kwds)
self->fes = new FEdgeSharp(*(((BPy_FEdgeSharp *)obj1)->fes));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!",
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
index 65d9dcbe01f..3fb739b18db 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
@@ -73,7 +73,7 @@ static int FEdgeSmooth_init(BPy_FEdgeSmooth *self, PyObject *args, PyObject *kwd
self->fes = new FEdgeSmooth(*(((BPy_FEdgeSmooth *)obj1)->fes));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!",
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
index 74ae7809284..90e751333b9 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
@@ -82,8 +82,8 @@ static int AdjacencyIterator_init(BPy_AdjacencyIterator *self, PyObject *args, P
self->at_start = ((BPy_AdjacencyIterator *)obj1)->at_start;
}
}
- else if (PyErr_Clear(),
- (obj2 = obj3 = 0),
+ else if ((void)PyErr_Clear(),
+ (void)(obj2 = obj3 = 0),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!|O!O!",
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
index 164e1646934..1703fc2bddb 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
@@ -114,8 +114,8 @@ static int ChainPredicateIterator_init(BPy_ChainPredicateIterator *self,
Py_INCREF(self->upred);
Py_INCREF(self->bpred);
}
- else if (PyErr_Clear(),
- (obj3 = obj4 = obj5 = obj6 = 0),
+ else if ((void)PyErr_Clear(),
+ (void)(obj3 = obj4 = obj5 = obj6 = 0),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!|O!O!O&O!",
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
index 401959be0c0..d8ad82d667c 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
@@ -91,8 +91,8 @@ static int ChainSilhouetteIterator_init(BPy_ChainSilhouetteIterator *self,
args, kwds, "O!", (char **)kwlist_1, &ChainSilhouetteIterator_Type, &obj1)) {
self->cs_it = new ChainSilhouetteIterator(*(((BPy_ChainSilhouetteIterator *)obj1)->cs_it));
}
- else if (PyErr_Clear(),
- (obj1 = obj2 = obj3 = 0),
+ else if ((void)PyErr_Clear(),
+ (void)(obj1 = obj2 = obj3 = 0),
PyArg_ParseTupleAndKeywords(args,
kwds,
"|O!O&O!",
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
index b6d841c5b64..dbd6e8dd09d 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
@@ -91,8 +91,8 @@ static int ChainingIterator___init__(BPy_ChainingIterator *self, PyObject *args,
args, kwds, "O!", (char **)kwlist_1, &ChainingIterator_Type, &obj1)) {
self->c_it = new ChainingIterator(*(((BPy_ChainingIterator *)obj1)->c_it));
}
- else if (PyErr_Clear(),
- (obj1 = obj2 = obj3 = obj4 = 0),
+ else if ((void)PyErr_Clear(),
+ (void)(obj1 = obj2 = obj3 = obj4 = 0),
PyArg_ParseTupleAndKeywords(args,
kwds,
"|O!O!O&O!",
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
index 6ea61a060cb..6c496b0308b 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
@@ -75,7 +75,8 @@ static int CurvePointIterator_init(BPy_CurvePointIterator *self, PyObject *args,
*(((BPy_CurvePointIterator *)brother)->cp_it));
}
}
- else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &step)) {
+ else if ((void)PyErr_Clear(),
+ PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &step)) {
self->cp_it = new CurveInternal::CurvePointIterator(step);
}
else {
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
index 0dbef9f325c..f0d6acf461b 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
@@ -81,14 +81,14 @@ static int Interface0DIterator_init(BPy_Interface0DIterator *self, PyObject *arg
self->at_start = true;
self->reversed = false;
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(
args, kwds, "O!", (char **)kwlist_2, &Interface1D_Type, &inter)) {
self->if0D_it = new Interface0DIterator(((BPy_Interface1D *)inter)->if1D->verticesBegin());
self->at_start = true;
self->reversed = false;
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(
args, kwds, "O!", (char **)kwlist_3, &Interface0DIterator_Type, &brother)) {
self->if0D_it = new Interface0DIterator(*(((BPy_Interface0DIterator *)brother)->if0D_it));
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
index dd738b97473..4a5927ff6eb 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
@@ -82,7 +82,7 @@ static int SVertexIterator_init(BPy_SVertexIterator *self, PyObject *args, PyObj
self->sv_it = new ViewEdgeInternal::SVertexIterator(*(((BPy_SVertexIterator *)obj1)->sv_it));
}
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(args,
kwds,
"O!O!O!O!f",
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
index 84f57f1fe31..df03ecba96f 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
@@ -74,7 +74,7 @@ static int StrokeVertexIterator_init(BPy_StrokeVertexIterator *self,
self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start;
}
- else if (PyErr_Clear(),
+ else if ((void)PyErr_Clear(),
PyArg_ParseTupleAndKeywords(
args, kwds, "|O!", (char **)kwlist_2, &Stroke_Type, &stroke)) {
if (!stroke) {
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
index c8a978784a4..3d0ed5d5a4d 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
@@ -78,8 +78,8 @@ static int ViewEdgeIterator_init(BPy_ViewEdgeIterator *self, PyObject *args, PyO
args, kwds, "O!", (char **)kwlist_1, &ViewEdgeIterator_Type, &obj1)) {
self->ve_it = new ViewEdgeInternal::ViewEdgeIterator(*(((BPy_ViewEdgeIterator *)obj1)->ve_it));
}
- else if (PyErr_Clear(),
- (obj1 = obj2 = 0),
+ else if ((void)PyErr_Clear(),
+ (void)(obj1 = obj2 = 0),
PyArg_ParseTupleAndKeywords(
args, kwds, "|O&O!", (char **)kwlist_2, check_begin, &obj1, &PyBool_Type, &obj2)) {
ViewEdge *begin = (!obj1 || obj1 == Py_None) ? NULL : ((BPy_ViewEdge *)obj1)->ve;
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
index 51a0c670d75..9e2726061c3 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
@@ -35,9 +35,9 @@ static char SmoothingShader___doc__[] =
"\n"
"[Geometry shader]\n"
"\n"
- ".. method:: __init__(num_iterations=100, factor_point=0.1,\n"
- " factor_curvature=0.0, factor_curvature_difference=0.2,\n"
- " aniso_point=0.0, aniso_normal=0.0, aniso_curvature=0.0,\n"
+ ".. method:: __init__(num_iterations=100, factor_point=0.1, \\\n"
+ " factor_curvature=0.0, factor_curvature_difference=0.2, \\\n"
+ " aniso_point=0.0, aniso_normal=0.0, aniso_curvature=0.0, \\\n"
" carricature_factor=1.0)\n"
"\n"
" Builds a SmoothingShader object.\n"
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 2686275e898..ad29dbe6668 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -57,3 +57,20 @@ set(LIB
)
blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ tests/FN_array_spans_test.cc
+ tests/FN_attributes_ref_test.cc
+ tests/FN_cpp_type_test.cc
+ tests/FN_generic_vector_array_test.cc
+ tests/FN_multi_function_network_test.cc
+ tests/FN_multi_function_test.cc
+ tests/FN_spans_test.cc
+ )
+ set (TEST_LIB
+ bf_functions
+ )
+ include(GTestTesting)
+ blender_add_test_lib(bf_functions_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+endif()
diff --git a/source/blender/functions/FN_array_spans.hh b/source/blender/functions/FN_array_spans.hh
index c362fef3630..5f976711e06 100644
--- a/source/blender/functions/FN_array_spans.hh
+++ b/source/blender/functions/FN_array_spans.hh
@@ -158,7 +158,7 @@ class GVArraySpan : public VArraySpanBase<void> {
this->type_ = &array.type();
this->virtual_size_ = virtual_size;
this->category_ = VArraySpanCategory::SingleArray;
- this->data_.single_array.start = array.buffer();
+ this->data_.single_array.start = array.data();
this->data_.single_array.size = array.size();
}
diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh
index ed14676731e..c694f11b7a7 100644
--- a/source/blender/functions/FN_attributes_ref.hh
+++ b/source/blender/functions/FN_attributes_ref.hh
@@ -50,12 +50,12 @@ class AttributesInfoBuilder : NonCopyable, NonMovable {
AttributesInfoBuilder() = default;
~AttributesInfoBuilder();
- template<typename T> void add(StringRef name, const T &default_value)
+ template<typename T> bool add(StringRef name, const T &default_value)
{
- this->add(name, CPPType::get<T>(), (const void *)&default_value);
+ return this->add(name, CPPType::get<T>(), (const void *)&default_value);
}
- void add(StringRef name, const CPPType &type, const void *default_value = nullptr);
+ bool add(StringRef name, const CPPType &type, const void *default_value = nullptr);
};
/**
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 594890e353a..531a9073784 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -371,7 +371,7 @@ class CPPType : NonCopyable, NonMovable {
void copy_to_initialized_n(const void *src, void *dst, int64_t n) const
{
- BLI_assert(src != dst);
+ BLI_assert(n == 0 || src != dst);
BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
@@ -380,7 +380,7 @@ class CPPType : NonCopyable, NonMovable {
void copy_to_initialized_indices(const void *src, void *dst, IndexMask mask) const
{
- BLI_assert(src != dst);
+ BLI_assert(mask.size() == 0 || src != dst);
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
@@ -406,7 +406,7 @@ class CPPType : NonCopyable, NonMovable {
void copy_to_uninitialized_n(const void *src, void *dst, int64_t n) const
{
- BLI_assert(src != dst);
+ BLI_assert(n == 0 || src != dst);
BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
@@ -415,7 +415,7 @@ class CPPType : NonCopyable, NonMovable {
void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask mask) const
{
- BLI_assert(src != dst);
+ BLI_assert(mask.size() == 0 || src != dst);
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
@@ -441,7 +441,7 @@ class CPPType : NonCopyable, NonMovable {
void relocate_to_initialized_n(void *src, void *dst, int64_t n) const
{
- BLI_assert(src != dst);
+ BLI_assert(n == 0 || src != dst);
BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
@@ -450,7 +450,7 @@ class CPPType : NonCopyable, NonMovable {
void relocate_to_initialized_indices(void *src, void *dst, IndexMask mask) const
{
- BLI_assert(src != dst);
+ BLI_assert(mask.size() == 0 || src != dst);
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
@@ -476,7 +476,7 @@ class CPPType : NonCopyable, NonMovable {
void relocate_to_uninitialized_n(void *src, void *dst, int64_t n) const
{
- BLI_assert(src != dst);
+ BLI_assert(n == 0 || src != dst);
BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
@@ -485,7 +485,7 @@ class CPPType : NonCopyable, NonMovable {
void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask mask) const
{
- BLI_assert(src != dst);
+ BLI_assert(mask.size() == 0 || src != dst);
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 93d7b47af83..ac4dca33cf0 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -50,52 +50,56 @@ class MFParamsBuilder {
MFParamsBuilder(const class MultiFunction &fn, int64_t min_array_size);
- template<typename T> void add_readonly_single_input(const T *value)
+ template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
- this->add_readonly_single_input(GVSpan::FromSingle(CPPType::get<T>(), value, min_array_size_));
+ this->add_readonly_single_input(GVSpan::FromSingle(CPPType::get<T>(), value, min_array_size_),
+ expected_name);
}
- void add_readonly_single_input(GVSpan ref)
+ void add_readonly_single_input(GVSpan ref, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()));
+ this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
virtual_spans_.append(ref);
}
- void add_readonly_vector_input(GVArraySpan ref)
+ void add_readonly_vector_input(GVArraySpan ref, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()));
+ this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
virtual_array_spans_.append(ref);
}
- template<typename T> void add_uninitialized_single_output(T *value)
+ template<typename T> void add_uninitialized_single_output(T *value, StringRef expected_name = "")
{
- this->add_uninitialized_single_output(GMutableSpan(CPPType::get<T>(), value, 1));
+ this->add_uninitialized_single_output(GMutableSpan(CPPType::get<T>(), value, 1),
+ expected_name);
}
- void add_uninitialized_single_output(GMutableSpan ref)
+ void add_uninitialized_single_output(GMutableSpan ref, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()));
+ this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
mutable_spans_.append(ref);
}
- void add_vector_output(GVectorArray &vector_array)
+ void add_vector_output(GVectorArray &vector_array, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()));
+ this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()),
+ expected_name);
BLI_assert(vector_array.size() >= min_array_size_);
vector_arrays_.append(&vector_array);
}
- void add_single_mutable(GMutableSpan ref)
+ void add_single_mutable(GMutableSpan ref, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()));
+ this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
mutable_spans_.append(ref);
}
- void add_vector_mutable(GVectorArray &vector_array)
+ void add_vector_mutable(GVectorArray &vector_array, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()));
+ this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()),
+ expected_name);
BLI_assert(vector_array.size() >= min_array_size_);
vector_arrays_.append(&vector_array);
}
@@ -119,11 +123,17 @@ class MFParamsBuilder {
}
private:
- void assert_current_param_type(MFParamType param_type)
+ void assert_current_param_type(MFParamType param_type, StringRef expected_name = "")
{
- UNUSED_VARS_NDEBUG(param_type);
+ UNUSED_VARS_NDEBUG(param_type, expected_name);
#ifdef DEBUG
int param_index = this->current_param_index();
+
+ if (expected_name != "") {
+ StringRef actual_name = signature_->param_names[param_index];
+ BLI_assert(actual_name == expected_name);
+ }
+
MFParamType expected_type = signature_->param_types[param_index];
BLI_assert(expected_type == param_type);
#endif
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index ba79dddff16..3c09d1c961c 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -32,10 +32,9 @@ namespace blender::fn {
struct MFSignature {
std::string function_name;
- /* Use RawAllocator so that a MultiFunction can have static storage duration. */
- RawVector<std::string> param_names;
- RawVector<MFParamType> param_types;
- RawVector<int> param_data_indices;
+ Vector<std::string> param_names;
+ Vector<MFParamType> param_types;
+ Vector<int> param_data_indices;
bool depends_on_context = false;
int data_index(int param_index) const
diff --git a/source/blender/functions/FN_spans.hh b/source/blender/functions/FN_spans.hh
index d8b381199cc..62fa7c8ed4b 100644
--- a/source/blender/functions/FN_spans.hh
+++ b/source/blender/functions/FN_spans.hh
@@ -51,12 +51,12 @@ namespace blender::fn {
class GSpan {
private:
const CPPType *type_;
- const void *buffer_;
+ const void *data_;
int64_t size_;
public:
GSpan(const CPPType &type, const void *buffer, int64_t size)
- : type_(&type), buffer_(buffer), size_(size)
+ : type_(&type), data_(buffer), size_(size)
{
BLI_assert(size >= 0);
BLI_assert(buffer != nullptr || size == 0);
@@ -87,21 +87,21 @@ class GSpan {
return size_;
}
- const void *buffer() const
+ const void *data() const
{
- return buffer_;
+ return data_;
}
const void *operator[](int64_t index) const
{
BLI_assert(index < size_);
- return POINTER_OFFSET(buffer_, type_->size() * index);
+ return POINTER_OFFSET(data_, type_->size() * index);
}
template<typename T> Span<T> typed() const
{
BLI_assert(type_->is<T>());
- return Span<T>((const T *)buffer_, size_);
+ return Span<T>((const T *)data_, size_);
}
};
@@ -112,12 +112,12 @@ class GSpan {
class GMutableSpan {
private:
const CPPType *type_;
- void *buffer_;
+ void *data_;
int64_t size_;
public:
GMutableSpan(const CPPType &type, void *buffer, int64_t size)
- : type_(&type), buffer_(buffer), size_(size)
+ : type_(&type), data_(buffer), size_(size)
{
BLI_assert(size >= 0);
BLI_assert(buffer != nullptr || size == 0);
@@ -136,7 +136,7 @@ class GMutableSpan {
operator GSpan() const
{
- return GSpan(*type_, buffer_, size_);
+ return GSpan(*type_, data_, size_);
}
const CPPType &type() const
@@ -154,21 +154,21 @@ class GMutableSpan {
return size_;
}
- void *buffer()
+ void *data()
{
- return buffer_;
+ return data_;
}
void *operator[](int64_t index)
{
BLI_assert(index < size_);
- return POINTER_OFFSET(buffer_, type_->size() * index);
+ return POINTER_OFFSET(data_, type_->size() * index);
}
template<typename T> MutableSpan<T> typed()
{
BLI_assert(type_->is<T>());
- return MutableSpan<T>((T *)buffer_, size_);
+ return MutableSpan<T>((T *)data_, size_);
}
};
@@ -209,6 +209,20 @@ template<typename T> struct VSpanBase {
return false;
}
+ bool is_full_array() const
+ {
+ switch (category_) {
+ case VSpanCategory::Single:
+ return virtual_size_ == 1;
+ case VSpanCategory::FullArray:
+ return true;
+ case VSpanCategory::FullPointerArray:
+ return virtual_size_ <= 1;
+ }
+ BLI_assert(false);
+ return false;
+ }
+
bool is_empty() const
{
return this->virtual_size_ == 0;
@@ -285,6 +299,22 @@ template<typename T> class VSpan : public VSpanBase<T> {
BLI_assert(false);
return *this->data_.single.data;
}
+
+ const T &as_single_element() const
+ {
+ BLI_assert(this->is_single_element());
+ return (*this)[0];
+ }
+
+ Span<T> as_full_array() const
+ {
+ BLI_assert(this->is_full_array());
+ if (this->virtual_size_ == 0) {
+ return Span<T>();
+ }
+ const T *data = &(*this)[0];
+ return Span<T>(data, this->virtual_size_);
+ }
};
/**
@@ -311,7 +341,7 @@ class GVSpan : public VSpanBase<void> {
this->type_ = &values.type();
this->virtual_size_ = values.size();
this->category_ = VSpanCategory::FullArray;
- this->data_.full_array.data = values.buffer();
+ this->data_.full_array.data = values.data();
}
GVSpan(GMutableSpan values) : GVSpan(GSpan(values))
@@ -395,6 +425,16 @@ class GVSpan : public VSpanBase<void> {
return (*this)[0];
}
+ GSpan as_full_array() const
+ {
+ BLI_assert(this->is_full_array());
+ if (this->virtual_size_ == 0) {
+ return GSpan(*this->type_);
+ }
+ const void *data = (*this)[0];
+ return GSpan(*this->type_, data, this->virtual_size_);
+ }
+
void materialize_to_uninitialized(void *dst) const
{
this->materialize_to_uninitialized(IndexRange(virtual_size_), dst);
diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc
index 7bfcc69671a..4686e217911 100644
--- a/source/blender/functions/intern/attributes_ref.cc
+++ b/source/blender/functions/intern/attributes_ref.cc
@@ -25,7 +25,7 @@ AttributesInfoBuilder::~AttributesInfoBuilder()
}
}
-void AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value)
+bool AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value)
{
if (names_.add_as(name)) {
types_.append(&type);
@@ -36,10 +36,15 @@ void AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void
void *dst = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(default_value, dst);
defaults_.append(dst);
+ return true;
}
else {
- /* The same name can be added more than once as long as the type is always the same. */
- BLI_assert(types_[names_.index_of_as(name)] == &type);
+ const CPPType &stored_type = *types_[names_.index_of_as(name)];
+ if (stored_type != type) {
+ std::cout << "Warning: Tried to add an attribute twice with different types (" << name
+ << ": " << stored_type.name() << ", " << type.name() << ").\n";
+ }
+ return false;
}
}
diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc
index 06084247e66..c9e8b88ba03 100644
--- a/source/blender/functions/intern/multi_function_builder.cc
+++ b/source/blender/functions/intern/multi_function_builder.cc
@@ -34,7 +34,7 @@ void CustomMF_GenericConstant::call(IndexMask mask,
MFContext UNUSED(context)) const
{
GMutableSpan output = params.uninitialized_single_output(0);
- type_.fill_uninitialized_indices(value_, output.buffer(), mask);
+ type_.fill_uninitialized_indices(value_, output.data(), mask);
}
uint64_t CustomMF_GenericConstant::hash() const
@@ -111,7 +111,7 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU
if (param_type.data_type().is_single()) {
GMutableSpan span = params.uninitialized_single_output(param_index);
const CPPType &type = span.type();
- type.fill_uninitialized_indices(type.default_value(), span.buffer(), mask);
+ type.fill_uninitialized_indices(type.default_value(), span.data(), mask);
}
}
}
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index 58577e31c42..25e983d2eeb 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -390,7 +390,7 @@ BLI_NOINLINE void MFNetworkEvaluator::initialize_remaining_outputs(
case MFDataType::Single: {
GVSpan values = storage.get_single_input__full(*socket);
GMutableSpan output_values = params.uninitialized_single_output(param_index);
- values.materialize_to_uninitialized(storage.mask(), output_values.buffer());
+ values.materialize_to_uninitialized(storage.mask(), output_values.data());
break;
}
case MFDataType::Vector: {
@@ -524,11 +524,11 @@ MFNetworkEvaluationStorage::~MFNetworkEvaluationStorage()
GMutableSpan span = value->span;
const CPPType &type = span.type();
if (value->is_single_allocated) {
- type.destruct(span.buffer());
+ type.destruct(span.data());
}
else {
- type.destruct_indices(span.buffer(), mask_);
- MEM_freeN(span.buffer());
+ type.destruct_indices(span.data(), mask_);
+ MEM_freeN(span.data());
}
}
else if (any_value->type == ValueType::OwnVector) {
@@ -634,11 +634,11 @@ void MFNetworkEvaluationStorage::finish_input_socket(const MFInputSocket &socket
GMutableSpan span = value->span;
const CPPType &type = span.type();
if (value->is_single_allocated) {
- type.destruct(span.buffer());
+ type.destruct(span.data());
}
else {
- type.destruct_indices(span.buffer(), mask_);
- MEM_freeN(span.buffer());
+ type.destruct_indices(span.data(), mask_);
+ MEM_freeN(span.data());
}
value_per_output_id_[origin.id()] = nullptr;
}
@@ -791,7 +791,7 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
BLI_assert(to_any_value->type == ValueType::OutputSingle);
GMutableSpan span = ((OutputSingleValue *)to_any_value)->span;
GVSpan virtual_span = this->get_single_input__full(input);
- virtual_span.materialize_to_uninitialized(mask_, span.buffer());
+ virtual_span.materialize_to_uninitialized(mask_, span.data());
return span;
}
@@ -808,7 +808,7 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
GVSpan virtual_span = this->get_single_input__full(input);
void *new_buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT);
GMutableSpan new_array_ref(type, new_buffer, min_array_size_);
- virtual_span.materialize_to_uninitialized(mask_, new_array_ref.buffer());
+ virtual_span.materialize_to_uninitialized(mask_, new_array_ref.data());
OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>(
new_array_ref, to.targets().size(), false);
@@ -953,7 +953,7 @@ GVSpan MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &s
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = (OwnSingleValue *)any_value;
if (value->is_single_allocated) {
- return GVSpan::FromSingle(value->span.type(), value->span.buffer(), min_array_size_);
+ return GVSpan::FromSingle(value->span.type(), value->span.data(), min_array_size_);
}
else {
return value->span;
diff --git a/source/blender/functions/intern/multi_function_network_optimization.cc b/source/blender/functions/intern/multi_function_network_optimization.cc
index f1e047f01a1..af1e77aa355 100644
--- a/source/blender/functions/intern/multi_function_network_optimization.cc
+++ b/source/blender/functions/intern/multi_function_network_optimization.cc
@@ -28,6 +28,7 @@
#include "BLI_disjoint_set.hh"
#include "BLI_ghash.h"
#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
#include "BLI_rand.h"
#include "BLI_stack.hh"
@@ -265,7 +266,7 @@ static Array<MFOutputSocket *> add_constant_folded_sockets(const MultiFunction &
case MFDataType::Single: {
const CPPType &cpp_type = data_type.single_type();
GMutableSpan array = params.computed_array(param_index);
- void *buffer = array.buffer();
+ void *buffer = array.data();
resources.add(buffer, array.type().destruct_cb(), AT);
constant_fn = &resources.construct<CustomMF_GenericConstant>(AT, cpp_type, buffer);
@@ -403,15 +404,15 @@ static Array<uint64_t> compute_node_hashes(MFNetwork &network)
return node_hashes;
}
-static Map<uint64_t, Vector<MFNode *, 1>> group_nodes_by_hash(MFNetwork &network,
- Span<uint64_t> node_hashes)
+static MultiValueMap<uint64_t, MFNode *> group_nodes_by_hash(MFNetwork &network,
+ Span<uint64_t> node_hashes)
{
- Map<uint64_t, Vector<MFNode *, 1>> nodes_by_hash;
+ MultiValueMap<uint64_t, MFNode *> nodes_by_hash;
for (int id : IndexRange(network.node_id_amount())) {
MFNode *node = network.node_or_null_by_id(id);
if (node != nullptr) {
uint64_t node_hash = node_hashes[id];
- nodes_by_hash.lookup_or_add_default(node_hash).append(node);
+ nodes_by_hash.add(node_hash, node);
}
}
return nodes_by_hash;
@@ -456,7 +457,7 @@ static bool nodes_output_same_values(DisjointSet &cache, const MFNode &a, const
}
static void relink_duplicate_nodes(MFNetwork &network,
- Map<uint64_t, Vector<MFNode *, 1>> &nodes_by_hash)
+ MultiValueMap<uint64_t, MFNode *> &nodes_by_hash)
{
DisjointSet same_node_cache{network.node_id_amount()};
@@ -494,7 +495,7 @@ static void relink_duplicate_nodes(MFNetwork &network,
void common_subnetwork_elimination(MFNetwork &network)
{
Array<uint64_t> node_hashes = compute_node_hashes(network);
- Map<uint64_t, Vector<MFNode *, 1>> nodes_by_hash = group_nodes_by_hash(network, node_hashes);
+ MultiValueMap<uint64_t, MFNode *> nodes_by_hash = group_nodes_by_hash(network, node_hashes);
relink_duplicate_nodes(network, nodes_by_hash);
}
diff --git a/tests/gtests/functions/FN_array_spans_test.cc b/source/blender/functions/tests/FN_array_spans_test.cc
index 6b7bb8429ff..9a632b58be8 100644
--- a/tests/gtests/functions/FN_array_spans_test.cc
+++ b/source/blender/functions/tests/FN_array_spans_test.cc
@@ -7,7 +7,7 @@
#include "BLI_array.hh"
-namespace blender::fn {
+namespace blender::fn::tests {
TEST(virtual_array_span, EmptyConstructor)
{
@@ -129,4 +129,4 @@ TEST(generic_virtual_array_span, IsSingleArray2)
EXPECT_FALSE(converted.is_single_array());
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/tests/gtests/functions/FN_attributes_ref_test.cc b/source/blender/functions/tests/FN_attributes_ref_test.cc
index 9c7cce83493..3a5e4743c1e 100644
--- a/tests/gtests/functions/FN_attributes_ref_test.cc
+++ b/source/blender/functions/tests/FN_attributes_ref_test.cc
@@ -5,7 +5,7 @@
#include "testing/testing.h"
-namespace blender::fn {
+namespace blender::fn::tests {
TEST(attributes_info, BuildEmpty)
{
@@ -68,10 +68,10 @@ TEST(mutable_attributes_ref, ComplexTest)
MutableAttributesRef attributes{info, buffers, IndexRange(1, 3)};
EXPECT_EQ(attributes.size(), 3);
EXPECT_EQ(attributes.info().size(), 4);
- EXPECT_EQ(attributes.get("Position").buffer(), positions.data() + 1);
- EXPECT_EQ(attributes.get("ID").buffer(), ids.data() + 1);
- EXPECT_EQ(attributes.get("Size").buffer(), sizes.data() + 1);
- EXPECT_EQ(attributes.get("Name").buffer(), names.data() + 1);
+ EXPECT_EQ(attributes.get("Position").data(), positions.data() + 1);
+ EXPECT_EQ(attributes.get("ID").data(), ids.data() + 1);
+ EXPECT_EQ(attributes.get("Size").data(), sizes.data() + 1);
+ EXPECT_EQ(attributes.get("Name").data(), names.data() + 1);
EXPECT_EQ(attributes.get("ID").size(), 3);
EXPECT_EQ(attributes.get<uint>("ID").size(), 3);
@@ -94,4 +94,4 @@ TEST(mutable_attributes_ref, ComplexTest)
EXPECT_EQ(ids[2], 100);
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/tests/gtests/functions/FN_cpp_type_test.cc b/source/blender/functions/tests/FN_cpp_type_test.cc
index 85fc1105c25..29368b251cc 100644
--- a/tests/gtests/functions/FN_cpp_type_test.cc
+++ b/source/blender/functions/tests/FN_cpp_type_test.cc
@@ -4,7 +4,7 @@
#include "FN_cpp_type.hh"
-namespace blender::fn {
+namespace blender::fn::tests {
static const int default_constructed_value = 1;
static const int copy_constructed_value = 2;
@@ -62,7 +62,7 @@ struct TestType {
return stream;
}
- friend bool operator==(const TestType &a, const TestType &b)
+ friend bool operator==(const TestType &UNUSED(a), const TestType &UNUSED(b))
{
return false;
}
@@ -73,7 +73,11 @@ struct TestType {
}
};
-MAKE_CPP_TYPE(TestType, TestType)
+} // namespace blender::fn::tests
+
+MAKE_CPP_TYPE(TestType, blender::fn::tests::TestType)
+
+namespace blender::fn::tests {
const CPPType &CPPType_TestType = CPPType::get<TestType>();
@@ -318,4 +322,4 @@ TEST(cpp_type, DebugPrint)
EXPECT_EQ(text, "42");
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/tests/gtests/functions/FN_generic_vector_array_test.cc b/source/blender/functions/tests/FN_generic_vector_array_test.cc
index cfca678ad27..77ec05f12dc 100644
--- a/tests/gtests/functions/FN_generic_vector_array_test.cc
+++ b/source/blender/functions/tests/FN_generic_vector_array_test.cc
@@ -4,7 +4,7 @@
#include "testing/testing.h"
-namespace blender::fn {
+namespace blender::fn::tests {
TEST(generic_vector_array, Constructor)
{
@@ -98,4 +98,4 @@ TEST(generic_vector_array, Extend)
EXPECT_EQ(ref[0][0], 3);
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/tests/gtests/functions/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc
index 9f16b71bb10..53290e9170c 100644
--- a/tests/gtests/functions/FN_multi_function_network_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_network_test.cc
@@ -6,7 +6,7 @@
#include "FN_multi_function_network.hh"
#include "FN_multi_function_network_evaluation.hh"
-namespace blender::fn {
+namespace blender::fn::tests {
TEST(multi_function_network, Test1)
{
@@ -250,4 +250,4 @@ TEST(multi_function_network, Test2)
}
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/tests/gtests/functions/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc
index 8b5fb060c36..6acb6e22b01 100644
--- a/tests/gtests/functions/FN_multi_function_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_test.cc
@@ -5,7 +5,7 @@
#include "FN_multi_function.hh"
#include "FN_multi_function_builder.hh"
-namespace blender::fn {
+namespace blender::fn::tests {
class AddFunction : public MultiFunction {
public:
@@ -382,4 +382,4 @@ TEST(multi_function, CustomMF_Convert)
EXPECT_EQ(outputs[2], 9);
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/tests/gtests/functions/FN_spans_test.cc b/source/blender/functions/tests/FN_spans_test.cc
index 3172cdc7170..fbcf1fda71e 100644
--- a/tests/gtests/functions/FN_spans_test.cc
+++ b/source/blender/functions/tests/FN_spans_test.cc
@@ -4,7 +4,7 @@
#include "FN_spans.hh"
-namespace blender::fn {
+namespace blender::fn::tests {
TEST(generic_span, TypeConstructor)
{
@@ -56,6 +56,7 @@ TEST(virtual_span, EmptyConstructor)
EXPECT_EQ(span.size(), 0);
EXPECT_TRUE(span.is_empty());
EXPECT_FALSE(span.is_single_element());
+ EXPECT_TRUE(span.is_full_array());
GVSpan converted(span);
EXPECT_EQ(converted.type(), CPPType::get<int>());
@@ -73,6 +74,7 @@ TEST(virtual_span, SpanConstructor)
EXPECT_EQ(virtual_span[2], 8);
EXPECT_EQ(virtual_span[3], 6);
EXPECT_FALSE(virtual_span.is_single_element());
+ EXPECT_TRUE(virtual_span.is_full_array());
GVSpan converted(span);
EXPECT_EQ(converted.type(), CPPType::get<int>());
@@ -93,6 +95,7 @@ TEST(virtual_span, PointerSpanConstructor)
EXPECT_EQ(span[2], 6);
EXPECT_EQ(&span[1], &x2);
EXPECT_FALSE(span.is_single_element());
+ EXPECT_FALSE(span.is_full_array());
GVSpan converted(span);
EXPECT_EQ(converted.type(), CPPType::get<int>());
@@ -115,6 +118,7 @@ TEST(virtual_span, SingleConstructor)
EXPECT_EQ(&span[1], &value);
EXPECT_EQ(&span[2], &value);
EXPECT_TRUE(span.is_single_element());
+ EXPECT_FALSE(span.is_full_array());
GVSpan converted(span);
EXPECT_EQ(converted.type(), CPPType::get<int>());
@@ -130,6 +134,7 @@ TEST(generic_virtual_span, TypeConstructor)
EXPECT_EQ(span.size(), 0);
EXPECT_TRUE(span.is_empty());
EXPECT_FALSE(span.is_single_element());
+ EXPECT_TRUE(span.is_full_array());
VSpan<int> converted = span.typed<int>();
EXPECT_EQ(converted.size(), 0);
@@ -146,6 +151,7 @@ TEST(generic_virtual_span, GenericSpanConstructor)
EXPECT_EQ(span[2], &values[2]);
EXPECT_EQ(span[3], &values[3]);
EXPECT_FALSE(span.is_single_element());
+ EXPECT_TRUE(span.is_full_array());
int materialized[4] = {0};
span.materialize_to_uninitialized(materialized);
@@ -172,6 +178,7 @@ TEST(generic_virtual_span, SpanConstructor)
EXPECT_EQ(span[1], &values[1]);
EXPECT_EQ(span[2], &values[2]);
EXPECT_FALSE(span.is_single_element());
+ EXPECT_TRUE(span.is_full_array());
int materialized[3] = {0};
span.materialize_to_uninitialized(materialized);
@@ -197,6 +204,7 @@ TEST(generic_virtual_span, SingleConstructor)
EXPECT_EQ(span[2], &value);
EXPECT_TRUE(span.is_single_element());
EXPECT_EQ(span.as_single_element(), &value);
+ EXPECT_FALSE(span.is_full_array());
int materialized[3] = {0};
span.materialize_to_uninitialized({1, 2}, materialized);
@@ -211,4 +219,4 @@ TEST(generic_virtual_span, SingleConstructor)
EXPECT_EQ(converted[2], 5);
}
-} // namespace blender::fn
+} // namespace blender::fn::tests
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index 9cc3712e8f4..75f929e979e 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -105,19 +105,23 @@ static void deformStroke(GpencilModifierData *md,
bGPDspoint *pt = &gps->points[i];
MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
- /* verify vertex group */
+ /* Verify vertex group. */
const float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_OFFSET_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
continue;
}
- /* calculate matrix */
+ /* Calculate matrix. */
mul_v3_v3fl(loc, mmd->loc, weight);
mul_v3_v3fl(rot, mmd->rot, weight);
mul_v3_v3fl(scale, mmd->scale, weight);
add_v3_fl(scale, 1.0);
loc_eul_size_to_mat4(mat, loc, rot, scale);
+ /* Apply scale to thickness. */
+ float unit_scale = (scale[0] + scale[1] + scale[2]) / 3.0f;
+ pt->pressure *= unit_scale;
+
mul_m4_v3(mat, &pt->x);
}
/* Calc geometry data. */
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 4f90482d16e..98a885f88e1 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -52,38 +52,37 @@ set(INC_SYS
)
set(SRC
- intern/gpu_attr_binding.c
- intern/gpu_batch.c
+ intern/gpu_attr_binding.cc
+ intern/gpu_batch.cc
intern/gpu_batch_presets.c
intern/gpu_batch_utils.c
intern/gpu_buffers.c
intern/gpu_codegen.c
- intern/gpu_context.cpp
- intern/gpu_debug.c
- intern/gpu_draw.c
- intern/gpu_draw_smoke.c
- intern/gpu_element.c
- intern/gpu_extensions.c
- intern/gpu_framebuffer.c
- intern/gpu_immediate.c
+ intern/gpu_context.cc
+ intern/gpu_debug.cc
+ intern/gpu_element.cc
+ intern/gpu_extensions.cc
+ intern/gpu_framebuffer.cc
+ intern/gpu_immediate.cc
intern/gpu_immediate_util.c
intern/gpu_init_exit.c
intern/gpu_material.c
intern/gpu_material_library.c
intern/gpu_matrix.c
intern/gpu_node_graph.c
- intern/gpu_platform.c
+ intern/gpu_platform.cc
intern/gpu_primitive.c
intern/gpu_select.c
intern/gpu_select_pick.c
intern/gpu_select_sample_query.c
- intern/gpu_shader.c
+ intern/gpu_shader.cc
+ intern/gpu_shader_builtin.c
intern/gpu_shader_interface.c
- intern/gpu_state.c
- intern/gpu_texture.c
- intern/gpu_uniformbuffer.c
- intern/gpu_vertex_buffer.c
- intern/gpu_vertex_format.c
+ intern/gpu_state.cc
+ intern/gpu_texture.cc
+ intern/gpu_uniformbuffer.cc
+ intern/gpu_vertex_buffer.cc
+ intern/gpu_vertex_format.cc
intern/gpu_viewport.c
GPU_attr_binding.h
@@ -94,7 +93,6 @@ set(SRC
GPU_common.h
GPU_context.h
GPU_debug.h
- GPU_draw.h
GPU_element.h
GPU_extensions.h
GPU_framebuffer.h
@@ -216,6 +214,8 @@ data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_codegen_lib.glsl SRC)
+
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_add_shader.glsl SRC)
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 5f55b512695..85d9c037b38 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -127,9 +127,8 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
#define GPU_batch_vertbuf_add(batch, verts) GPU_batch_vertbuf_add_ex(batch, verts, false)
-void GPU_batch_program_set_no_use(GPUBatch *, uint32_t program, const GPUShaderInterface *);
-void GPU_batch_program_set(GPUBatch *, uint32_t program, const GPUShaderInterface *);
-void GPU_batch_program_set_shader(GPUBatch *, GPUShader *shader);
+void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader);
+void GPU_batch_set_shader_no_bind(GPUBatch *batch, GPUShader *shader);
void GPU_batch_program_set_imm_shader(GPUBatch *batch);
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id);
void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index 8928581ee08..fc6ca791664 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -24,8 +24,6 @@
#ifndef __GPU_DEBUG_H__
#define __GPU_DEBUG_H__
-#include "GPU_glew.h"
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
deleted file mode 100644
index b364bd0ef95..00000000000
--- a/source/blender/gpu/GPU_draw.h
+++ /dev/null
@@ -1,95 +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.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup gpu
- */
-
-#ifndef __GPU_DRAW_H__
-#define __GPU_DRAW_H__
-
-#include "BLI_utildefines.h"
-#include "DNA_object_enums.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct FluidModifierData;
-struct ImBuf;
-struct Image;
-struct ImageUser;
-struct Main;
-
-/* OpenGL drawing functions related to shading. */
-
-/* Mipmap settings
- * - these will free textures on changes */
-
-void GPU_set_mipmap(struct Main *bmain, bool mipmap);
-bool GPU_get_mipmap(void);
-void GPU_set_linear_mipmap(bool linear);
-bool GPU_get_linear_mipmap(void);
-void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap);
-
-/* Anisotropic filtering settings
- * - these will free textures on changes */
-void GPU_set_anisotropic(float value);
-float GPU_get_anisotropic(void);
-
-/* Image updates and free
- * - these deal with images bound as opengl textures */
-
-void GPU_paint_update_image(
- struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
-void GPU_create_gl_tex(unsigned int *bind,
- unsigned int *rect,
- float *frect,
- int rectw,
- int recth,
- int textarget,
- bool mipmap,
- bool half_float,
- bool use_srgb,
- struct Image *ima);
-void GPU_create_gl_tex_compressed(unsigned int *bind,
- int textarget,
- struct Image *ima,
- struct ImBuf *ibuf);
-bool GPU_upload_dxt_texture(struct ImBuf *ibuf, bool use_srgb);
-void GPU_free_image(struct Image *ima);
-void GPU_free_images(struct Main *bmain);
-void GPU_free_images_anim(struct Main *bmain);
-void GPU_free_images_old(struct Main *bmain);
-
-/* gpu_draw_smoke.c */
-void GPU_free_smoke(struct FluidModifierData *fmd);
-void GPU_free_smoke_velocity(struct FluidModifierData *fmd);
-void GPU_create_smoke(struct FluidModifierData *fmd, int highres);
-void GPU_create_smoke_coba_field(struct FluidModifierData *fmd);
-void GPU_create_smoke_velocity(struct FluidModifierData *fmd);
-
-/* Delayed free of OpenGL buffers by main thread */
-void GPU_free_unused_buffers(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 263deeaf28d..0d8954dc16c 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -52,6 +52,8 @@ bool GPU_context_local_shaders_workaround(void);
bool GPU_texture_copy_workaround(void);
bool GPU_crappy_amd_driver(void);
+int GPU_texture_size_with_limit(int res);
+
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 0a43b2c58a0..db531cdef9b 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -32,7 +32,7 @@ extern "C" {
typedef struct GPUAttachment {
struct GPUTexture *tex;
- int mip, layer;
+ int layer, mip;
} GPUAttachment;
typedef enum eGPUFrameBufferBits {
@@ -120,35 +120,35 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *confi
#define GPU_ATTACHMENT_NONE \
{ \
- .tex = NULL, .layer = -1, .mip = 0, \
+ NULL, -1, 0, \
}
#define GPU_ATTACHMENT_LEAVE \
{ \
- .tex = NULL, .layer = -1, .mip = -1, \
+ NULL, -1, -1, \
}
#define GPU_ATTACHMENT_TEXTURE(_tex) \
{ \
- .tex = _tex, .layer = -1, .mip = 0, \
+ _tex, -1, 0, \
}
#define GPU_ATTACHMENT_TEXTURE_MIP(_tex, _mip) \
{ \
- .tex = _tex, .layer = -1, .mip = _mip, \
+ _tex, -1, _mip, \
}
#define GPU_ATTACHMENT_TEXTURE_LAYER(_tex, _layer) \
{ \
- .tex = _tex, .layer = _layer, .mip = 0, \
+ _tex, _layer, 0, \
}
#define GPU_ATTACHMENT_TEXTURE_LAYER_MIP(_tex, _layer, _mip) \
{ \
- .tex = _tex, .layer = _layer, .mip = _mip, \
+ _tex, _layer, _mip, \
}
#define GPU_ATTACHMENT_TEXTURE_CUBEFACE(_tex, _face) \
{ \
- .tex = _tex, .layer = _face, .mip = 0, \
+ _tex, _face, 0, \
}
#define GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(_tex, _face, _mip) \
{ \
- .tex = _tex, .layer = _face, .mip = _mip, \
+ _tex, _face, _mip, \
}
/* Framebuffer operations */
@@ -212,7 +212,7 @@ GPUOffScreen *GPU_offscreen_create(
void GPU_offscreen_free(GPUOffScreen *ofs);
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
-void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
+void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat type, void *pixels);
void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y);
int GPU_offscreen_width(const GPUOffScreen *ofs);
int GPU_offscreen_height(const GPUOffScreen *ofs);
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
index 698c4585d20..869c1fff29d 100644
--- a/source/blender/gpu/GPU_immediate.h
+++ b/source/blender/gpu/GPU_immediate.h
@@ -42,7 +42,7 @@ extern "C" {
GPUVertFormat *immVertexFormat(void);
/** Every immBegin must have a program bound first. */
-void immBindProgram(uint32_t program, const GPUShaderInterface *);
+void immBindShader(GPUShader *shader);
/** Call after your last immEnd, or before binding another program. */
void immUnbindProgram(void);
@@ -134,7 +134,7 @@ void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a);
void immUniformColor4ubv(const unsigned char rgba[4]);
/**
- * Extend #immBindProgram to use Blender’s library of built-in shader programs.
+ * Extend #immBindShader to use Blender’s library of built-in shader programs.
* Use #immUnbindProgram() when done.
*/
void immBindBuiltinProgram(eGPUBuiltinShader shader_id);
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index c372bfaf218..7512fac6410 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -110,6 +110,7 @@ typedef enum eGPUMatFlag {
GPU_MATFLAG_GLOSSY = (1 << 1),
GPU_MATFLAG_REFRACT = (1 << 2),
GPU_MATFLAG_SSS = (1 << 3),
+ GPU_MATFLAG_BARYCENTRIC = (1 << 4),
} eGPUMatFlag;
typedef enum eGPUBlendMode {
@@ -137,6 +138,13 @@ typedef enum eGPUMaterialStatus {
GPU_MAT_SUCCESS,
} eGPUMaterialStatus;
+typedef void (*GPUMaterialEvalCallbackFn)(GPUMaterial *mat,
+ int options,
+ const char **vert_code,
+ const char **geom_code,
+ const char **frag_lib,
+ const char **defines);
+
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name);
@@ -190,7 +198,8 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
const char *geom_code,
const char *frag_lib,
const char *defines,
- const char *name);
+ const char *name,
+ GPUMaterialEvalCallbackFn callback);
void GPU_material_compile(GPUMaterial *mat);
void GPU_material_free(struct ListBase *gpumaterial);
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index f199a748cb5..104d5ef0ddc 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -25,10 +25,7 @@
#define __GPU_PLATFORM_H__
#include "BLI_sys_types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "BLI_utildefines.h"
/* GPU platform support */
@@ -43,6 +40,8 @@ typedef enum eGPUDeviceType {
GPU_DEVICE_ANY = (0xff),
} eGPUDeviceType;
+ENUM_OPERATORS(eGPUDeviceType)
+
typedef enum eGPUOSType {
GPU_OS_WIN = (1 << 8),
GPU_OS_MAC = (1 << 9),
@@ -63,6 +62,10 @@ typedef enum eGPUSupportLevel {
GPU_SUPPORT_LEVEL_UNSUPPORTED,
} eGPUSupportLevel;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_support_level_key(void);
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index a19ed2d84fd..b51a63a1c1f 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -87,8 +87,6 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader);
int GPU_shader_get_program(GPUShader *shader);
-void *GPU_shader_get_interface(GPUShader *shader);
-
void GPU_shader_set_srgb_uniform(const struct GPUShaderInterface *interface);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 8d50330ac93..a71b44507ba 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -87,6 +87,7 @@ bool GPU_depth_mask_get(void);
void GPU_stencil_mask(uint stencil);
void GPU_unpack_row_length_set(uint len);
void GPU_clip_distances(int enabled_len);
+bool GPU_mipmap_enabled(void);
void GPU_flush(void);
void GPU_finish(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index de08391b40c..1fbcfd41dec 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -25,6 +25,7 @@
#define __GPU_TEXTURE_H__
#include "BLI_utildefines.h"
+
#include "GPU_state.h"
struct GPUVertBuf;
@@ -43,7 +44,6 @@ typedef struct GPUTexture GPUTexture;
* - Internally used by textures.
* - All states are created at startup to avoid runtime costs.
*/
-
typedef enum eGPUSamplerState {
GPU_SAMPLER_FILTER = (1 << 0),
GPU_SAMPLER_MIPMAP = (1 << 1),
@@ -57,6 +57,8 @@ typedef enum eGPUSamplerState {
GPU_SAMPLER_MAX = (1 << 8),
} eGPUSamplerState;
+ENUM_OPERATORS(eGPUSamplerState)
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -121,7 +123,6 @@ typedef enum eGPUTextureFormat {
#if 0
GPU_RGB10_A2,
GPU_RGB10_A2UI,
- GPU_SRGB8_A8,
#endif
GPU_R11F_G11F_B10F,
GPU_DEPTH32F_STENCIL8,
@@ -150,7 +151,13 @@ typedef enum eGPUTextureFormat {
GPU_R8_SNORM,
#endif
-/* Special formats texture only */
+ /* Special formats texture only */
+ GPU_SRGB8_A8_DXT1,
+ GPU_SRGB8_A8_DXT3,
+ GPU_SRGB8_A8_DXT5,
+ GPU_RGBA8_DXT1,
+ GPU_RGBA8_DXT3,
+ GPU_RGBA8_DXT5,
#if 0
GPU_SRGB8,
GPU_RGB9_E5,
@@ -223,17 +230,10 @@ GPUTexture *GPU_texture_create_cube_array(
GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert);
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer);
-GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode);
-GPUTexture *GPU_texture_from_blender(struct Image *ima,
- struct ImageUser *iuser,
- struct ImBuf *ibuf,
- int textarget);
+GPUTexture *GPU_texture_create_compressed(
+ int w, int h, int miplen, eGPUTextureFormat format, const void *data);
-/* movie clip drawing */
-GPUTexture *GPU_texture_from_movieclip(struct MovieClip *clip,
- struct MovieClipUser *cuser,
- int textarget);
-void GPU_free_texture_movieclip(struct MovieClip *clip);
+GPUTexture *GPU_texture_create_error(int dimension, bool array);
void GPU_texture_add_mipmap(GPUTexture *tex,
eGPUDataFormat gpu_data_format,
@@ -269,6 +269,7 @@ void GPU_texture_unbind_all(void);
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
+void GPU_texture_anisotropic_filter(GPUTexture *tex, bool use_aniso);
void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter);
diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h
index b221ae035d3..6862c1d960d 100644
--- a/source/blender/gpu/GPU_uniformbuffer.h
+++ b/source/blender/gpu/GPU_uniformbuffer.h
@@ -42,8 +42,7 @@ void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_);
void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number);
void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo);
-
-int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo);
+void GPU_uniformbuffer_unbind_all(void);
bool GPU_uniformbuffer_is_empty(GPUUniformBuffer *ubo);
bool GPU_uniformbuffer_is_dirty(GPUUniformBuffer *ubo);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index f9bdf726930..d1693852c1a 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -59,10 +59,10 @@ typedef struct GPUVertBuf {
/** 0 indicates not yet allocated. */
uint32_t vbo_id;
/** Usage hint for GL optimisation. */
- uint usage : 2;
+ GPUUsageType usage;
/** Data has been touched and need to be reuploaded to GPU. */
- uint dirty : 1;
- unsigned char *data; /* NULL indicates data in VRAM (unmapped) */
+ bool dirty;
+ uchar *data; /* NULL indicates data in VRAM (unmapped) */
} GPUVertBuf;
GPUVertBuf *GPU_vertbuf_create(GPUUsageType);
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 34bfbb27823..cf0f52e3950 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -42,7 +42,7 @@ extern "C" {
#define GPU_MAX_SAFE_ATTR_NAME 12
typedef enum {
- GPU_COMP_I8,
+ GPU_COMP_I8 = 0,
GPU_COMP_U8,
GPU_COMP_I16,
GPU_COMP_U16,
@@ -52,17 +52,21 @@ typedef enum {
GPU_COMP_F32,
GPU_COMP_I10,
+ /* Warning! adjust GPUVertAttr if changing. */
} GPUVertCompType;
typedef enum {
- GPU_FETCH_FLOAT,
+ GPU_FETCH_FLOAT = 0,
GPU_FETCH_INT,
GPU_FETCH_INT_TO_FLOAT_UNIT, /* 127 (ubyte) -> 0.5 (and so on for other int types) */
GPU_FETCH_INT_TO_FLOAT, /* 127 (any int type) -> 127.0 */
+ /* Warning! adjust GPUVertAttr if changing. */
} GPUVertFetchMode;
typedef struct GPUVertAttr {
+ /* GPUVertFetchMode */
uint fetch_mode : 2;
+ /* GPUVertCompType */
uint comp_type : 3;
/* 1 to 4 or 8 or 12 or 16 */
uint comp_len : 5;
@@ -72,8 +76,6 @@ typedef struct GPUVertAttr {
uint offset : 11;
/* up to GPU_VERT_ATTR_MAX_NAMES */
uint name_len : 3;
- uint gl_comp_type;
- /* -- 8 Bytes -- */
uchar names[GPU_VERT_ATTR_MAX_NAMES];
} GPUVertAttr;
diff --git a/source/blender/gpu/intern/gpu_attr_binding.c b/source/blender/gpu/intern/gpu_attr_binding.cc
index 6cb60884620..6cb60884620 100644
--- a/source/blender/gpu/intern/gpu_attr_binding.c
+++ b/source/blender/gpu/intern/gpu_attr_binding.cc
diff --git a/source/blender/gpu/intern/gpu_attr_binding_private.h b/source/blender/gpu/intern/gpu_attr_binding_private.h
index 301ec3333dd..7df403a3ea5 100644
--- a/source/blender/gpu/intern/gpu_attr_binding_private.h
+++ b/source/blender/gpu/intern/gpu_attr_binding_private.h
@@ -29,6 +29,11 @@
#include "GPU_shader_interface.h"
#include "GPU_vertex_format.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* TODO(fclem) remove, use shaderface directly. */
void AttrBinding_clear(GPUAttrBinding *binding);
void get_attr_locations(const GPUVertFormat *format,
@@ -36,4 +41,8 @@ void get_attr_locations(const GPUVertFormat *format,
const GPUShaderInterface *shaderface);
uint read_attr_location(const GPUAttrBinding *binding, uint a_idx);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __GPU_ATTR_BINDING_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.cc
index 5f77f13c135..9f9adcacfa6 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -37,6 +37,7 @@
#include "gpu_context_private.h"
#include "gpu_primitive_private.h"
#include "gpu_shader_private.h"
+#include "gpu_vertex_format_private.h"
#include <limits.h>
#include <stdlib.h>
@@ -89,7 +90,7 @@ GPUBatch *GPU_batch_create_ex(GPUPrimType prim_type,
GPUIndexBuf *elem,
uint owns_flag)
{
- GPUBatch *batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
+ GPUBatch *batch = (GPUBatch *)MEM_callocN(sizeof(GPUBatch), "GPUBatch");
GPU_batch_init_ex(batch, prim_type, verts, elem, owns_flag);
return batch;
}
@@ -327,10 +328,10 @@ static GLuint batch_vao_get(GPUBatch *batch)
}
/* Init dynamic arrays and let the branch below set the values. */
batch->dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT;
- batch->dynamic_vaos.interfaces = MEM_callocN(
+ batch->dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_callocN(
batch->dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces");
- batch->dynamic_vaos.vao_ids = MEM_callocN(batch->dynamic_vaos.count * sizeof(GLuint),
- "dyn vaos ids");
+ batch->dynamic_vaos.vao_ids = (GLuint *)MEM_callocN(
+ batch->dynamic_vaos.count * sizeof(GLuint), "dyn vaos ids");
}
}
@@ -346,11 +347,11 @@ static GLuint batch_vao_get(GPUBatch *batch)
/* Not enough place, realloc the array. */
i = batch->dynamic_vaos.count;
batch->dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT;
- batch->dynamic_vaos.interfaces = MEM_recallocN((void *)batch->dynamic_vaos.interfaces,
- sizeof(GPUShaderInterface *) *
- batch->dynamic_vaos.count);
- batch->dynamic_vaos.vao_ids = MEM_recallocN(batch->dynamic_vaos.vao_ids,
- sizeof(GLuint) * batch->dynamic_vaos.count);
+ batch->dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_recallocN(
+ (void *)batch->dynamic_vaos.interfaces,
+ sizeof(GPUShaderInterface *) * batch->dynamic_vaos.count);
+ batch->dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(
+ batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count);
}
batch->dynamic_vaos.interfaces[i] = batch->interface;
batch->dynamic_vaos.vao_ids[i] = new_vao = GPU_vao_alloc();
@@ -370,22 +371,20 @@ static GLuint batch_vao_get(GPUBatch *batch)
return new_vao;
}
-void GPU_batch_program_set_no_use(GPUBatch *batch,
- uint32_t program,
- const GPUShaderInterface *shaderface)
+void GPU_batch_set_shader_no_bind(GPUBatch *batch, GPUShader *shader)
{
#if TRUST_NO_ONE
- assert(glIsProgram(program));
+ assert(glIsProgram(shader->program));
assert(batch->program_in_use == 0);
#endif
- batch->interface = shaderface;
- batch->program = program;
+ batch->interface = shader->interface;
+ batch->program = shader->program;
batch->vao_id = batch_vao_get(batch);
}
-void GPU_batch_program_set(GPUBatch *batch, uint32_t program, const GPUShaderInterface *shaderface)
+void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader)
{
- GPU_batch_program_set_no_use(batch, program, shaderface);
+ GPU_batch_set_shader_no_bind(batch, shader);
GPU_batch_program_use_begin(batch); /* hack! to make Batch_Uniform* simpler */
}
@@ -440,6 +439,7 @@ static void create_bindings(GPUVertBuf *verts,
}
const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride;
+ const GLenum type = convert_comp_type_to_gl(static_cast<GPUVertCompType>(a->comp_type));
for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
@@ -452,19 +452,13 @@ static void create_bindings(GPUVertBuf *verts,
*attr_mask &= ~(1 << input->location);
if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) {
-#if TRUST_NO_ONE
- assert(a->fetch_mode == GPU_FETCH_FLOAT);
- assert(a->gl_comp_type == GL_FLOAT);
-#endif
+ BLI_assert(a->fetch_mode == GPU_FETCH_FLOAT);
+ BLI_assert(a->comp_type == GPU_COMP_F32);
for (int i = 0; i < a->comp_len / 4; i++) {
glEnableVertexAttribArray(input->location + i);
glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0);
- glVertexAttribPointer(input->location + i,
- 4,
- a->gl_comp_type,
- GL_FALSE,
- stride,
- (const GLubyte *)pointer + i * 16);
+ glVertexAttribPointer(
+ input->location + i, 4, type, GL_FALSE, stride, (const GLubyte *)pointer + i * 16);
}
}
else {
@@ -474,15 +468,13 @@ static void create_bindings(GPUVertBuf *verts,
switch (a->fetch_mode) {
case GPU_FETCH_FLOAT:
case GPU_FETCH_INT_TO_FLOAT:
- glVertexAttribPointer(
- input->location, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer);
+ glVertexAttribPointer(input->location, a->comp_len, type, GL_FALSE, stride, pointer);
break;
case GPU_FETCH_INT_TO_FLOAT_UNIT:
- glVertexAttribPointer(
- input->location, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer);
+ glVertexAttribPointer(input->location, a->comp_len, type, GL_TRUE, stride, pointer);
break;
case GPU_FETCH_INT:
- glVertexAttribIPointer(input->location, a->comp_len, a->gl_comp_type, stride, pointer);
+ glVertexAttribIPointer(input->location, a->comp_len, type, stride, pointer);
break;
}
}
@@ -839,7 +831,7 @@ struct GPUDrawList {
GPUDrawList *GPU_draw_list_create(int length)
{
- GPUDrawList *list = MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
+ GPUDrawList *list = (GPUDrawList *)MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
/* Alloc the biggest possible command list which is indexed. */
list->buffer_size = sizeof(GPUDrawCommandIndexed) * length;
if (USE_MULTI_DRAW_INDIRECT) {
@@ -848,7 +840,7 @@ GPUDrawList *GPU_draw_list_create(int length)
glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
}
else {
- list->commands = MEM_mallocN(list->buffer_size, "GPUDrawList data");
+ list->commands = (GPUDrawCommand *)MEM_mallocN(list->buffer_size, "GPUDrawList data");
}
return list;
}
@@ -880,7 +872,7 @@ void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch)
list->cmd_offset = 0;
}
GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
- list->commands = glMapBufferRange(
+ list->commands = (GPUDrawCommand *)glMapBufferRange(
GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags);
}
}
@@ -989,17 +981,12 @@ void GPU_draw_list_submit(GPUDrawList *list)
/** \name Utilities
* \{ */
-void GPU_batch_program_set_shader(GPUBatch *batch, GPUShader *shader)
-{
- GPU_batch_program_set(batch, shader->program, shader->interface);
-}
-
void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
eGPUBuiltinShader shader_id,
eGPUShaderConfig sh_cfg)
{
GPUShader *shader = GPU_shader_get_builtin_shader_with_config(shader_id, sh_cfg);
- GPU_batch_program_set(batch, shader->program, shader->interface);
+ GPU_batch_set_shader(batch, shader);
}
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
@@ -1012,10 +999,7 @@ void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
* DO NOT DRAW WITH THE BATCH BEFORE CALLING immUnbindProgram. */
void GPU_batch_program_set_imm_shader(GPUBatch *batch)
{
- GLuint program;
- GPUShaderInterface *interface;
- immGetProgram(&program, &interface);
- GPU_batch_program_set(batch, program, interface);
+ GPU_batch_set_shader(batch, immGetShader());
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 0a1d6f560b6..e15e4e08159 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -41,7 +41,6 @@
#include "BKE_material.h"
#include "GPU_extensions.h"
-#include "GPU_glew.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_uniformbuffer.h"
@@ -56,8 +55,8 @@
#include <stdarg.h>
#include <string.h>
+extern char datatoc_gpu_shader_codegen_lib_glsl[];
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
/* -------------------- GPUPass Cache ------------------ */
/**
@@ -282,18 +281,15 @@ static const char *gpu_builtin_name(eGPUBuiltin builtin)
static void codegen_set_unique_ids(GPUNodeGraph *graph)
{
- GPUNode *node;
- GPUInput *input;
- GPUOutput *output;
int id = 1;
- for (node = graph->nodes.first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
+ LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
/* set id for unique names of uniform variables */
input->id = id++;
}
- for (output = node->outputs.first; output; output = output->next) {
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
/* set id for unique names of tmp variables storing output */
output->id = id++;
}
@@ -307,17 +303,10 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
DynStr *ds,
GPUNodeGraph *graph)
{
- GPUNode *node;
- GPUInput *input;
const char *name;
int builtins = 0;
ListBase ubo_inputs = {NULL, NULL};
- /* Attributes */
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- BLI_dynstr_appendf(ds, "in %s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
- }
-
/* Textures */
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph->textures) {
if (tex->colorband) {
@@ -339,8 +328,9 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
}
/* Print other uniforms */
- for (node = graph->nodes.first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
+
+ LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
if (input->source == GPU_SOURCE_BUILTIN) {
/* only define each builtin uniform/varying once */
if (!(builtins & input->builtin)) {
@@ -382,8 +372,8 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME);
LISTBASE_FOREACH (LinkData *, link, &ubo_inputs) {
- input = link->data;
- BLI_dynstr_appendf(ds, "\t%s unf%d;\n", gpu_data_type_to_string(input->type), input->id);
+ GPUInput *input = (GPUInput *)(link->data);
+ BLI_dynstr_appendf(ds, " %s unf%d;\n", gpu_data_type_to_string(input->type), input->id);
}
BLI_dynstr_append(ds, "};\n");
BLI_freelistN(&ubo_inputs);
@@ -396,34 +386,26 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph)
{
- GPUNode *node;
- GPUOutput *output;
-
- for (node = graph->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
/* declare temporary variables for node output storage */
- for (output = node->outputs.first; output; output = output->next) {
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
if (output->type == GPU_CLOSURE) {
- BLI_dynstr_appendf(ds, "\tClosure tmp%d;\n", output->id);
+ BLI_dynstr_appendf(ds, " Closure tmp%d;\n", output->id);
}
else {
- BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", gpu_data_type_to_string(output->type), output->id);
+ BLI_dynstr_appendf(ds, " %s tmp%d;\n", gpu_data_type_to_string(output->type), output->id);
}
}
}
-
BLI_dynstr_append(ds, "\n");
}
static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *finaloutput)
{
- GPUNode *node;
- GPUInput *input;
- GPUOutput *output;
-
- for (node = graph->nodes.first; node; node = node->next) {
- BLI_dynstr_appendf(ds, "\t%s(", node->name);
+ LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
+ BLI_dynstr_appendf(ds, " %s(", node->name);
- for (input = node->inputs.first; input; input = input->next) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
if (input->source == GPU_SOURCE_TEX) {
BLI_dynstr_append(ds, input->texture->sampler_name);
}
@@ -504,7 +486,7 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f
BLI_dynstr_append(ds, ", ");
}
- for (output = node->outputs.first; output; output = output->next) {
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
BLI_dynstr_appendf(ds, "tmp%d", output->id);
if (output->next) {
BLI_dynstr_append(ds, ", ");
@@ -514,21 +496,24 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f
BLI_dynstr_append(ds, ");\n");
}
- BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id);
- BLI_dynstr_append(ds, ";\n");
+ BLI_dynstr_appendf(ds, "\n return tmp%d;\n", finaloutput->id);
}
-static char *code_generate_fragment(GPUMaterial *material, GPUNodeGraph *graph)
+static char *code_generate_fragment(GPUMaterial *material,
+ GPUNodeGraph *graph,
+ const char *interface_str)
{
DynStr *ds = BLI_dynstr_new();
char *code;
int builtins;
-#if 0
- BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
-#endif
-
codegen_set_unique_ids(graph);
+
+ /* Attributes, Shader stage interface. */
+ if (interface_str) {
+ BLI_dynstr_appendf(ds, "in codegenInterface {%s};\n\n", interface_str);
+ }
+
builtins = codegen_process_uniforms_functions(material, ds, graph);
if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
@@ -536,73 +521,61 @@ static char *code_generate_fragment(GPUMaterial *material, GPUNodeGraph *graph)
}
if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n");
- }
-
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "flat in vec3 barycentricDist;\n");
+ BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
}
BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n");
if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds,
- "\tvec2 barytexco = vec2((fract(barycentricTexCo.y) != 0.0)\n"
- "\t ? barycentricTexCo.x\n"
- "\t : 1.0 - barycentricTexCo.x,\n"
- "\t 0.0);\n");
- BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, "\tvec2 barytexco = barycentricTexCo;\n");
- BLI_dynstr_append(ds, "#endif\n");
+ BLI_dynstr_append(ds, " vec2 barytexco = barycentric_resolve(barycentricTexCo);\n");
}
/* TODO(fclem) get rid of that. */
if (builtins & GPU_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "\t#define viewmat ViewMatrix\n");
+ BLI_dynstr_append(ds, " #define viewmat ViewMatrix\n");
}
if (builtins & GPU_CAMERA_TEXCO_FACTORS) {
- BLI_dynstr_append(ds, "\t#define camtexfac CameraTexCoFactors\n");
+ BLI_dynstr_append(ds, " #define camtexfac CameraTexCoFactors\n");
}
if (builtins & GPU_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, "\t#define objmat ModelMatrix\n");
+ BLI_dynstr_append(ds, " #define objmat ModelMatrix\n");
}
if (builtins & GPU_INVERSE_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, "\t#define objinv ModelMatrixInverse\n");
+ BLI_dynstr_append(ds, " #define objinv ModelMatrixInverse\n");
}
if (builtins & GPU_INVERSE_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "\t#define viewinv ViewMatrixInverse\n");
+ BLI_dynstr_append(ds, " #define viewinv ViewMatrixInverse\n");
}
if (builtins & GPU_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "\t#define localtoviewmat (ViewMatrix * ModelMatrix)\n");
+ BLI_dynstr_append(ds, " #define localtoviewmat (ViewMatrix * ModelMatrix)\n");
}
if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
BLI_dynstr_append(ds,
- "\t#define invlocaltoviewmat (ModelMatrixInverse * ViewMatrixInverse)\n");
+ " #define invlocaltoviewmat (ModelMatrixInverse * ViewMatrixInverse)\n");
}
if (builtins & GPU_VIEW_NORMAL) {
BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, "\tvec3 n;\n");
- BLI_dynstr_append(ds, "\tworld_normals_get(n);\n");
- BLI_dynstr_append(ds, "\tvec3 facingnormal = transform_direction(ViewMatrix, n);\n");
+ BLI_dynstr_append(ds, " vec3 n;\n");
+ BLI_dynstr_append(ds, " world_normals_get(n);\n");
+ BLI_dynstr_append(ds, " vec3 facingnormal = transform_direction(ViewMatrix, n);\n");
BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing ? viewNormal: -viewNormal;\n");
+ BLI_dynstr_append(ds, " vec3 facingnormal = gl_FrontFacing ? viewNormal: -viewNormal;\n");
BLI_dynstr_append(ds, "#endif\n");
}
if (builtins & GPU_WORLD_NORMAL) {
- BLI_dynstr_append(ds, "\tvec3 facingwnormal;\n");
+ BLI_dynstr_append(ds, " vec3 facingwnormal;\n");
if (builtins & GPU_VIEW_NORMAL) {
BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, "\tfacingwnormal = n;\n");
+ BLI_dynstr_append(ds, " facingwnormal = n;\n");
BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, "\tworld_normals_get(facingwnormal);\n");
+ BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n");
BLI_dynstr_append(ds, "#endif\n");
}
else {
- BLI_dynstr_append(ds, "\tworld_normals_get(facingwnormal);\n");
+ BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n");
}
}
if (builtins & GPU_VIEW_POSITION) {
- BLI_dynstr_append(ds, "\t#define viewposition viewPosition\n");
+ BLI_dynstr_append(ds, " #define viewposition viewPosition\n");
}
codegen_declare_tmps(ds, graph);
@@ -610,21 +583,6 @@ static char *code_generate_fragment(GPUMaterial *material, GPUNodeGraph *graph)
BLI_dynstr_append(ds, "}\n");
- /* XXX This cannot go into gpu_shader_material.glsl because main()
- * would be parsed and generate error */
- /* Old glsl mode compat. */
- /* TODO(fclem) This is only used by world shader now. get rid of it? */
- BLI_dynstr_append(ds, "#ifndef NODETREE_EXEC\n");
- BLI_dynstr_append(ds, "out vec4 fragColor;\n");
- BLI_dynstr_append(ds, "void main()\n");
- BLI_dynstr_append(ds, "{\n");
- BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n");
- BLI_dynstr_append(ds,
- "\tfragColor = vec4(cl.radiance, "
- "saturate(1.0 - avg(cl.transmittance)));\n");
- BLI_dynstr_append(ds, "}\n");
- BLI_dynstr_append(ds, "#endif\n\n");
-
/* create shader */
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -659,23 +617,48 @@ static const char *attr_prefix_get(CustomDataType type)
}
}
-static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bool use_geom)
+/* We talk about shader stage interface, not to be mistaken with GPUShaderInterface. */
+static char *code_generate_interface(GPUNodeGraph *graph, int builtins)
{
+ if (BLI_listbase_is_empty(&graph->attributes) &&
+ (builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0) {
+ return NULL;
+ }
+
DynStr *ds = BLI_dynstr_new();
- GPUNode *node;
- GPUInput *input;
- char *code;
- int builtins = 0;
- /* Hairs uv and col attributes are passed by bufferTextures. */
- BLI_dynstr_append(ds,
- "#ifdef HAIR_SHADER\n"
- "#define DEFINE_ATTR(type, attr) uniform samplerBuffer attr\n"
- "#else\n"
- "#define DEFINE_ATTR(type, attr) in type attr\n"
- "#endif\n");
+ BLI_dynstr_append(ds, "\n");
+
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
+ BLI_dynstr_appendf(ds, "%s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
+ }
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_append(ds, "vec2 barycentricTexCo;\n");
+ }
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_append(ds, "vec3 barycentricDist;\n");
+ }
+
+ char *code = BLI_dynstr_get_cstring(ds);
+
+ BLI_dynstr_free(ds);
+ return code;
+}
+
+static char *code_generate_vertex(GPUNodeGraph *graph,
+ const char *interface_str,
+ const char *vert_code,
+ int builtins)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
+
+ /* Inputs */
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
+ const char *type_str = gpu_data_type_to_string(attr->gputype);
+ const char *prefix = attr_prefix_get(attr->type);
/* XXX FIXME : see notes in mesh_render_data_create() */
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (attr->type == CD_ORCO) {
@@ -684,188 +667,58 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo
BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
}
else if (attr->name[0] == '\0') {
- BLI_dynstr_appendf(ds,
- "DEFINE_ATTR(%s, %s);\n",
- gpu_data_type_to_string(attr->gputype),
- attr_prefix_get(attr->type));
- BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, attr_prefix_get(attr->type));
+ BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s);\n", type_str, prefix);
+ BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, prefix);
}
else {
char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
GPU_vertformat_safe_attr_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
- BLI_dynstr_appendf(ds,
- "DEFINE_ATTR(%s, %s%s);\n",
- gpu_data_type_to_string(attr->gputype),
- attr_prefix_get(attr->type),
- attr_safe_name);
- BLI_dynstr_appendf(
- ds, "#define att%d %s%s\n", attr->id, attr_prefix_get(attr->type), attr_safe_name);
+ BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s%s);\n", type_str, prefix, attr_safe_name);
+ BLI_dynstr_appendf(ds, "#define att%d %s%s\n", attr->id, prefix, attr_safe_name);
}
- BLI_dynstr_appendf(ds,
- "out %s var%d%s;\n",
- gpu_data_type_to_string(attr->gputype),
- attr->id,
- use_geom ? "g" : "");
- }
-
- for (node = graph->nodes.first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
- if (input->source == GPU_SOURCE_BUILTIN) {
- builtins |= input->builtin;
- }
- }
- }
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_appendf(ds, "out vec2 barycentricTexCo%s;\n", use_geom ? "g" : "");
- BLI_dynstr_append(ds, "#endif\n");
}
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "out vec3 barycentricPosg;\n");
+ /* Outputs interface */
+ if (interface_str) {
+ BLI_dynstr_appendf(ds, "out codegenInterface {%s};\n\n", interface_str);
}
- BLI_dynstr_append(ds, "\n#define USE_ATTR\n");
-
- /* Prototype, defined later (this is because of matrices definition). */
- BLI_dynstr_append(ds, "void pass_attr(in vec3 position);\n");
-
- BLI_dynstr_append(ds, "\n");
-
- if (use_geom) {
- /* XXX HACK: Eevee specific. */
- char *vert_new, *vert_new2;
- vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong");
- vert_new2 = vert_new;
- vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong");
- MEM_freeN(vert_new2);
- vert_new2 = vert_new;
- vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg");
- MEM_freeN(vert_new2);
- vert_new2 = vert_new;
- vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg");
- MEM_freeN(vert_new2);
-
- BLI_dynstr_append(ds, vert_new);
-
- MEM_freeN(vert_new);
- }
- else {
- BLI_dynstr_append(ds, vert_code);
- }
+ /* Prototype. Needed for hair functions. */
+ BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv);\n");
+ BLI_dynstr_append(ds, "#define USE_ATTR\n\n");
+ BLI_dynstr_append(ds, vert_code);
BLI_dynstr_append(ds, "\n");
- BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n");
-
- /* Prototype because defined later. */
- BLI_dynstr_append(ds,
- "vec2 hair_get_customdata_vec2(const samplerBuffer);\n"
- "vec3 hair_get_customdata_vec3(const samplerBuffer);\n"
- "vec4 hair_get_customdata_vec4(const samplerBuffer);\n"
- "vec3 hair_get_strand_pos(void);\n"
- "int hair_get_base_id(void);\n"
- "\n");
-
- BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n");
-
- BLI_dynstr_append(ds, use_geom ? "\tPASS_RESOURCE_ID_GEOM\n" : "\tPASS_RESOURCE_ID\n");
-
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- /* To match cycles without breaking into individual segment we encode if we need to invert
- * the first component into the second component. We invert if the barycentricTexCo.y
- * is NOT 0.0 or 1.0. */
- BLI_dynstr_append(ds, "\tint _base_id = hair_get_base_id();\n");
- BLI_dynstr_appendf(
- ds, "\tbarycentricTexCo%s.x = float((_base_id %% 2) == 1);\n", use_geom ? "g" : "");
- BLI_dynstr_appendf(
- ds, "\tbarycentricTexCo%s.y = float(((_base_id %% 4) %% 3) > 0);\n", use_geom ? "g" : "");
- }
-
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "\tbarycentricPosg = position;\n");
- }
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- if (attr->type == CD_TANGENT) {
- /* Not supported by hairs */
- BLI_dynstr_appendf(ds, "\tvar%d%s = vec4(0.0);\n", attr->id, use_geom ? "g" : "");
- }
- else if (attr->type == CD_ORCO) {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0].xyz + (ModelMatrixInverse * "
- "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1].xyz;\n",
- attr->id,
- use_geom ? "g" : "");
- /* TODO: fix ORCO with modifiers. */
- }
- else {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = hair_get_customdata_%s(att%d);\n",
- attr->id,
- use_geom ? "g" : "",
- gpu_data_type_to_string(attr->gputype),
- attr->id);
- }
- }
-
- BLI_dynstr_append(ds, "#else /* MESH_SHADER */\n");
+ BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv) {\n");
/* GPU_BARYCENTRIC_TEXCO cannot be computed based on gl_VertexID
* for MESH_SHADER because of indexed drawing. In this case a
* geometry shader is needed. */
-
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_appendf(ds, " barycentricTexCo = barycentric_get();\n");
+ }
if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n");
+ BLI_dynstr_appendf(ds, " barycentricDist = vec3(0);\n");
}
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
if (attr->type == CD_TANGENT) { /* silly exception */
- BLI_dynstr_appendf(ds,
- "\tvar%d%s.xyz = transpose(mat3(ModelMatrixInverse)) * att%d.xyz;\n",
- attr->id,
- use_geom ? "g" : "",
- attr->id);
- BLI_dynstr_appendf(ds, "\tvar%d%s.w = att%d.w;\n", attr->id, use_geom ? "g" : "", attr->id);
- /* Normalize only if vector is not null. */
- BLI_dynstr_appendf(ds,
- "\tfloat lvar%d = dot(var%d%s.xyz, var%d%s.xyz);\n",
- attr->id,
- attr->id,
- use_geom ? "g" : "",
- attr->id,
- use_geom ? "g" : "");
- BLI_dynstr_appendf(ds,
- "\tvar%d%s.xyz *= (lvar%d > 0.0) ? inversesqrt(lvar%d) : 1.0;\n",
- attr->id,
- use_geom ? "g" : "",
- attr->id,
- attr->id);
+ BLI_dynstr_appendf(ds, " var%d = tangent_get(att%d, normalmat);\n", attr->id, attr->id);
}
else if (attr->type == CD_ORCO) {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0].xyz + position *"
- " OrcoTexCoFactors[1].xyz;\n",
- attr->id,
- use_geom ? "g" : "");
- /* See mesh_create_loop_orco() for explanation. */
- BLI_dynstr_appendf(ds,
- "\tif (orco.w == 0.0) { var%d%s = orco.xyz * 0.5 + 0.5; }\n",
- attr->id,
- use_geom ? "g" : "");
+ BLI_dynstr_appendf(
+ ds, " var%d = orco_get(position, modelmatinv, OrcoTexCoFactors, orco);\n", attr->id);
}
else {
- BLI_dynstr_appendf(ds, "\tvar%d%s = att%d;\n", attr->id, use_geom ? "g" : "", attr->id);
+ const char *type_str = gpu_data_type_to_string(attr->gputype);
+ BLI_dynstr_appendf(ds, " var%d = GET_ATTR(%s, att%d);\n", attr->id, type_str, attr->id);
}
}
- BLI_dynstr_append(ds, "#endif /* HAIR_SHADER */\n");
BLI_dynstr_append(ds, "}\n");
- code = BLI_dynstr_get_cstring(ds);
+ char *code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -879,146 +732,46 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo
}
static char *code_generate_geometry(GPUNodeGraph *graph,
+ const char *interface_str,
const char *geom_code,
- const char *defines)
+ int builtins)
{
- DynStr *ds = BLI_dynstr_new();
- GPUNode *node;
- GPUInput *input;
- char *code;
- int builtins = 0;
-
- /* XXX we should not make specific eevee cases here. */
- bool is_hair_shader = (strstr(defines, "HAIR_SHADER") != NULL);
-
- /* Create prototype because attributes cannot be declared before layout. */
- BLI_dynstr_append(ds, "void pass_attr(in int vert);\n");
- BLI_dynstr_append(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2);\n");
- BLI_dynstr_append(ds, "#define USE_ATTR\n");
-
- /* Generate varying declarations. */
- for (node = graph->nodes.first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
- if (input->source == GPU_SOURCE_BUILTIN) {
- builtins |= input->builtin;
- }
- }
- }
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- BLI_dynstr_appendf(ds, "in %s var%dg[];\n", gpu_data_type_to_string(attr->gputype), attr->id);
- BLI_dynstr_appendf(ds, "out %s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
+ if (!geom_code) {
+ return NULL;
}
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, "in vec2 barycentricTexCog[];\n");
- BLI_dynstr_append(ds, "#endif\n");
-
- BLI_dynstr_append(ds, "out vec2 barycentricTexCo;\n");
- }
+ DynStr *ds = BLI_dynstr_new();
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "in vec3 barycentricPosg[];\n");
- BLI_dynstr_append(ds, "flat out vec3 barycentricDist;\n");
+ /* Attributes, Shader interface; */
+ if (interface_str) {
+ BLI_dynstr_appendf(ds, "in codegenInterface {%s} dataAttrIn[];\n\n", interface_str);
+ BLI_dynstr_appendf(ds, "out codegenInterface {%s} dataAttrOut;\n\n", interface_str);
}
- if (geom_code == NULL) {
- /* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used.
- * Note: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */
- if ((builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0 || is_hair_shader) {
- /* Early out */
- BLI_dynstr_free(ds);
- return NULL;
- }
- else {
- /* Force geom shader usage */
- /* TODO put in external file. */
- BLI_dynstr_append(ds, "layout(triangles) in;\n");
- BLI_dynstr_append(ds, "layout(triangle_strip, max_vertices=3) out;\n");
-
- BLI_dynstr_append(ds, "in vec3 worldPositiong[];\n");
- BLI_dynstr_append(ds, "in vec3 viewPositiong[];\n");
- BLI_dynstr_append(ds, "in vec3 worldNormalg[];\n");
- BLI_dynstr_append(ds, "in vec3 viewNormalg[];\n");
-
- BLI_dynstr_append(ds, "out vec3 worldPosition;\n");
- BLI_dynstr_append(ds, "out vec3 viewPosition;\n");
- BLI_dynstr_append(ds, "out vec3 worldNormal;\n");
- BLI_dynstr_append(ds, "out vec3 viewNormal;\n");
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
-
- BLI_dynstr_append(ds, "void main(){\n");
-
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds,
- "\tcalc_barycentric_distances(barycentricPosg[0], barycentricPosg[1], "
- "barycentricPosg[2]);\n");
- }
-
- for (int i = 0; i < 3; i++) {
- BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[%d].gl_Position;\n", i);
- BLI_dynstr_appendf(ds, "\tgl_ClipDistance[0] = gl_in[%d].gl_ClipDistance[0];\n", i);
- BLI_dynstr_appendf(ds, "\tpass_attr(%d);\n", i);
- BLI_dynstr_append(ds, "\tEmitVertex();\n");
- }
- BLI_dynstr_append(ds, "}\n");
- }
- }
- else {
- BLI_dynstr_append(ds, geom_code);
- }
+ BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2) {\n");
- BLI_dynstr_append(ds, "\tvec3 edge21 = pos2 - pos1;\n");
- BLI_dynstr_append(ds, "\tvec3 edge10 = pos1 - pos0;\n");
- BLI_dynstr_append(ds, "\tvec3 edge02 = pos0 - pos2;\n");
- BLI_dynstr_append(ds, "\tvec3 d21 = normalize(edge21);\n");
- BLI_dynstr_append(ds, "\tvec3 d10 = normalize(edge10);\n");
- BLI_dynstr_append(ds, "\tvec3 d02 = normalize(edge02);\n");
-
- BLI_dynstr_append(ds, "\tfloat d = dot(d21, edge02);\n");
- BLI_dynstr_append(ds, "\tbarycentricDist.x = sqrt(dot(edge02, edge02) - d * d);\n");
- BLI_dynstr_append(ds, "\td = dot(d02, edge10);\n");
- BLI_dynstr_append(ds, "\tbarycentricDist.y = sqrt(dot(edge10, edge10) - d * d);\n");
- BLI_dynstr_append(ds, "\td = dot(d10, edge21);\n");
- BLI_dynstr_append(ds, "\tbarycentricDist.z = sqrt(dot(edge21, edge21) - d * d);\n");
- BLI_dynstr_append(ds, "}\n");
+ /* geom_code should do something with this, but may not. */
+ BLI_dynstr_append(ds, "#define DO_BARYCENTRIC_DISTANCES\n");
}
- BLI_dynstr_append(ds, "RESOURCE_ID_VARYING\n");
-
/* Generate varying assignments. */
- BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n");
-
- BLI_dynstr_append(ds, "\tPASS_RESOURCE_ID(vert)\n");
-
- /* XXX HACK: Eevee specific. */
- if (geom_code == NULL) {
- BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n");
- BLI_dynstr_append(ds, "\tviewPosition = viewPositiong[vert];\n");
- BLI_dynstr_append(ds, "\tworldNormal = worldNormalg[vert];\n");
- BLI_dynstr_append(ds, "\tviewNormal = viewNormalg[vert];\n");
- }
+ BLI_dynstr_append(ds, "#define USE_ATTR\n");
+ BLI_dynstr_append(ds, "void pass_attr(const int vert) {\n");
if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, "\tbarycentricTexCo = barycentricTexCog[vert];\n");
- BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, "\tbarycentricTexCo.x = float((vert % 3) == 0);\n");
- BLI_dynstr_append(ds, "\tbarycentricTexCo.y = float((vert % 3) == 1);\n");
- BLI_dynstr_append(ds, "#endif\n");
+ BLI_dynstr_append(ds, " dataAttrOut.barycentricTexCo = calc_barycentric_co(vert);\n");
}
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
/* TODO let shader choose what to do depending on what the attribute is. */
- BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", attr->id, attr->id);
+ BLI_dynstr_appendf(ds, " dataAttrOut.var%d = dataAttrIn[vert].var%d;\n", attr->id, attr->id);
}
- BLI_dynstr_append(ds, "}\n");
+ BLI_dynstr_append(ds, "}\n\n");
- code = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_append(ds, geom_code);
+
+ char *code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
return code;
@@ -1048,8 +801,17 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
* generated VBOs are ready to accept the future shader. */
gpu_node_graph_prune_unused(graph);
+ int builtins = 0;
+ LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ if (input->source == GPU_SOURCE_BUILTIN) {
+ builtins |= input->builtin;
+ }
+ }
+ }
/* generate code */
- char *fragmentgen = code_generate_fragment(material, graph);
+ char *interface_str = code_generate_interface(graph, builtins);
+ char *fragmentgen = code_generate_fragment(material, graph, interface_str);
/* Cache lookup: Reuse shaders already compiled */
uint32_t hash = gpu_pass_hash(fragmentgen, defines, &graph->attributes);
@@ -1057,6 +819,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) {
/* No collision, just return the pass. */
+ MEM_SAFE_FREE(interface_str);
MEM_freeN(fragmentgen);
if (!gpu_pass_is_valid(pass_hash)) {
/* Shader has already been created but failed to compile. */
@@ -1071,10 +834,11 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
GSet *used_libraries = gpu_material_used_libraries(material);
char *tmp = gpu_material_library_generate_code(used_libraries, frag_lib);
- char *geometrycode = code_generate_geometry(graph, geom_code, defines);
- char *vertexcode = code_generate_vertex(graph, vert_code, (geometrycode != NULL));
+ char *geometrycode = code_generate_geometry(graph, interface_str, geom_code, builtins);
+ char *vertexcode = code_generate_vertex(graph, interface_str, vert_code, builtins);
char *fragmentcode = BLI_strdupcat(tmp, fragmentgen);
+ MEM_SAFE_FREE(interface_str);
MEM_freeN(fragmentgen);
MEM_freeN(tmp);
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index ce20f495ba3..18ff4c3241d 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -26,6 +26,10 @@
#ifndef __GPU_CODEGEN_H__
#define __GPU_CODEGEN_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct GPUMaterial;
struct GPUNodeGraph;
struct GPUOutput;
@@ -68,4 +72,8 @@ void GPU_pass_release(GPUPass *pass);
void gpu_codegen_init(void);
void gpu_codegen_exit(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __GPU_CODEGEN_H__ */
diff --git a/source/blender/gpu/intern/gpu_context.cpp b/source/blender/gpu/intern/gpu_context.cc
index 0b9104e5349..0b9104e5349 100644
--- a/source/blender/gpu/intern/gpu_context.cpp
+++ b/source/blender/gpu/intern/gpu_context.cc
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.cc
index f7d6236071d..f7d6236071d 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.cc
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
deleted file mode 100644
index e5f49555265..00000000000
--- a/source/blender/gpu/intern/gpu_draw.c
+++ /dev/null
@@ -1,1469 +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.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup gpu
- *
- * Utility functions for dealing with OpenGL texture & material context,
- * mipmap generation and light objects.
- *
- * These are some obscure rendering functions shared between the game engine (not anymore)
- * and the blender, in this module to avoid duplication
- * and abstract them away from the rest a bit.
- */
-
-#include <string.h>
-
-#include "BLI_blenlib.h"
-#include "BLI_boxpack_2d.h"
-#include "BLI_linklist.h"
-#include "BLI_math.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_image_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_userdef_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_main.h"
-#include "BKE_movieclip.h"
-
-#include "GPU_draw.h"
-#include "GPU_extensions.h"
-#include "GPU_glew.h"
-#include "GPU_matrix.h"
-#include "GPU_platform.h"
-#include "GPU_texture.h"
-
-#include "PIL_time.h"
-
-static void gpu_free_image(Image *ima, const bool immediate);
-static void gpu_free_unused_buffers(void);
-
-//* Checking powers of two for images since OpenGL ES requires it */
-#ifdef WITH_DDS
-static bool is_power_of_2_resolution(int w, int h)
-{
- return is_power_of_2_i(w) && is_power_of_2_i(h);
-}
-#endif
-
-static bool is_over_resolution_limit(GLenum textarget, int w, int h)
-{
- int size = (textarget == GL_TEXTURE_CUBE_MAP) ? GPU_max_cube_map_size() : GPU_max_texture_size();
- int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
-
- return (w > reslimit || h > reslimit);
-}
-
-static int smaller_power_of_2_limit(int num)
-{
- int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, GPU_max_texture_size()) :
- GPU_max_texture_size();
- /* take texture clamping into account */
- if (num > reslimit) {
- return reslimit;
- }
-
- return power_of_2_min_i(num);
-}
-
-/* Current OpenGL state caching for GPU_set_tpage */
-
-static struct GPUTextureState {
- /* also controls min/mag filtering */
- bool domipmap;
- /* only use when 'domipmap' is set */
- bool linearmipmap;
- /* store this so that new images created while texture painting won't be set to mipmapped */
- bool texpaint;
-
- float anisotropic;
-} GTS = {1, 0, 0, 1.0f};
-
-/* Mipmap settings */
-
-void GPU_set_mipmap(Main *bmain, bool mipmap)
-{
- if (GTS.domipmap != mipmap) {
- GPU_free_images(bmain);
- GTS.domipmap = mipmap;
- }
-}
-
-void GPU_set_linear_mipmap(bool linear)
-{
- if (GTS.linearmipmap != linear) {
- GTS.linearmipmap = linear;
- }
-}
-
-bool GPU_get_mipmap(void)
-{
- return GTS.domipmap && !GTS.texpaint;
-}
-
-bool GPU_get_linear_mipmap(void)
-{
- return GTS.linearmipmap;
-}
-
-static GLenum gpu_get_mipmap_filter(bool mag)
-{
- /* linearmipmap is off by default *when mipmapping is off,
- * use unfiltered display */
- if (mag) {
- if (GTS.domipmap) {
- return GL_LINEAR;
- }
- else {
- return GL_NEAREST;
- }
- }
- else {
- if (GTS.domipmap) {
- if (GTS.linearmipmap) {
- return GL_LINEAR_MIPMAP_LINEAR;
- }
- else {
- return GL_LINEAR_MIPMAP_NEAREST;
- }
- }
- else {
- return GL_NEAREST;
- }
- }
-}
-
-/* Anisotropic filtering settings */
-void GPU_set_anisotropic(float value)
-{
- if (GTS.anisotropic != value) {
- GPU_samplers_free();
-
- /* Clamp value to the maximum value the graphics card supports */
- const float max = GPU_max_texture_anisotropy();
- if (value > max) {
- value = max;
- }
-
- GTS.anisotropic = value;
-
- GPU_samplers_init();
- }
-}
-
-float GPU_get_anisotropic(void)
-{
- return GTS.anisotropic;
-}
-
-/* Set OpenGL state for an MTFace */
-
-static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget, const int multiview_eye)
-{
- if (textarget == GL_TEXTURE_2D) {
- return &(ima->gputexture[TEXTARGET_TEXTURE_2D][multiview_eye]);
- }
- else if (textarget == GL_TEXTURE_CUBE_MAP) {
- return &(ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP][multiview_eye]);
- }
- else if (textarget == GL_TEXTURE_2D_ARRAY) {
- return &(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][multiview_eye]);
- }
- else if (textarget == GL_TEXTURE_1D_ARRAY) {
- return &(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][multiview_eye]);
- }
-
- return NULL;
-}
-
-static uint gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
-{
- GPUTexture *tilearray = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][multiview_eye];
-
- if (tilearray == NULL) {
- return 0;
- }
-
- float array_w = GPU_texture_width(tilearray);
- float array_h = GPU_texture_height(tilearray);
-
- ImageTile *last_tile = ima->tiles.last;
- /* Tiles are sorted by number. */
- int max_tile = last_tile->tile_number - 1001;
-
- /* create image */
- int bindcode;
- glGenTextures(1, (GLuint *)&bindcode);
- glBindTexture(GL_TEXTURE_1D_ARRAY, bindcode);
-
- int width = max_tile + 1;
- float *data = MEM_callocN(width * 8 * sizeof(float), __func__);
- for (int i = 0; i < width; i++) {
- data[4 * i] = -1.0f;
- }
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- int i = tile->tile_number - 1001;
- data[4 * i] = tile->runtime.tilearray_layer;
-
- float *tile_info = &data[4 * width + 4 * i];
- tile_info[0] = tile->runtime.tilearray_offset[0] / array_w;
- tile_info[1] = tile->runtime.tilearray_offset[1] / array_h;
- tile_info[2] = tile->runtime.tilearray_size[0] / array_w;
- tile_info[3] = tile->runtime.tilearray_size[1] / array_h;
- }
-
- glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA32F, width, 2, 0, GL_RGBA, GL_FLOAT, data);
- MEM_freeN(data);
-
- glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- glBindTexture(GL_TEXTURE_1D_ARRAY, 0);
-
- return bindcode;
-}
-
-typedef struct PackTile {
- FixedSizeBoxPack boxpack;
- ImageTile *tile;
- float pack_score;
-} PackTile;
-
-static int compare_packtile(const void *a, const void *b)
-{
- const PackTile *tile_a = a;
- const PackTile *tile_b = b;
-
- return tile_a->pack_score < tile_b->pack_score;
-}
-
-static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
-{
- int arraywidth = 0, arrayheight = 0;
-
- ListBase boxes = {NULL};
-
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- ImageUser iuser;
- BKE_imageuser_default(&iuser);
- iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
-
- if (ibuf) {
- PackTile *packtile = MEM_callocN(sizeof(PackTile), __func__);
- packtile->tile = tile;
- packtile->boxpack.w = ibuf->x;
- packtile->boxpack.h = ibuf->y;
-
- if (is_over_resolution_limit(
- GL_TEXTURE_2D_ARRAY, packtile->boxpack.w, packtile->boxpack.h)) {
- packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
- packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
- }
- arraywidth = max_ii(arraywidth, packtile->boxpack.w);
- arrayheight = max_ii(arrayheight, packtile->boxpack.h);
-
- /* We sort the tiles by decreasing size, with an additional penalty term
- * for high aspect ratios. This improves packing efficiency. */
- float w = packtile->boxpack.w, h = packtile->boxpack.h;
- packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h;
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- BLI_addtail(&boxes, packtile);
- }
- }
-
- BLI_assert(arraywidth > 0 && arrayheight > 0);
-
- BLI_listbase_sort(&boxes, compare_packtile);
- int arraylayers = 0;
- /* Keep adding layers until all tiles are packed. */
- while (boxes.first != NULL) {
- ListBase packed = {NULL};
- BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
- BLI_assert(packed.first != NULL);
-
- LISTBASE_FOREACH (PackTile *, packtile, &packed) {
- ImageTile *tile = packtile->tile;
- int *tileoffset = tile->runtime.tilearray_offset;
- int *tilesize = tile->runtime.tilearray_size;
-
- tileoffset[0] = packtile->boxpack.x;
- tileoffset[1] = packtile->boxpack.y;
- tilesize[0] = packtile->boxpack.w;
- tilesize[1] = packtile->boxpack.h;
- tile->runtime.tilearray_layer = arraylayers;
- }
-
- BLI_freelistN(&packed);
- arraylayers++;
- }
-
- /* create image */
- int bindcode;
- glGenTextures(1, (GLuint *)&bindcode);
- glBindTexture(GL_TEXTURE_2D_ARRAY, bindcode);
-
- GLenum data_type, internal_format;
- if (main_ibuf->rect_float) {
- data_type = GL_FLOAT;
- internal_format = (!(main_ibuf->flags & IB_halffloat) && (ima->flag & IMA_HIGH_BITDEPTH)) ?
- GL_RGBA32F :
- GL_RGBA16F;
- }
- else {
- data_type = GL_UNSIGNED_BYTE;
- internal_format = GL_RGBA8;
- if (!IMB_colormanagement_space_is_data(main_ibuf->rect_colorspace) &&
- !IMB_colormanagement_space_is_scene_linear(main_ibuf->rect_colorspace)) {
- internal_format = GL_SRGB8_ALPHA8;
- }
- }
-
- glTexImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- internal_format,
- arraywidth,
- arrayheight,
- arraylayers,
- 0,
- GL_RGBA,
- data_type,
- NULL);
-
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- int tilelayer = tile->runtime.tilearray_layer;
- int *tileoffset = tile->runtime.tilearray_offset;
- int *tilesize = tile->runtime.tilearray_size;
-
- if (tilesize[0] == 0 || tilesize[1] == 0) {
- continue;
- }
-
- ImageUser iuser;
- BKE_imageuser_default(&iuser);
- iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
-
- if (ibuf) {
- bool needs_scale = (ibuf->x != tilesize[0] || ibuf->y != tilesize[1]);
-
- ImBuf *scale_ibuf = NULL;
- if (ibuf->rect_float) {
- float *rect_float = ibuf->rect_float;
-
- const bool store_premultiplied = ima->alpha_mode != IMA_ALPHA_STRAIGHT;
- if (ibuf->channels != 4 || !store_premultiplied) {
- rect_float = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
- IMB_colormanagement_imbuf_to_float_texture(
- rect_float, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
- }
-
- float *pixeldata = rect_float;
- if (needs_scale) {
- scale_ibuf = IMB_allocFromBuffer(NULL, rect_float, ibuf->x, ibuf->y, 4);
- IMB_scaleImBuf(scale_ibuf, tilesize[0], tilesize[1]);
- pixeldata = scale_ibuf->rect_float;
- }
-
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- tileoffset[0],
- tileoffset[1],
- tilelayer,
- tilesize[0],
- tilesize[1],
- 1,
- GL_RGBA,
- GL_FLOAT,
- pixeldata);
-
- if (rect_float != ibuf->rect_float) {
- MEM_freeN(rect_float);
- }
- }
- else {
- unsigned int *rect = ibuf->rect;
-
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
- IMB_colormanagement_imbuf_to_byte_texture((uchar *)rect,
- 0,
- 0,
- ibuf->x,
- ibuf->y,
- ibuf,
- internal_format == GL_SRGB8_ALPHA8,
- ima->alpha_mode == IMA_ALPHA_PREMUL);
- }
-
- unsigned int *pixeldata = rect;
- if (needs_scale) {
- scale_ibuf = IMB_allocFromBuffer(rect, NULL, ibuf->x, ibuf->y, 4);
- IMB_scaleImBuf(scale_ibuf, tilesize[0], tilesize[1]);
- pixeldata = scale_ibuf->rect;
- }
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- tileoffset[0],
- tileoffset[1],
- tilelayer,
- tilesize[0],
- tilesize[1],
- 1,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- pixeldata);
-
- if (rect != ibuf->rect) {
- MEM_freeN(rect);
- }
- }
- if (scale_ibuf != NULL) {
- IMB_freeImBuf(scale_ibuf);
- }
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- if (GPU_get_mipmap()) {
- glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
- if (ima) {
- ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
- }
- }
-
- glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
-
- return bindcode;
-}
-
-static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget)
-{
- uint bindcode = 0;
- const bool mipmap = GPU_get_mipmap();
- const bool half_float = (ibuf->flags & IB_halffloat) != 0;
-
-#ifdef WITH_DDS
- if (ibuf->ftype == IMB_FTYPE_DDS) {
- /* DDS is loaded directly in compressed form. */
- GPU_create_gl_tex_compressed(&bindcode, textarget, ima, ibuf);
- return bindcode;
- }
-#endif
-
- /* Regular uncompressed texture. */
- float *rect_float = ibuf->rect_float;
- uchar *rect = (uchar *)ibuf->rect;
- bool compress_as_srgb = false;
-
- if (rect_float == NULL) {
- /* Byte image is in original colorspace from the file. If the file is sRGB
- * scene linear, or non-color data no conversion is needed. Otherwise we
- * compress as scene linear + sRGB transfer function to avoid precision loss
- * in common cases.
- *
- * We must also convert to premultiplied for correct texture interpolation
- * and consistency with float images. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace);
-
- rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
- if (rect == NULL) {
- return bindcode;
- }
-
- /* Texture storage of images is defined by the alpha mode of the image. The
- * downside of this is that there can be artifacts near alpha edges. However,
- * this allows us to use sRGB texture formats and preserves color values in
- * zero alpha areas, and appears generally closer to what game engines that we
- * want to be compatible with do. */
- const bool store_premultiplied = ima ? (ima->alpha_mode == IMA_ALPHA_PREMUL) : true;
- IMB_colormanagement_imbuf_to_byte_texture(
- rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
- }
- }
- else {
- /* Float image is already in scene linear colorspace or non-color data by
- * convention, no colorspace conversion needed. But we do require 4 channels
- * currently. */
- const bool store_premultiplied = ima ? (ima->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
-
- if (ibuf->channels != 4 || !store_premultiplied) {
- rect_float = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
- if (rect_float == NULL) {
- return bindcode;
- }
- IMB_colormanagement_imbuf_to_float_texture(
- rect_float, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
- }
- }
-
- /* Create OpenGL texture. */
- GPU_create_gl_tex(&bindcode,
- (uint *)rect,
- rect_float,
- ibuf->x,
- ibuf->y,
- textarget,
- mipmap,
- half_float,
- compress_as_srgb,
- ima);
-
- /* Free buffers if needed. */
- if (rect && rect != (uchar *)ibuf->rect) {
- MEM_freeN(rect);
- }
- if (rect_float && rect_float != ibuf->rect_float) {
- MEM_freeN(rect_float);
- }
-
- return bindcode;
-}
-
-static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip,
- MovieClipUser *cuser,
- GLenum textarget)
-{
- MovieClip_RuntimeGPUTexture *tex;
- for (tex = clip->runtime.gputextures.first; tex; tex = tex->next) {
- if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
- break;
- }
- }
-
- if (tex == NULL) {
- tex = MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture), __func__);
-
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- tex->gputexture[i] = NULL;
- }
-
- memcpy(&tex->user, cuser, sizeof(MovieClipUser));
- BLI_addtail(&clip->runtime.gputextures, tex);
- }
-
- if (textarget == GL_TEXTURE_2D) {
- return &tex->gputexture[TEXTARGET_TEXTURE_2D];
- }
- else if (textarget == GL_TEXTURE_CUBE_MAP) {
- return &tex->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
- }
-
- return NULL;
-}
-
-static ImBuf *update_do_scale(uchar *rect,
- float *rect_float,
- int *x,
- int *y,
- int *w,
- int *h,
- int limit_w,
- int limit_h,
- int full_w,
- int full_h)
-{
- /* Partial update with scaling. */
- float xratio = limit_w / (float)full_w;
- float yratio = limit_h / (float)full_h;
-
- int part_w = *w, part_h = *h;
-
- /* Find sub coordinates in scaled image. Take ceiling because we will be
- * losing 1 pixel due to rounding errors in x,y. */
- *x *= xratio;
- *y *= yratio;
- *w = (int)ceil(xratio * (*w));
- *h = (int)ceil(yratio * (*h));
-
- /* ...but take back if we are over the limit! */
- if (*x + *w > limit_w) {
- (*w)--;
- }
- if (*y + *h > limit_h) {
- (*h)--;
- }
-
- /* Scale pixels. */
- ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, part_w, part_h, 4);
- IMB_scaleImBuf(ibuf, *w, *h);
-
- return ibuf;
-}
-
-static void gpu_texture_update_scaled_array(uchar *rect,
- float *rect_float,
- int full_w,
- int full_h,
- int x,
- int y,
- int layer,
- const int *tile_offset,
- const int *tile_size,
- int w,
- int h)
-{
- ImBuf *ibuf = update_do_scale(
- rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h);
-
- /* Shift to account for tile packing. */
- x += tile_offset[0];
- y += tile_offset[1];
-
- if (ibuf->rect_float) {
- glTexSubImage3D(
- GL_TEXTURE_2D_ARRAY, 0, x, y, layer, w, h, 1, GL_RGBA, GL_FLOAT, ibuf->rect_float);
- }
- else {
- glTexSubImage3D(
- GL_TEXTURE_2D_ARRAY, 0, x, y, layer, w, h, 1, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- }
-
- IMB_freeImBuf(ibuf);
-}
-
-static void gpu_texture_update_scaled(
- uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h)
-{
- /* Partial update with scaling. */
- int limit_w = smaller_power_of_2_limit(full_w);
- int limit_h = smaller_power_of_2_limit(full_h);
-
- ImBuf *ibuf = update_do_scale(
- rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
-
- if (ibuf->rect_float) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, ibuf->rect_float);
- }
- else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- }
-
- IMB_freeImBuf(ibuf);
-}
-
-static void gpu_texture_update_unscaled(uchar *rect,
- float *rect_float,
- int x,
- int y,
- int layer,
- int w,
- int h,
- GLint tex_stride,
- GLint tex_offset)
-{
- /* Partial update without scaling. Stride and offset are used to copy only a
- * subset of a possible larger buffer than what we are updating. */
- GPU_unpack_row_length_set(tex_stride);
-
- if (layer >= 0) {
- if (rect_float == NULL) {
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- x,
- y,
- layer,
- w,
- h,
- 1,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- rect + tex_offset);
- }
- else {
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- x,
- y,
- layer,
- w,
- h,
- 1,
- GL_RGBA,
- GL_FLOAT,
- rect_float + tex_offset);
- }
- }
- else {
- if (rect_float == NULL) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect + tex_offset);
- }
- else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, rect_float + tex_offset);
- }
- }
-
- /* Restore default. */
- GPU_unpack_row_length_set(0);
-}
-
-static void gpu_texture_update_from_ibuf(
- GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
-{
- /* Partial update of texture for texture painting. This is often much
- * quicker than fully updating the texture for high resolution images. */
- GPU_texture_bind(tex, 0);
-
- bool scaled;
- if (tile != NULL) {
- int *tilesize = tile->runtime.tilearray_size;
- scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
- }
- else {
- scaled = is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y);
- }
-
- if (scaled) {
- /* Extra padding to account for bleed from neighboring pixels. */
- const int padding = 4;
- const int xmax = min_ii(x + w + padding, ibuf->x);
- const int ymax = min_ii(y + h + padding, ibuf->y);
- x = max_ii(x - padding, 0);
- y = max_ii(y - padding, 0);
- w = xmax - x;
- h = ymax - y;
- }
-
- /* Get texture data pointers. */
- float *rect_float = ibuf->rect_float;
- uchar *rect = (uchar *)ibuf->rect;
- GLint tex_stride = ibuf->x;
- GLint tex_offset = ibuf->channels * (y * ibuf->x + x);
-
- if (rect_float == NULL) {
- /* Byte pixels. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
- ibuf->rect_colorspace);
-
- rect = MEM_mallocN(sizeof(uchar) * 4 * w * h, __func__);
- if (rect == NULL) {
- return;
- }
-
- tex_stride = w;
- tex_offset = 0;
-
- /* Convert to scene linear with sRGB compression, and premultiplied for
- * correct texture interpolation. */
- const bool store_premultiplied = (ima->alpha_mode == IMA_ALPHA_PREMUL);
- IMB_colormanagement_imbuf_to_byte_texture(
- rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied);
- }
- }
- else {
- /* Float pixels. */
- const bool store_premultiplied = (ima->alpha_mode != IMA_ALPHA_STRAIGHT);
-
- if (ibuf->channels != 4 || scaled || !store_premultiplied) {
- rect_float = MEM_mallocN(sizeof(float) * 4 * w * h, __func__);
- if (rect_float == NULL) {
- return;
- }
-
- tex_stride = w;
- tex_offset = 0;
-
- IMB_colormanagement_imbuf_to_float_texture(
- rect_float, x, y, w, h, ibuf, store_premultiplied);
- }
- }
-
- if (scaled) {
- /* Slower update where we first have to scale the input pixels. */
- if (tile != NULL) {
- int *tileoffset = tile->runtime.tilearray_offset;
- int *tilesize = tile->runtime.tilearray_size;
- int tilelayer = tile->runtime.tilearray_layer;
- gpu_texture_update_scaled_array(
- rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
- }
- else {
- gpu_texture_update_scaled(rect, rect_float, ibuf->x, ibuf->y, x, y, w, h);
- }
- }
- else {
- /* Fast update at same resolution. */
- if (tile != NULL) {
- int *tileoffset = tile->runtime.tilearray_offset;
- int tilelayer = tile->runtime.tilearray_layer;
- gpu_texture_update_unscaled(rect,
- rect_float,
- x + tileoffset[0],
- y + tileoffset[1],
- tilelayer,
- w,
- h,
- tex_stride,
- tex_offset);
- }
- else {
- gpu_texture_update_unscaled(rect, rect_float, x, y, -1, w, h, tex_stride, tex_offset);
- }
- }
-
- /* Free buffers if needed. */
- if (rect && rect != (uchar *)ibuf->rect) {
- MEM_freeN(rect);
- }
- if (rect_float && rect_float != ibuf->rect_float) {
- MEM_freeN(rect_float);
- }
-
- if (GPU_get_mipmap()) {
- glGenerateMipmap((tile != NULL) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D);
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
-
- GPU_texture_unbind(tex);
-}
-
-/* Get the GPUTexture for a given `Image`.
- *
- * `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
- * 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;
- }
-
- /* Free any unused GPU textures, since we know we are in a thread with OpenGL
- * context and might as well ensure we have as much space free as possible. */
- gpu_free_unused_buffers();
-
- /* currently, gpu refresh tagging is used by ima sequences */
- if (ima->gpuflag & IMA_GPU_REFRESH) {
- gpu_free_image(ima, true);
- ima->gpuflag &= ~IMA_GPU_REFRESH;
- }
-
- /* Tag as in active use for garbage collector. */
- BKE_image_tag_time(ima);
-
- /* Test if we already have a texture. */
- GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0);
- if (*tex) {
- return *tex;
- }
-
- /* Check if we have a valid image. If not, we return a dummy
- * texture with zero bindcode so we don't keep trying. */
- uint bindcode = 0;
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- if (tile == NULL || tile->ok == 0) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
- }
-
- /* check if we have a valid image buffer */
- ImBuf *ibuf_intern = ibuf;
- if (ibuf_intern == NULL) {
- ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf_intern == NULL) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
- }
- }
-
- if (textarget == GL_TEXTURE_2D_ARRAY) {
- bindcode = gpu_texture_create_tile_array(ima, ibuf_intern);
- }
- else if (textarget == GL_TEXTURE_1D_ARRAY) {
- bindcode = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
- }
- else {
- bindcode = gpu_texture_create_from_ibuf(ima, ibuf_intern, textarget);
- }
-
- /* if `ibuf` was given, we don't own the `ibuf_intern` */
- if (ibuf == NULL) {
- BKE_image_release_ibuf(ima, ibuf_intern, NULL);
- }
-
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
-
- GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
-
- if (textarget == GL_TEXTURE_1D_ARRAY) {
- /* Special for tile mapping. */
- GPU_texture_mipmap_mode(*tex, false, false);
- }
-
- return *tex;
-#endif
- return NULL;
-}
-
-GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, int textarget)
-{
-#ifndef GPU_STANDALONE
- if (clip == NULL) {
- return NULL;
- }
-
- GPUTexture **tex = gpu_get_movieclip_gputexture(clip, cuser, textarget);
- if (*tex) {
- return *tex;
- }
-
- /* check if we have a valid image buffer */
- uint bindcode = 0;
- ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
- if (ibuf == NULL) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
- }
-
- bindcode = gpu_texture_create_from_ibuf(NULL, ibuf, textarget);
- IMB_freeImBuf(ibuf);
-
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
-#else
- return NULL;
-#endif
-}
-
-void GPU_free_texture_movieclip(struct MovieClip *clip)
-{
- /* number of gpu textures to keep around as cache
- * We don't want to keep too many GPU textures for
- * movie clips around, as they can be large.*/
- const int MOVIECLIP_NUM_GPUTEXTURES = 1;
-
- while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
- MovieClip_RuntimeGPUTexture *tex = BLI_pophead(&clip->runtime.gputextures);
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- /* free glsl image binding */
- if (tex->gputexture[i]) {
- GPU_texture_free(tex->gputexture[i]);
- tex->gputexture[i] = NULL;
- }
- }
- MEM_freeN(tex);
- }
-}
-
-static void **gpu_gen_cube_map(uint *rect, float *frect, int rectw, int recth)
-{
- size_t block_size = frect ? sizeof(float[4]) : sizeof(uchar[4]);
- void **sides = NULL;
- int h = recth / 2;
- int w = rectw / 3;
-
- if (w != h) {
- return sides;
- }
-
- /* PosX, NegX, PosY, NegY, PosZ, NegZ */
- sides = MEM_mallocN(sizeof(void *) * 6, "");
- for (int i = 0; i < 6; i++) {
- sides[i] = MEM_mallocN(block_size * w * h, "");
- }
-
- /* divide image into six parts */
- /* ______________________
- * | | | |
- * | NegX | NegY | PosX |
- * |______|______|______|
- * | | | |
- * | NegZ | PosZ | PosY |
- * |______|______|______|
- */
- if (frect) {
- float(*frectb)[4] = (float(*)[4])frect;
- float(**fsides)[4] = (float(**)[4])sides;
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- memcpy(&fsides[0][x * h + y], &frectb[(recth - y - 1) * rectw + 2 * w + x], block_size);
- memcpy(&fsides[1][x * h + y], &frectb[(y + h) * rectw + w - 1 - x], block_size);
- memcpy(
- &fsides[3][y * w + x], &frectb[(recth - y - 1) * rectw + 2 * w - 1 - x], block_size);
- memcpy(&fsides[5][y * w + x], &frectb[(h - y - 1) * rectw + w - 1 - x], block_size);
- }
- memcpy(&fsides[2][y * w], frectb[y * rectw + 2 * w], block_size * w);
- memcpy(&fsides[4][y * w], frectb[y * rectw + w], block_size * w);
- }
- }
- else {
- uint **isides = (uint **)sides;
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- isides[0][x * h + y] = rect[(recth - y - 1) * rectw + 2 * w + x];
- isides[1][x * h + y] = rect[(y + h) * rectw + w - 1 - x];
- isides[3][y * w + x] = rect[(recth - y - 1) * rectw + 2 * w - 1 - x];
- isides[5][y * w + x] = rect[(h - y - 1) * rectw + w - 1 - x];
- }
- memcpy(&isides[2][y * w], &rect[y * rectw + 2 * w], block_size * w);
- memcpy(&isides[4][y * w], &rect[y * rectw + w], block_size * w);
- }
- }
-
- return sides;
-}
-
-static void gpu_del_cube_map(void **cube_map)
-{
- int i;
- if (cube_map == NULL) {
- return;
- }
- for (i = 0; i < 6; i++) {
- MEM_freeN(cube_map[i]);
- }
- MEM_freeN(cube_map);
-}
-
-/* Image *ima can be NULL */
-void GPU_create_gl_tex(uint *bind,
- uint *rect,
- float *frect,
- int rectw,
- int recth,
- int textarget,
- bool mipmap,
- bool half_float,
- bool use_srgb,
- Image *ima)
-{
- ImBuf *ibuf = NULL;
-
- if (textarget == GL_TEXTURE_2D && is_over_resolution_limit(textarget, rectw, recth)) {
- int tpx = rectw;
- int tpy = recth;
- rectw = smaller_power_of_2_limit(rectw);
- recth = smaller_power_of_2_limit(recth);
-
- if (frect) {
- ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy, 4);
- IMB_scaleImBuf(ibuf, rectw, recth);
-
- frect = ibuf->rect_float;
- }
- else {
- ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy, 4);
- IMB_scaleImBuf(ibuf, rectw, recth);
-
- rect = ibuf->rect;
- }
- }
-
- /* create image */
- glGenTextures(1, (GLuint *)bind);
- glBindTexture(textarget, *bind);
-
- GLenum float_format = (!half_float && (ima && (ima->flag & IMA_HIGH_BITDEPTH))) ? GL_RGBA32F :
- GL_RGBA16F;
- GLenum internal_format = (frect) ? float_format : (use_srgb) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
-
- if (textarget == GL_TEXTURE_2D) {
- if (frect) {
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
- else {
- glTexImage2D(
- GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- }
-
- if (GPU_get_mipmap() && mipmap) {
- glGenerateMipmap(GL_TEXTURE_2D);
- if (ima) {
- ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
- }
- }
- }
- else if (textarget == GL_TEXTURE_CUBE_MAP) {
- int w = rectw / 3, h = recth / 2;
-
- if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
- void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth);
- GLenum type = frect ? GL_FLOAT : GL_UNSIGNED_BYTE;
-
- if (cube_map) {
- for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
- 0,
- internal_format,
- w,
- h,
- 0,
- GL_RGBA,
- type,
- cube_map[i]);
- }
- }
-
- if (GPU_get_mipmap() && mipmap) {
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
-
- if (ima) {
- ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
- }
- }
-
- gpu_del_cube_map(cube_map);
- }
- else {
- printf("Incorrect envmap size\n");
- }
- }
-
- glBindTexture(textarget, 0);
-
- if (ibuf) {
- IMB_freeImBuf(ibuf);
- }
-}
-
-/**
- * GPU_upload_dxt_texture() assumes that the texture is already bound and ready to go.
- * This is so the viewport and the BGE can share some code.
- * Returns false if the provided ImBuf doesn't have a supported DXT compression format
- */
-bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb)
-{
-#ifdef WITH_DDS
- GLint format = 0;
- int blocksize, height, width, i, size, offset = 0;
-
- width = ibuf->x;
- height = ibuf->y;
-
- if (GLEW_EXT_texture_compression_s3tc) {
- if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
- format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT :
- GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- }
- else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
- format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT :
- GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- }
- else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
- format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT :
- GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- }
- }
-
- if (format == 0) {
- fprintf(stderr, "Unable to find a suitable DXT compression, falling back to uncompressed\n");
- return false;
- }
-
- if (!is_power_of_2_resolution(width, height)) {
- fprintf(
- stderr,
- "Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n");
- return false;
- }
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
-
- /* Reset to opengl Defaults. (Untested, might not be needed) */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
- blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) {
- if (width == 0) {
- width = 1;
- }
- if (height == 0) {
- height = 1;
- }
-
- size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
-
- glCompressedTexImage2D(
- GL_TEXTURE_2D, i, format, width, height, 0, size, ibuf->dds_data.data + offset);
-
- offset += size;
- width >>= 1;
- height >>= 1;
- }
- /* Restore Blender default. */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- /* set number of mipmap levels we have, needed in case they don't go down to 1x1 */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
-
- return true;
-#else
- UNUSED_VARS(ibuf, use_srgb);
- return false;
-#endif
-}
-
-void GPU_create_gl_tex_compressed(unsigned int *bind, int textarget, Image *ima, ImBuf *ibuf)
-{
- /* For DDS we only support data, scene linear and sRGB. Converting to
- * different colorspace would break the compression. */
- const bool use_srgb = !(IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
- IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- const bool mipmap = GPU_get_mipmap();
- const bool half_float = (ibuf->flags & IB_halffloat) != 0;
-
-#ifndef WITH_DDS
- (void)ibuf;
- /* Fall back to uncompressed if DDS isn't enabled */
- GPU_create_gl_tex(
- bind, ibuf->rect, NULL, ibuf->x, ibuf->y, textarget, mipmap, half_float, use_srgb, ima);
-#else
- glGenTextures(1, (GLuint *)bind);
- glBindTexture(textarget, *bind);
-
- if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf, use_srgb) == 0) {
- glDeleteTextures(1, (GLuint *)bind);
- GPU_create_gl_tex(
- bind, ibuf->rect, NULL, ibuf->x, ibuf->y, textarget, mipmap, half_float, use_srgb, ima);
- }
-
- glBindTexture(textarget, 0);
-#endif
-}
-
-/* these two functions are called on entering and exiting texture paint mode,
- * temporary disabling/enabling mipmapping on all images for quick texture
- * updates with glTexSubImage2D. images that didn't change don't have to be
- * re-uploaded to OpenGL */
-void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
-{
-#ifndef GPU_STANDALONE
- if (!GTS.domipmap) {
- return;
- }
-
- GTS.texpaint = !mipmap;
-
- if (mipmap) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (BKE_image_has_opengl_texture(ima)) {
- if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
- for (int eye = 0; eye < 2; eye++) {
- for (int a = 0; a < TEXTARGET_COUNT; a++) {
- if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) {
- GPUTexture *tex = ima->gputexture[a][eye];
- if (tex != NULL) {
- GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(tex);
- }
- }
- }
- }
- }
- else {
- GPU_free_image(ima);
- }
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
- }
- }
- else {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (BKE_image_has_opengl_texture(ima)) {
- for (int eye = 0; eye < 2; eye++) {
- for (int a = 0; a < TEXTARGET_COUNT; a++) {
- if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) {
- GPUTexture *tex = ima->gputexture[a][eye];
- if (tex != NULL) {
- GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(tex);
- }
- }
- }
- }
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
- }
- }
-#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);
-
- if ((ibuf == NULL) || (w == 0) || (h == 0)) {
- /* Full reload of texture. */
- GPU_free_image(ima);
- }
-
- GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D][0];
- /* Check if we need to update the main gputexture. */
- if (tex != NULL && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
- }
-
- /* Check if we need to update the array gputexture. */
- tex = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][0];
- if (tex != NULL) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-#endif
-}
-
-/* Delayed GPU texture free. Image datablocks can be deleted by any thread,
- * but there may not be any active OpenGL context. In that case we push them
- * into a queue and free the buffers later. */
-static LinkNode *gpu_texture_free_queue = NULL;
-static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
-
-static void gpu_free_unused_buffers()
-{
- if (gpu_texture_free_queue == NULL) {
- return;
- }
-
- BLI_mutex_lock(&gpu_texture_queue_mutex);
-
- if (gpu_texture_free_queue != NULL) {
- for (LinkNode *node = gpu_texture_free_queue; node; node = node->next) {
- GPUTexture *tex = node->link;
- GPU_texture_free(tex);
- }
-
- BLI_linklist_free(gpu_texture_free_queue, NULL);
- gpu_texture_free_queue = NULL;
- }
-
- BLI_mutex_unlock(&gpu_texture_queue_mutex);
-}
-
-static void gpu_free_image(Image *ima, const bool immediate)
-{
- for (int eye = 0; eye < 2; eye++) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye] != NULL) {
- if (immediate) {
- GPU_texture_free(ima->gputexture[i][eye]);
- }
- else {
- BLI_mutex_lock(&gpu_texture_queue_mutex);
- BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
- BLI_mutex_unlock(&gpu_texture_queue_mutex);
- }
-
- ima->gputexture[i][eye] = NULL;
- }
- }
- }
-
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
-}
-
-void GPU_free_unused_buffers()
-{
- if (BLI_thread_is_main()) {
- gpu_free_unused_buffers();
- }
-}
-
-void GPU_free_image(Image *ima)
-{
- gpu_free_image(ima, BLI_thread_is_main());
-}
-
-void GPU_free_images(Main *bmain)
-{
- if (bmain) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- GPU_free_image(ima);
- }
- }
-}
-
-/* same as above but only free animated images */
-void GPU_free_images_anim(Main *bmain)
-{
- if (bmain) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (BKE_image_is_animated(ima)) {
- GPU_free_image(ima);
- }
- }
- }
-}
-
-void GPU_free_images_old(Main *bmain)
-{
- static int lasttime = 0;
- int ctime = (int)PIL_check_seconds_timer();
-
- /*
- * Run garbage collector once for every collecting period of time
- * if textimeout is 0, that's the option to NOT run the collector
- */
- if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) {
- return;
- }
-
- /* of course not! */
- if (G.is_rendering) {
- return;
- }
-
- lasttime = ctime;
-
- Image *ima = bmain->images.first;
- while (ima) {
- if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
- /* If it's in GL memory, deallocate and set time tag to current time
- * This gives textures a "second chance" to be used before dying. */
- if (BKE_image_has_opengl_texture(ima)) {
- GPU_free_image(ima);
- ima->lastused = ctime;
- }
- /* Otherwise, just kill the buffers */
- else {
- BKE_image_free_buffers(ima);
- }
- }
- ima = ima->id.next;
- }
-}
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.cc
index 036588b4a48..9f104ab3fec 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.cc
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
#include "GPU_element.h"
+#include "GPU_glew.h"
#include "gpu_context_private.h"
@@ -37,21 +38,18 @@
static GLenum convert_index_type_to_gl(GPUIndexBufType type)
{
- static const GLenum table[] = {
- [GPU_INDEX_U16] = GL_UNSIGNED_SHORT,
- [GPU_INDEX_U32] = GL_UNSIGNED_INT,
- };
- return table[type];
+#if GPU_TRACK_INDEX_RANGE
+ return (type == GPU_INDEX_U32) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+#else
+ return GL_UNSIGNED_INT;
+#endif
}
uint GPU_indexbuf_size_get(const GPUIndexBuf *elem)
{
#if GPU_TRACK_INDEX_RANGE
- static const uint table[] = {
- [GPU_INDEX_U16] = sizeof(GLushort),
- [GPU_INDEX_U32] = sizeof(GLuint),
- };
- return elem->index_len * table[elem->index_type];
+ return elem->index_len *
+ ((elem->index_type == GPU_INDEX_U32) ? sizeof(GLuint) : sizeof(GLshort));
#else
return elem->index_len * sizeof(GLuint);
#endif
@@ -86,7 +84,7 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder,
builder->max_index_len = index_len;
builder->index_len = 0; // start empty
builder->prim_type = prim_type;
- builder->data = MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
+ builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
}
void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
@@ -241,7 +239,7 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
{
- GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+ GPUIndexBuf *elem = (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
GPU_indexbuf_create_subrange_in_place(elem, elem_src, start, length);
return elem;
}
@@ -331,7 +329,7 @@ static void squeeze_indices_short(GPUIndexBufBuilder *builder,
GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder)
{
- GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+ GPUIndexBuf *elem = (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
GPU_indexbuf_build_in_place(builder, elem);
return elem;
}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.cc
index 9aa3becef1d..32c1bf6e2d3 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.cc
@@ -31,6 +31,8 @@
#include "BKE_global.h"
#include "MEM_guardedalloc.h"
+#include "DNA_userdef_types.h"
+
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_glew.h"
@@ -104,7 +106,8 @@ static struct GPUGlobal {
static void gpu_detect_mip_render_workaround(void)
{
int cube_size = 2;
- float *source_pix = MEM_callocN(sizeof(float) * 4 * 6 * cube_size * cube_size, __func__);
+ float *source_pix = (float *)MEM_callocN(sizeof(float) * 4 * 6 * cube_size * cube_size,
+ __func__);
float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f};
GPUTexture *tex = GPU_texture_create_cube(cube_size, GPU_RGBA16F, source_pix, NULL);
@@ -123,7 +126,7 @@ static void gpu_detect_mip_render_workaround(void)
GPU_framebuffer_restore();
GPU_framebuffer_free(fb);
- float *data = GPU_texture_read(tex, GPU_DATA_FLOAT, 1);
+ float *data = (float *)GPU_texture_read(tex, GPU_DATA_FLOAT, 1);
GG.mip_render_workaround = !equals_v4v4(clear_color, data);
MEM_freeN(data);
@@ -238,6 +241,13 @@ bool GPU_crappy_amd_driver(void)
return GG.broken_amd_driver;
}
+int GPU_texture_size_with_limit(int res)
+{
+ int size = GPU_max_texture_size();
+ int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
+ return min_ii(reslimit, res);
+}
+
void gpu_extensions_init(void)
{
/* during 2.8 development each platform has its own OpenGL minimum requirements
@@ -311,7 +321,7 @@ void gpu_extensions_init(void)
if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) {
/* Limit this fix to older hardware with GL < 4.5. This means Broadwell GPUs are
* covered since they only support GL 4.4 on windows.
- * This fixes some issues with workbench antialiasing on Win + Intel GPU. (see T76273) */
+ * This fixes some issues with workbench anti-aliasing on Win + Intel GPU. (see T76273) */
if (!GLEW_VERSION_4_5) {
GG.texture_copy_workaround = true;
}
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.cc
index 77abb786117..35432b0a8f9 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -28,7 +28,6 @@
#include "BLI_utildefines.h"
#include "GPU_batch.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_shader.h"
@@ -53,6 +52,10 @@ typedef enum {
GPU_FB_MAX_ATTACHEMENT,
} GPUAttachmentType;
+#define FOREACH_ATTACHMENT_RANGE(att, _start, _end) \
+ for (GPUAttachmentType att = static_cast<GPUAttachmentType>(_start); att < _end; \
+ att = static_cast<GPUAttachmentType>(att + 1))
+
#define GPU_FB_MAX_COLOR_ATTACHMENT (GPU_FB_MAX_ATTACHEMENT - GPU_FB_COLOR_ATTACHMENT0)
#define GPU_FB_DIRTY_DRAWBUFFER (1 << 15)
@@ -74,17 +77,25 @@ struct GPUFrameBuffer {
static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
{
- static const GLenum table[] = {
- [GPU_FB_DEPTH_ATTACHMENT] = GL_DEPTH_ATTACHMENT,
- [GPU_FB_DEPTH_STENCIL_ATTACHMENT] = GL_DEPTH_STENCIL_ATTACHMENT,
- [GPU_FB_COLOR_ATTACHMENT0] = GL_COLOR_ATTACHMENT0,
- [GPU_FB_COLOR_ATTACHMENT1] = GL_COLOR_ATTACHMENT1,
- [GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2,
- [GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3,
- [GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4,
- [GPU_FB_COLOR_ATTACHMENT5] = GL_COLOR_ATTACHMENT5,
- };
- return table[type];
+#define ATTACHMENT(type) \
+ case GPU_FB_##type: { \
+ return GL_##type; \
+ } \
+ ((void)0)
+
+ switch (type) {
+ ATTACHMENT(DEPTH_ATTACHMENT);
+ ATTACHMENT(DEPTH_STENCIL_ATTACHMENT);
+ ATTACHMENT(COLOR_ATTACHMENT0);
+ ATTACHMENT(COLOR_ATTACHMENT1);
+ ATTACHMENT(COLOR_ATTACHMENT2);
+ ATTACHMENT(COLOR_ATTACHMENT3);
+ ATTACHMENT(COLOR_ATTACHMENT4);
+ ATTACHMENT(COLOR_ATTACHMENT5);
+ default:
+ BLI_assert(0);
+ return GL_COLOR_ATTACHMENT0;
+ }
}
static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot)
@@ -98,7 +109,7 @@ static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot)
case GPU_DEPTH32F_STENCIL8:
return GPU_FB_DEPTH_STENCIL_ATTACHMENT;
default:
- return GPU_FB_COLOR_ATTACHMENT0 + slot;
+ return static_cast<GPUAttachmentType>(GPU_FB_COLOR_ATTACHMENT0 + slot);
}
}
@@ -198,7 +209,7 @@ GPUFrameBuffer *GPU_framebuffer_create(void)
{
/* We generate the FB object later at first use in order to
* create the framebuffer in the right opengl context. */
- return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
+ return (GPUFrameBuffer *)MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
}
static void gpu_framebuffer_init(GPUFrameBuffer *fb)
@@ -210,7 +221,8 @@ static void gpu_framebuffer_init(GPUFrameBuffer *fb)
void GPU_framebuffer_free(GPUFrameBuffer *fb)
{
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
+ for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
+ GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex);
}
@@ -304,7 +316,7 @@ void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *fb, GPUTexture *tex, in
void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
{
- GPUAttachmentType type = GPU_texture_detach_framebuffer(tex, fb);
+ GPUAttachmentType type = (GPUAttachmentType)GPU_texture_detach_framebuffer(tex, fb);
GPU_framebuffer_texture_detach_slot(fb, tex, type);
}
@@ -387,8 +399,8 @@ static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb)
BLI_assert(GPU_framebuffer_active_get() == fb);
/* Update attachments */
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
-
+ FOREACH_ATTACHMENT_RANGE(type, 0, GPU_FB_MAX_ATTACHEMENT)
+ {
if (type >= GPU_FB_COLOR_ATTACHMENT0) {
if (fb->attachments[type].tex) {
gl_attachments[numslots] = convert_attachment_type_to_gl(type);
@@ -438,7 +450,8 @@ static void gpu_framebuffer_update_attachments_and_fill_empty_slots(GPUFrameBuff
BLI_assert(GPU_framebuffer_active_get() == fb);
/* Update attachments */
- for (GPUAttachmentType type = GPU_FB_MAX_ATTACHEMENT; type--;) {
+ for (int i_type = GPU_FB_MAX_ATTACHEMENT; i_type >= 0; --i_type) {
+ GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
GPUTexture *tex = fb->attachments[type].tex;
if (type >= GPU_FB_COLOR_ATTACHMENT0) {
@@ -623,8 +636,9 @@ void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
- for (int i = 0; type < GPU_FB_MAX_ATTACHEMENT; i++, type++) {
+ int i_type = GPU_FB_COLOR_ATTACHMENT0;
+ for (int i = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i++, i_type++) {
+ GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
glClearBufferfv(GL_COLOR, i, clear_cols[i]);
}
@@ -702,7 +716,8 @@ void GPU_framebuffer_read_color(GPUFrameBuffer *fb,
void *data)
{
CHECK_FRAMEBUFFER_IS_BOUND(fb);
- gpu_framebuffer_read_color_ex(x, y, w, h, channels, GL_COLOR_ATTACHMENT0 + slot, format, data);
+ gpu_framebuffer_read_color_ex(
+ x, y, w, h, channels, GL_COLOR_ATTACHMENT0 + slot, format, (float *)data);
}
/* read_slot and write_slot are only used for color buffers. */
@@ -815,7 +830,8 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
current_dim[0] = max_ii(current_dim[0] / 2, 1);
current_dim[1] = max_ii(current_dim[1] / 2, 1);
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
+ for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
+ GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
/* Some Intel HDXXX have issue with rendering to a mipmap that is below
* the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
@@ -844,7 +860,8 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
}
}
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
+ for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
+ GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
/* reset mipmap level range */
GPUTexture *tex = fb->attachments[type].tex;
@@ -885,9 +902,11 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
for (int i = 0; i < MAX_CTX_FB_LEN; i++) {
if (ofs->framebuffers[i].fb == NULL) {
ofs->framebuffers[i].ctx = ctx;
- GPU_framebuffer_ensure_config(
- &ofs->framebuffers[i].fb,
- {GPU_ATTACHMENT_TEXTURE(ofs->depth), GPU_ATTACHMENT_TEXTURE(ofs->color)});
+ GPU_framebuffer_ensure_config(&ofs->framebuffers[i].fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(ofs->depth),
+ GPU_ATTACHMENT_TEXTURE(ofs->color),
+ });
}
if (ofs->framebuffers[i].ctx == ctx) {
@@ -916,9 +935,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
GPUOffScreen *GPU_offscreen_create(
int width, int height, bool depth, bool high_bitdepth, char err_out[256])
{
- GPUOffScreen *ofs;
-
- ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
+ GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__);
/* Sometimes areas can have 0 height or width and this will
* create a 1D texture which we don't want. */
@@ -975,7 +992,7 @@ void GPU_offscreen_free(GPUOffScreen *ofs)
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
{
if (save) {
- gpuPushAttr(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT);
+ gpuPushAttr((eGPUAttrMask)(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT));
GPUFrameBuffer *fb = GPU_framebuffer_active_get();
gpuPushFrameBuffer(fb);
}
@@ -1023,14 +1040,15 @@ void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y)
glBindFramebuffer(GL_READ_FRAMEBUFFER, GPU_framebuffer_default());
}
-void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
+void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat type, void *pixels)
{
const int w = GPU_texture_width(ofs->color);
const int h = GPU_texture_height(ofs->color);
- BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT);
+ BLI_assert(ELEM(type, GPU_DATA_UNSIGNED_BYTE, GPU_DATA_FLOAT));
+ GLenum gl_type = (type == GPU_DATA_FLOAT) ? GL_FLOAT : GL_UNSIGNED_BYTE;
- glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
+ glReadPixels(0, 0, w, h, GL_RGBA, gl_type, pixels);
}
int GPU_offscreen_width(const GPUOffScreen *ofs)
@@ -1077,8 +1095,7 @@ void GPU_clear(eGPUFrameBufferBits flags)
void GPU_frontbuffer_read_pixels(
int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
{
- glReadBuffer(GL_FRONT);
- gpu_framebuffer_read_color_ex(x, y, w, h, channels, GL_FRONT, format, data);
+ gpu_framebuffer_read_color_ex(x, y, w, h, channels, GL_FRONT, format, (float *)data);
}
/* For stereo rendering. */
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.cc
index 4f5cb3fcc91..ac3e653c9ff 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -29,6 +29,7 @@
#include "GPU_attr_binding.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_texture.h"
#include "gpu_attr_binding_private.h"
@@ -40,10 +41,6 @@
#include <stdlib.h>
#include <string.h>
-/* necessary functions from matrix API */
-extern void GPU_matrix_bind(const GPUShaderInterface *);
-extern bool GPU_matrix_dirty_get(void);
-
typedef struct ImmediateDrawBuffer {
GLuint vbo_id;
GLubyte *buffer_data;
@@ -75,7 +72,7 @@ typedef struct {
GLuint vao_id;
- GLuint bound_program;
+ GPUShader *bound_program;
const GPUShaderInterface *shader_interface;
GPUAttrBinding attr_binding;
uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */
@@ -146,48 +143,47 @@ GPUVertFormat *immVertexFormat(void)
return &imm.vertex_format;
}
-void immBindProgram(GLuint program, const GPUShaderInterface *shaderface)
+void immBindShader(GPUShader *shader)
{
#if TRUST_NO_ONE
- assert(imm.bound_program == 0);
- assert(glIsProgram(program));
+ assert(imm.bound_program == NULL);
+ assert(glIsProgram(shader->program));
#endif
- imm.bound_program = program;
- imm.shader_interface = shaderface;
+ imm.bound_program = shader;
+ imm.shader_interface = shader->interface;
if (!imm.vertex_format.packed) {
VertexFormat_pack(&imm.vertex_format);
}
- glUseProgram(program);
- get_attr_locations(&imm.vertex_format, &imm.attr_binding, shaderface);
- GPU_matrix_bind(shaderface);
- GPU_shader_set_srgb_uniform(shaderface);
+ GPU_shader_bind(shader);
+ get_attr_locations(&imm.vertex_format, &imm.attr_binding, imm.shader_interface);
+ GPU_matrix_bind(imm.shader_interface);
+ GPU_shader_set_srgb_uniform(imm.shader_interface);
}
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
{
GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
- immBindProgram(shader->program, shader->interface);
+ immBindShader(shader);
}
void immUnbindProgram(void)
{
#if TRUST_NO_ONE
- assert(imm.bound_program != 0);
+ assert(imm.bound_program != NULL);
#endif
#if PROGRAM_NO_OPTI
glUseProgram(0);
#endif
- imm.bound_program = 0;
+ imm.bound_program = NULL;
}
/* XXX do not use it. Special hack to use OCIO with batch API. */
-void immGetProgram(GLuint *program, GPUShaderInterface **shaderface)
+GPUShader *immGetShader(void)
{
- *program = imm.bound_program;
- *shaderface = (GPUShaderInterface *)imm.shader_interface;
+ return imm.bound_program;
}
#if TRUST_NO_ONE
@@ -281,7 +277,7 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
}
#endif
- active_buffer->buffer_data = glMapBufferRange(
+ active_buffer->buffer_data = (GLubyte *)glMapBufferRange(
GL_ARRAY_BUFFER,
active_buffer->buffer_offset,
bytes_needed,
@@ -367,17 +363,18 @@ static void immDrawSetup(void)
const GLvoid *pointer = (const GLubyte *)0 + offset;
const uint loc = read_attr_location(&imm.attr_binding, a_idx);
+ const GLenum type = convert_comp_type_to_gl(static_cast<GPUVertCompType>(a->comp_type));
switch (a->fetch_mode) {
case GPU_FETCH_FLOAT:
case GPU_FETCH_INT_TO_FLOAT:
- glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer);
+ glVertexAttribPointer(loc, a->comp_len, type, GL_FALSE, stride, pointer);
break;
case GPU_FETCH_INT_TO_FLOAT_UNIT:
- glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer);
+ glVertexAttribPointer(loc, a->comp_len, type, GL_TRUE, stride, pointer);
break;
case GPU_FETCH_INT:
- glVertexAttribIPointer(loc, a->comp_len, a->gl_comp_type, stride, pointer);
+ glVertexAttribIPointer(loc, a->comp_len, type, stride, pointer);
}
}
@@ -425,7 +422,7 @@ void immEnd(void)
GPU_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_len);
/* TODO: resize only if vertex count is much smaller */
}
- GPU_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
+ GPU_batch_set_shader(imm.batch, imm.bound_program);
imm.batch->phase = GPU_BATCH_READY_TO_DRAW;
imm.batch = NULL; /* don't free, batch belongs to caller */
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index c65c1046b8f..f3477b6f3a4 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -85,7 +85,7 @@ struct GPUMaterial {
bool has_surface_output;
/* Only used by Eevee to know which bsdf are used. */
- int flag;
+ eGPUMatFlag flag;
/* Used by 2.8 pipeline */
GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
@@ -659,7 +659,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
const char *geom_code,
const char *frag_lib,
const char *defines,
- const char *name)
+ const char *name,
+ GPUMaterialEvalCallbackFn callback)
{
LinkData *link;
bool has_volume_output, has_surface_output;
@@ -696,6 +697,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
mat->has_volume_output = has_volume_output;
if (mat->graph.outlink) {
+ if (callback) {
+ callback(mat, options, &vert_code, &geom_code, &frag_lib, &defines);
+ }
/* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */
if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
defines = BLI_string_joinN(defines,
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index bf59b720cff..a133dd1ccdc 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -29,7 +29,6 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
-#include "GPU_glew.h"
#include "GPU_material.h"
#include "GPU_shader.h"
diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.cc
index 5cabde61bc3..5cabde61bc3 100644
--- a/source/blender/gpu/intern/gpu_platform.c
+++ b/source/blender/gpu/intern/gpu_platform.cc
diff --git a/source/blender/gpu/intern/gpu_primitive.c b/source/blender/gpu/intern/gpu_primitive.c
index 2285c1ab95b..3b11b38db87 100644
--- a/source/blender/gpu/intern/gpu_primitive.c
+++ b/source/blender/gpu/intern/gpu_primitive.c
@@ -26,35 +26,6 @@
#include "GPU_primitive.h"
#include "gpu_primitive_private.h"
-GPUPrimClass GPU_primtype_class(GPUPrimType prim_type)
-{
- static const GPUPrimClass classes[] = {
- [GPU_PRIM_POINTS] = GPU_PRIM_CLASS_POINT,
- [GPU_PRIM_LINES] = GPU_PRIM_CLASS_LINE,
- [GPU_PRIM_LINE_STRIP] = GPU_PRIM_CLASS_LINE,
- [GPU_PRIM_LINE_LOOP] = GPU_PRIM_CLASS_LINE,
- [GPU_PRIM_TRIS] = GPU_PRIM_CLASS_SURFACE,
- [GPU_PRIM_TRI_STRIP] = GPU_PRIM_CLASS_SURFACE,
- [GPU_PRIM_TRI_FAN] = GPU_PRIM_CLASS_SURFACE,
-
- [GPU_PRIM_LINES_ADJ] = GPU_PRIM_CLASS_LINE,
- [GPU_PRIM_LINE_STRIP_ADJ] = GPU_PRIM_CLASS_LINE,
- [GPU_PRIM_TRIS_ADJ] = GPU_PRIM_CLASS_SURFACE,
-
- [GPU_PRIM_NONE] = GPU_PRIM_CLASS_NONE,
- };
-
- return classes[prim_type];
-}
-
-bool GPU_primtype_belongs_to_class(GPUPrimType prim_type, GPUPrimClass prim_class)
-{
- if (prim_class == GPU_PRIM_CLASS_NONE && prim_type == GPU_PRIM_NONE) {
- return true;
- }
- return prim_class & GPU_primtype_class(prim_type);
-}
-
GLenum convert_prim_type_to_gl(GPUPrimType prim_type)
{
#if TRUST_NO_ONE
diff --git a/source/blender/gpu/intern/gpu_primitive_private.h b/source/blender/gpu/intern/gpu_primitive_private.h
index abefa6abd20..b7d7b262128 100644
--- a/source/blender/gpu/intern/gpu_primitive_private.h
+++ b/source/blender/gpu/intern/gpu_primitive_private.h
@@ -26,6 +26,15 @@
#ifndef __GPU_PRIMITIVE_PRIVATE_H__
#define __GPU_PRIMITIVE_PRIVATE_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* TODO(fclem) move to OGL backend */
GLenum convert_prim_type_to_gl(GPUPrimType);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __GPU_PRIMITIVE_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 7846bff87f4..ed729dd399c 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -21,6 +21,10 @@
#ifndef __GPU_PRIVATE_H__
#define __GPU_PRIVATE_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* call this before running any of the functions below */
void gpu_platform_init(void);
void gpu_platform_exit(void);
@@ -41,4 +45,8 @@ void gpu_framebuffer_module_exit(void);
void gpu_pbvh_init(void);
void gpu_pbvh_exit(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __GPU_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 5766a176a96..c069cbe012f 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -26,7 +26,6 @@
#include <stdlib.h>
#include <string.h>
-#include "GPU_glew.h"
#include "GPU_select.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index c6d8545527c..3025b5d66da 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include <string.h>
-#include "GPU_draw.h"
#include "GPU_glew.h"
#include "GPU_immediate.h"
#include "GPU_select.h"
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
new file mode 100644
index 00000000000..2b54e733bf5
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -0,0 +1,839 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_appdir.h"
+#include "BKE_global.h"
+
+#include "DNA_space_types.h"
+
+#include "GPU_extensions.h"
+#include "GPU_matrix.h"
+#include "GPU_platform.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
+
+#include "gpu_shader_private.h"
+
+extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
+
+/* Adjust these constants as needed. */
+#define MAX_DEFINE_LENGTH 256
+#define MAX_EXT_DEFINE_LENGTH 512
+
+#ifndef NDEBUG
+static uint g_shaderid = 0;
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Convenience functions
+ * \{ */
+
+static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
+{
+ int line = 1;
+
+ fprintf(stderr, "GPUShader: %s error:\n", task);
+
+ for (int i = 0; i < totcode; i++) {
+ const char *c, *pos, *end = code[i] + strlen(code[i]);
+
+ if (G.debug & G_DEBUG) {
+ fprintf(stderr, "===== shader string %d ====\n", i + 1);
+
+ c = code[i];
+ while ((c < end) && (pos = strchr(c, '\n'))) {
+ fprintf(stderr, "%2d ", line);
+ fwrite(c, (pos + 1) - c, 1, stderr);
+ c = pos + 1;
+ line++;
+ }
+
+ fprintf(stderr, "%s", c);
+ }
+ }
+
+ fprintf(stderr, "%s\n", log);
+}
+
+static const char *gpu_shader_version(void)
+{
+ return "#version 330\n";
+}
+
+static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
+{
+ /* enable extensions for features that are not part of our base GLSL version
+ * don't use an extension for something already available!
+ */
+
+ if (GLEW_ARB_texture_gather) {
+ /* There is a bug on older Nvidia GPU where GL_ARB_texture_gather
+ * is reported to be supported but yield a compile error (see T55802). */
+ if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) || GLEW_VERSION_4_0) {
+ strcat(defines, "#extension GL_ARB_texture_gather: enable\n");
+
+ /* Some drivers don't agree on GLEW_ARB_texture_gather and the actual support in the
+ * shader so double check the preprocessor define (see T56544). */
+ if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && !GLEW_VERSION_4_0) {
+ strcat(defines, "#ifdef GL_ARB_texture_gather\n");
+ strcat(defines, "# define GPU_ARB_texture_gather\n");
+ strcat(defines, "#endif\n");
+ }
+ else {
+ strcat(defines, "#define GPU_ARB_texture_gather\n");
+ }
+ }
+ }
+ if (GLEW_ARB_texture_query_lod) {
+ /* a #version 400 feature, but we use #version 330 maximum so use extension */
+ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
+ }
+ 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])
+{
+ /* some useful defines to detect GPU type */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define GPU_ATI\n");
+ if (GPU_crappy_amd_driver()) {
+ strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n");
+ }
+ }
+ else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define GPU_NVIDIA\n");
+ }
+ else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define GPU_INTEL\n");
+ }
+
+ /* some useful defines to detect OS type */
+ if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_WIN, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define OS_WIN\n");
+ }
+ else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define OS_MAC\n");
+ }
+ else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define OS_UNIX\n");
+ }
+
+ float derivatives_factors[2];
+ GPU_get_dfdy_factors(derivatives_factors);
+ if (derivatives_factors[0] == 1.0f) {
+ strcat(defines, "#define DFDX_SIGN 1.0\n");
+ }
+ else {
+ strcat(defines, "#define DFDX_SIGN -1.0\n");
+ }
+
+ if (derivatives_factors[1] == 1.0f) {
+ strcat(defines, "#define DFDY_SIGN 1.0\n");
+ }
+ else {
+ strcat(defines, "#define DFDY_SIGN -1.0\n");
+ }
+}
+
+#define DEBUG_SHADER_NONE ""
+#define DEBUG_SHADER_VERTEX "vert"
+#define DEBUG_SHADER_FRAGMENT "frag"
+#define DEBUG_SHADER_GEOMETRY "geom"
+
+/**
+ * Dump GLSL shaders to disk
+ *
+ * This is used for profiling shader performance externally and debug if shader code is correct.
+ * If called with no code, it simply bumps the shader index, so different shaders for the same
+ * program share the same index.
+ */
+static void gpu_dump_shaders(const char **code, const int num_shaders, const char *extension)
+{
+ if ((G.debug & G_DEBUG_GPU_SHADERS) == 0) {
+ return;
+ }
+
+ /* We use the same shader index for shaders in the same program.
+ * So we call this function once before calling for the individual shaders. */
+ static int shader_index = 0;
+ if (code == NULL) {
+ shader_index++;
+ BLI_assert(STREQ(DEBUG_SHADER_NONE, extension));
+ return;
+ }
+
+ /* Determine the full path of the new shader. */
+ char shader_path[FILE_MAX];
+
+ char file_name[512] = {'\0'};
+ sprintf(file_name, "%04d.%s", shader_index, extension);
+
+ BLI_join_dirfile(shader_path, sizeof(shader_path), BKE_tempdir_session(), file_name);
+
+ /* Write shader to disk. */
+ FILE *f = fopen(shader_path, "w");
+ if (f == NULL) {
+ printf("Error writing to file: %s\n", shader_path);
+ }
+ for (int j = 0; j < num_shaders; j++) {
+ fprintf(f, "%s", code[j]);
+ }
+ fclose(f);
+ printf("Shader file written to disk: %s\n", shader_path);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Creation / Destruction
+ * \{ */
+
+GPUShader *GPU_shader_create(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ const char *shname)
+{
+ return GPU_shader_create_ex(
+ vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname);
+}
+
+GPUShader *GPU_shader_create_from_python(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines)
+{
+ char *libcodecat = NULL;
+
+ if (libcode == NULL) {
+ libcode = datatoc_gpu_shader_colorspace_lib_glsl;
+ }
+ else {
+ libcode = libcodecat = BLI_strdupcat(libcode, datatoc_gpu_shader_colorspace_lib_glsl);
+ }
+
+ GPUShader *sh = GPU_shader_create_ex(
+ vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL);
+
+ MEM_SAFE_FREE(libcodecat);
+ return sh;
+}
+
+GPUShader *GPU_shader_load_from_binary(const char *binary,
+ const int binary_format,
+ const int binary_len,
+ const char *shname)
+{
+ BLI_assert(GL_ARB_get_program_binary);
+ int success;
+ int program = glCreateProgram();
+
+ glProgramBinary(program, binary_format, binary, binary_len);
+ glGetProgramiv(program, GL_LINK_STATUS, &success);
+
+ if (success) {
+ glUseProgram(program);
+
+ GPUShader *shader = (GPUShader *)MEM_callocN(sizeof(*shader), __func__);
+ shader->interface = GPU_shaderinterface_create(program);
+ shader->program = program;
+
+#ifndef NDEBUG
+ BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++);
+#else
+ UNUSED_VARS(shname);
+#endif
+
+ return shader;
+ }
+
+ glDeleteProgram(program);
+ return NULL;
+}
+
+GPUShader *GPU_shader_create_ex(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ const eGPUShaderTFBType tf_type,
+ const char **tf_names,
+ const int tf_count,
+ const char *shname)
+{
+ GLint status;
+ GLchar log[5000];
+ GLsizei length = 0;
+ GPUShader *shader;
+ char standard_defines[MAX_DEFINE_LENGTH] = "";
+ char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
+
+ shader = (GPUShader *)MEM_callocN(sizeof(GPUShader), "GPUShader");
+ gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE);
+
+#ifndef NDEBUG
+ BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++);
+#else
+ UNUSED_VARS(shname);
+#endif
+
+ /* At least a vertex shader and a fragment shader are required. */
+ BLI_assert((fragcode != NULL) && (vertexcode != NULL));
+
+ if (vertexcode) {
+ shader->vertex = glCreateShader(GL_VERTEX_SHADER);
+ }
+ if (fragcode) {
+ shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ }
+ if (geocode) {
+ shader->geometry = glCreateShader(GL_GEOMETRY_SHADER);
+ }
+
+ shader->program = glCreateProgram();
+
+ if (!shader->program || (vertexcode && !shader->vertex) || (fragcode && !shader->fragment) ||
+ (geocode && !shader->geometry)) {
+ fprintf(stderr, "GPUShader, object creation failed.\n");
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+ gpu_shader_standard_defines(standard_defines);
+ gpu_shader_standard_extensions(standard_extensions);
+
+ if (vertexcode) {
+ const char *source[7];
+ /* custom limit, may be too small, beware */
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] =
+ "#define GPU_VERTEX_SHADER\n"
+ "#define IN_OUT out\n";
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (geocode) {
+ source[num_source++] = "#define USE_GEOMETRY_SHADER\n";
+ }
+ if (defines) {
+ source[num_source++] = defines;
+ }
+ source[num_source++] = vertexcode;
+
+ gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX);
+
+ glAttachShader(shader->program, shader->vertex);
+ glShaderSource(shader->vertex, num_source, source, NULL);
+
+ glCompileShader(shader->vertex);
+ glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status);
+
+ if (!status) {
+ glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+ }
+
+ if (fragcode) {
+ const char *source[8];
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] =
+ "#define GPU_FRAGMENT_SHADER\n"
+ "#define IN_OUT in\n";
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (geocode) {
+ source[num_source++] = "#define USE_GEOMETRY_SHADER\n";
+ }
+ if (defines) {
+ source[num_source++] = defines;
+ }
+ if (libcode) {
+ source[num_source++] = libcode;
+ }
+ source[num_source++] = fragcode;
+
+ gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT);
+
+ glAttachShader(shader->program, shader->fragment);
+ glShaderSource(shader->fragment, num_source, source, NULL);
+
+ glCompileShader(shader->fragment);
+ glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status);
+
+ if (!status) {
+ glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+ }
+
+ if (geocode) {
+ const char *source[6];
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] = "#define GPU_GEOMETRY_SHADER\n";
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (defines) {
+ source[num_source++] = defines;
+ }
+ source[num_source++] = geocode;
+
+ gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY);
+
+ glAttachShader(shader->program, shader->geometry);
+ glShaderSource(shader->geometry, num_source, source, NULL);
+
+ glCompileShader(shader->geometry);
+ glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status);
+
+ if (!status) {
+ glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+ }
+
+ if (tf_names != NULL) {
+ glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS);
+ /* Primitive type must be setup */
+ BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
+ shader->feedback_transform_type = tf_type;
+ }
+
+ glLinkProgram(shader->program);
+ glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
+ if (!status) {
+ glGetProgramInfoLog(shader->program, sizeof(log), &length, log);
+ /* print attached shaders in pipeline order */
+ if (defines) {
+ shader_print_errors("linking", log, &defines, 1);
+ }
+ if (vertexcode) {
+ shader_print_errors("linking", log, &vertexcode, 1);
+ }
+ if (geocode) {
+ shader_print_errors("linking", log, &geocode, 1);
+ }
+ if (libcode) {
+ shader_print_errors("linking", log, &libcode, 1);
+ }
+ if (fragcode) {
+ shader_print_errors("linking", log, &fragcode, 1);
+ }
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+ glUseProgram(shader->program);
+ shader->interface = GPU_shaderinterface_create(shader->program);
+
+ return shader;
+}
+
+#undef DEBUG_SHADER_GEOMETRY
+#undef DEBUG_SHADER_FRAGMENT
+#undef DEBUG_SHADER_VERTEX
+#undef DEBUG_SHADER_NONE
+
+void GPU_shader_free(GPUShader *shader)
+{
+#if 0 /* Would be nice to have, but for now the Deferred compilation \
+ * does not have a GPUContext. */
+ BLI_assert(GPU_context_active_get() != NULL);
+#endif
+ BLI_assert(shader);
+
+ if (shader->vertex) {
+ glDeleteShader(shader->vertex);
+ }
+ if (shader->geometry) {
+ glDeleteShader(shader->geometry);
+ }
+ if (shader->fragment) {
+ glDeleteShader(shader->fragment);
+ }
+ if (shader->program) {
+ glDeleteProgram(shader->program);
+ }
+
+ if (shader->interface) {
+ GPU_shaderinterface_discard(shader->interface);
+ }
+
+ MEM_freeN(shader);
+}
+
+static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_is_alloc)
+{
+ bool is_alloc = false;
+ if (str_arr == NULL) {
+ *r_is_alloc = false;
+ return NULL;
+ }
+ /* Skip empty strings (avoid alloc if we can). */
+ while (str_arr[0] && str_arr[0][0] == '\0') {
+ str_arr++;
+ }
+ int i;
+ for (i = 0; str_arr[i]; i++) {
+ if (i != 0 && str_arr[i][0] != '\0') {
+ is_alloc = true;
+ }
+ }
+ *r_is_alloc = is_alloc;
+ if (is_alloc) {
+ return BLI_string_join_arrayN(str_arr, i);
+ }
+ else {
+ return str_arr[0];
+ }
+}
+
+/**
+ * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
+ *
+ * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
+ *
+ * It has the advantage that each item can be conditionally included
+ * without having to build the string inline, then free it.
+ *
+ * \param params: NULL terminated arrays of strings.
+ *
+ * Example:
+ * \code{.c}
+ * sh = GPU_shader_create_from_arrays({
+ * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
+ * .geom = (const char *[]){shader_geom_glsl, NULL},
+ * .frag = (const char *[]){shader_frag_glsl, NULL},
+ * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
+ * });
+ * \endcode
+ */
+struct GPUShader *GPU_shader_create_from_arrays_impl(
+ const struct GPU_ShaderCreateFromArray_Params *params)
+{
+ struct {
+ const char *str;
+ bool is_alloc;
+ } str_dst[4] = {{0}};
+ const char **str_src[4] = {params->vert, params->frag, params->geom, params->defs};
+
+ for (int i = 0; i < ARRAY_SIZE(str_src); i++) {
+ str_dst[i].str = string_join_array_maybe_alloc(str_src[i], &str_dst[i].is_alloc);
+ }
+
+ GPUShader *sh = GPU_shader_create(
+ str_dst[0].str, str_dst[1].str, str_dst[2].str, NULL, str_dst[3].str, __func__);
+
+ for (int i = 0; i < ARRAY_SIZE(str_dst); i++) {
+ if (str_dst[i].is_alloc) {
+ MEM_freeN((void *)str_dst[i].str);
+ }
+ }
+ return sh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Binding
+ * \{ */
+
+void GPU_shader_bind(GPUShader *shader)
+{
+ BLI_assert(shader && shader->program);
+
+ glUseProgram(shader->program);
+ GPU_matrix_bind(shader->interface);
+ GPU_shader_set_srgb_uniform(shader->interface);
+}
+
+void GPU_shader_unbind(void)
+{
+ glUseProgram(0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform feedback
+ * \{ */
+
+bool GPU_shader_transform_feedback_enable(GPUShader *shader, uint vbo_id)
+{
+ if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) {
+ return false;
+ }
+
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id);
+
+ switch (shader->feedback_transform_type) {
+ case GPU_SHADER_TFB_POINTS:
+ glBeginTransformFeedback(GL_POINTS);
+ return true;
+ case GPU_SHADER_TFB_LINES:
+ glBeginTransformFeedback(GL_LINES);
+ return true;
+ case GPU_SHADER_TFB_TRIANGLES:
+ glBeginTransformFeedback(GL_TRIANGLES);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
+{
+ glEndTransformFeedback();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Uniforms / Resource location
+ * \{ */
+
+int GPU_shader_get_uniform(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name);
+ return uniform ? uniform->location : -1;
+}
+
+int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
+{
+ BLI_assert(shader && shader->program);
+ return GPU_shaderinterface_uniform_builtin(shader->interface,
+ static_cast<GPUUniformBuiltin>(builtin));
+}
+
+int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
+{
+ BLI_assert(shader && shader->program);
+ return GPU_shaderinterface_block_builtin(shader->interface,
+ static_cast<GPUUniformBlockBuiltin>(builtin));
+}
+
+int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
+ return ubo ? ubo->location : -1;
+}
+
+int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
+ return ubo ? ubo->binding : -1;
+}
+
+int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name);
+ return tex ? tex->binding : -1;
+}
+
+int GPU_shader_get_attribute(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *attr = GPU_shaderinterface_attr(shader->interface, name);
+ return attr ? attr->location : -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Getters
+ * \{ */
+
+/* Clement : Temp */
+int GPU_shader_get_program(GPUShader *shader)
+{
+ return (int)shader->program;
+}
+
+char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len)
+{
+ BLI_assert(GLEW_ARB_get_program_binary);
+ char *r_binary;
+ int binary_len = 0;
+
+ glGetProgramiv(shader->program, GL_PROGRAM_BINARY_LENGTH, &binary_len);
+ r_binary = (char *)MEM_mallocN(binary_len, __func__);
+ glGetProgramBinary(shader->program, binary_len, NULL, r_binary_format, r_binary);
+
+ if (r_binary_len) {
+ *r_binary_len = binary_len;
+ }
+
+ return r_binary;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Uniforms setters
+ * \{ */
+
+void GPU_shader_uniform_float(GPUShader *UNUSED(shader), int location, float value)
+{
+ if (location == -1) {
+ return;
+ }
+
+ glUniform1f(location, value);
+}
+
+void GPU_shader_uniform_vector(
+ GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
+{
+ if (location == -1 || value == NULL) {
+ return;
+ }
+
+ switch (length) {
+ case 1:
+ glUniform1fv(location, arraysize, value);
+ break;
+ case 2:
+ glUniform2fv(location, arraysize, value);
+ break;
+ case 3:
+ glUniform3fv(location, arraysize, value);
+ break;
+ case 4:
+ glUniform4fv(location, arraysize, value);
+ break;
+ case 9:
+ glUniformMatrix3fv(location, arraysize, 0, value);
+ break;
+ case 16:
+ glUniformMatrix4fv(location, arraysize, 0, value);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
+void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
+{
+ if (location == -1) {
+ return;
+ }
+
+ glUniform1i(location, value);
+}
+
+void GPU_shader_uniform_vector_int(
+ GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
+{
+ if (location == -1) {
+ return;
+ }
+
+ switch (length) {
+ case 1:
+ glUniform1iv(location, arraysize, value);
+ break;
+ case 2:
+ glUniform2iv(location, arraysize, value);
+ break;
+ case 3:
+ glUniform3iv(location, arraysize, value);
+ break;
+ case 4:
+ glUniform4iv(location, arraysize, value);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name sRGB Rendering Workaround
+ *
+ * The viewport overlay frame-buffer is sRGB and will expect shaders to output display referred
+ * Linear colors. But other frame-buffers (i.e: the area frame-buffers) are not sRGB and require
+ * the shader output color to be in sRGB space
+ * (assumed display encoded color-space as the time of writing).
+ * For this reason we have a uniform to switch the transform on and off depending on the current
+ * frame-buffer color-space.
+ * \{ */
+
+static int g_shader_builtin_srgb_transform = 0;
+
+void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface)
+{
+ int32_t loc = GPU_shaderinterface_uniform_builtin(interface, GPU_UNIFORM_SRGB_TRANSFORM);
+ if (loc != -1) {
+ glUniform1i(loc, g_shader_builtin_srgb_transform);
+ }
+}
+
+void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
+{
+ g_shader_builtin_srgb_transform = use_srgb_to_linear;
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 9ea798e5669..9c0692b76e2 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -153,11 +153,6 @@ const struct GPUShaderConfigData GPU_shader_cfg_data[GPU_SHADER_CFG_LEN] = {
/* cache of built-in shaders (each is created on first use) */
static GPUShader *builtin_shaders[GPU_SHADER_CFG_LEN][GPU_SHADER_BUILTIN_LEN] = {{NULL}};
-static int g_shader_builtin_srgb_transform = 0;
-
-#ifndef NDEBUG
-static uint g_shaderid = 0;
-#endif
typedef struct {
const char *vert;
@@ -168,727 +163,6 @@ typedef struct {
const char *defs;
} GPUShaderStages;
-static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
-{
- int line = 1;
-
- fprintf(stderr, "GPUShader: %s error:\n", task);
-
- for (int i = 0; i < totcode; i++) {
- const char *c, *pos, *end = code[i] + strlen(code[i]);
-
- if (G.debug & G_DEBUG) {
- fprintf(stderr, "===== shader string %d ====\n", i + 1);
-
- c = code[i];
- while ((c < end) && (pos = strchr(c, '\n'))) {
- fprintf(stderr, "%2d ", line);
- fwrite(c, (pos + 1) - c, 1, stderr);
- c = pos + 1;
- line++;
- }
-
- fprintf(stderr, "%s", c);
- }
- }
-
- fprintf(stderr, "%s\n", log);
-}
-
-static const char *gpu_shader_version(void)
-{
- return "#version 330\n";
-}
-
-static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
-{
- /* enable extensions for features that are not part of our base GLSL version
- * don't use an extension for something already available!
- */
-
- if (GLEW_ARB_texture_gather) {
- /* There is a bug on older Nvidia GPU where GL_ARB_texture_gather
- * is reported to be supported but yield a compile error (see T55802). */
- if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) || GLEW_VERSION_4_0) {
- strcat(defines, "#extension GL_ARB_texture_gather: enable\n");
-
- /* Some drivers don't agree on GLEW_ARB_texture_gather and the actual support in the
- * shader so double check the preprocessor define (see T56544). */
- if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && !GLEW_VERSION_4_0) {
- strcat(defines, "#ifdef GL_ARB_texture_gather\n");
- strcat(defines, "# define GPU_ARB_texture_gather\n");
- strcat(defines, "#endif\n");
- }
- else {
- strcat(defines, "#define GPU_ARB_texture_gather\n");
- }
- }
- }
- if (GLEW_ARB_texture_query_lod) {
- /* a #version 400 feature, but we use #version 330 maximum so use extension */
- strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
- }
- 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])
-{
- /* some useful defines to detect GPU type */
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- strcat(defines, "#define GPU_ATI\n");
- if (GPU_crappy_amd_driver()) {
- strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n");
- }
- }
- else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- strcat(defines, "#define GPU_NVIDIA\n");
- }
- else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- strcat(defines, "#define GPU_INTEL\n");
- }
-
- /* some useful defines to detect OS type */
- if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_WIN, GPU_DRIVER_ANY)) {
- strcat(defines, "#define OS_WIN\n");
- }
- else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY)) {
- strcat(defines, "#define OS_MAC\n");
- }
- else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
- strcat(defines, "#define OS_UNIX\n");
- }
-
- float derivatives_factors[2];
- GPU_get_dfdy_factors(derivatives_factors);
- if (derivatives_factors[0] == 1.0f) {
- strcat(defines, "#define DFDX_SIGN 1.0\n");
- }
- else {
- strcat(defines, "#define DFDX_SIGN -1.0\n");
- }
-
- if (derivatives_factors[1] == 1.0f) {
- strcat(defines, "#define DFDY_SIGN 1.0\n");
- }
- else {
- strcat(defines, "#define DFDY_SIGN -1.0\n");
- }
-}
-
-GPUShader *GPU_shader_create(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- const char *shname)
-{
- return GPU_shader_create_ex(
- vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname);
-}
-
-GPUShader *GPU_shader_create_from_python(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines)
-{
- char *libcodecat = NULL;
-
- if (libcode == NULL) {
- libcode = datatoc_gpu_shader_colorspace_lib_glsl;
- }
- else {
- libcode = libcodecat = BLI_strdupcat(libcode, datatoc_gpu_shader_colorspace_lib_glsl);
- }
-
- GPUShader *sh = GPU_shader_create_ex(
- vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL);
-
- MEM_SAFE_FREE(libcodecat);
- return sh;
-}
-
-GPUShader *GPU_shader_load_from_binary(const char *binary,
- const int binary_format,
- const int binary_len,
- const char *shname)
-{
- BLI_assert(GL_ARB_get_program_binary);
- int success;
- int program = glCreateProgram();
-
- glProgramBinary(program, binary_format, binary, binary_len);
- glGetProgramiv(program, GL_LINK_STATUS, &success);
-
- if (success) {
- glUseProgram(program);
-
- GPUShader *shader = MEM_callocN(sizeof(*shader), __func__);
- shader->interface = GPU_shaderinterface_create(program);
- shader->program = program;
-
-#ifndef NDEBUG
- BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++);
-#else
- UNUSED_VARS(shname);
-#endif
-
- return shader;
- }
-
- glDeleteProgram(program);
- return NULL;
-}
-
-#define DEBUG_SHADER_NONE ""
-#define DEBUG_SHADER_VERTEX "vert"
-#define DEBUG_SHADER_FRAGMENT "frag"
-#define DEBUG_SHADER_GEOMETRY "geom"
-
-/**
- * Dump GLSL shaders to disk
- *
- * This is used for profiling shader performance externally and debug if shader code is correct.
- * If called with no code, it simply bumps the shader index, so different shaders for the same
- * program share the same index.
- */
-static void gpu_dump_shaders(const char **code, const int num_shaders, const char *extension)
-{
- if ((G.debug & G_DEBUG_GPU_SHADERS) == 0) {
- return;
- }
-
- /* We use the same shader index for shaders in the same program.
- * So we call this function once before calling for the individual shaders. */
- static int shader_index = 0;
- if (code == NULL) {
- shader_index++;
- BLI_assert(STREQ(DEBUG_SHADER_NONE, extension));
- return;
- }
-
- /* Determine the full path of the new shader. */
- char shader_path[FILE_MAX];
-
- char file_name[512] = {'\0'};
- sprintf(file_name, "%04d.%s", shader_index, extension);
-
- BLI_join_dirfile(shader_path, sizeof(shader_path), BKE_tempdir_session(), file_name);
-
- /* Write shader to disk. */
- FILE *f = fopen(shader_path, "w");
- if (f == NULL) {
- printf("Error writing to file: %s\n", shader_path);
- }
- for (int j = 0; j < num_shaders; j++) {
- fprintf(f, "%s", code[j]);
- }
- fclose(f);
- printf("Shader file written to disk: %s\n", shader_path);
-}
-
-GPUShader *GPU_shader_create_ex(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- const eGPUShaderTFBType tf_type,
- const char **tf_names,
- const int tf_count,
- const char *shname)
-{
- GLint status;
- GLchar log[5000];
- GLsizei length = 0;
- GPUShader *shader;
- char standard_defines[MAX_DEFINE_LENGTH] = "";
- char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
-
- shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
- gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE);
-
-#ifndef NDEBUG
- BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++);
-#else
- UNUSED_VARS(shname);
-#endif
-
- /* At least a vertex shader and a fragment shader are required. */
- BLI_assert((fragcode != NULL) && (vertexcode != NULL));
-
- if (vertexcode) {
- shader->vertex = glCreateShader(GL_VERTEX_SHADER);
- }
- if (fragcode) {
- shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
- }
- if (geocode) {
- shader->geometry = glCreateShader(GL_GEOMETRY_SHADER);
- }
-
- shader->program = glCreateProgram();
-
- if (!shader->program || (vertexcode && !shader->vertex) || (fragcode && !shader->fragment) ||
- (geocode && !shader->geometry)) {
- fprintf(stderr, "GPUShader, object creation failed.\n");
- GPU_shader_free(shader);
- return NULL;
- }
-
- gpu_shader_standard_defines(standard_defines);
- gpu_shader_standard_extensions(standard_extensions);
-
- if (vertexcode) {
- const char *source[6];
- /* custom limit, may be too small, beware */
- int num_source = 0;
-
- source[num_source++] = gpu_shader_version();
- source[num_source++] =
- "#define GPU_VERTEX_SHADER\n"
- "#define IN_OUT out\n";
- source[num_source++] = standard_extensions;
- source[num_source++] = standard_defines;
-
- if (defines) {
- source[num_source++] = defines;
- }
- source[num_source++] = vertexcode;
-
- gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX);
-
- glAttachShader(shader->program, shader->vertex);
- glShaderSource(shader->vertex, num_source, source, NULL);
-
- glCompileShader(shader->vertex);
- glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status);
-
- if (!status) {
- glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log);
- shader_print_errors("compile", log, source, num_source);
-
- GPU_shader_free(shader);
- return NULL;
- }
- }
-
- if (fragcode) {
- const char *source[7];
- int num_source = 0;
-
- source[num_source++] = gpu_shader_version();
- source[num_source++] =
- "#define GPU_FRAGMENT_SHADER\n"
- "#define IN_OUT in\n";
- source[num_source++] = standard_extensions;
- source[num_source++] = standard_defines;
-
- if (defines) {
- source[num_source++] = defines;
- }
- if (libcode) {
- source[num_source++] = libcode;
- }
- source[num_source++] = fragcode;
-
- gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT);
-
- glAttachShader(shader->program, shader->fragment);
- glShaderSource(shader->fragment, num_source, source, NULL);
-
- glCompileShader(shader->fragment);
- glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status);
-
- if (!status) {
- glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log);
- shader_print_errors("compile", log, source, num_source);
-
- GPU_shader_free(shader);
- return NULL;
- }
- }
-
- if (geocode) {
- const char *source[6];
- int num_source = 0;
-
- source[num_source++] = gpu_shader_version();
- source[num_source++] = "#define GPU_GEOMETRY_SHADER\n";
- source[num_source++] = standard_extensions;
- source[num_source++] = standard_defines;
-
- if (defines) {
- source[num_source++] = defines;
- }
- source[num_source++] = geocode;
-
- gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY);
-
- glAttachShader(shader->program, shader->geometry);
- glShaderSource(shader->geometry, num_source, source, NULL);
-
- glCompileShader(shader->geometry);
- glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status);
-
- if (!status) {
- glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log);
- shader_print_errors("compile", log, source, num_source);
-
- GPU_shader_free(shader);
- return NULL;
- }
- }
-
- if (tf_names != NULL) {
- glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS);
- /* Primitive type must be setup */
- BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
- shader->feedback_transform_type = tf_type;
- }
-
- glLinkProgram(shader->program);
- glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
- if (!status) {
- glGetProgramInfoLog(shader->program, sizeof(log), &length, log);
- /* print attached shaders in pipeline order */
- if (vertexcode) {
- shader_print_errors("linking", log, &vertexcode, 1);
- }
- if (geocode) {
- shader_print_errors("linking", log, &geocode, 1);
- }
- if (libcode) {
- shader_print_errors("linking", log, &libcode, 1);
- }
- if (fragcode) {
- shader_print_errors("linking", log, &fragcode, 1);
- }
-
- GPU_shader_free(shader);
- return NULL;
- }
-
- glUseProgram(shader->program);
- shader->interface = GPU_shaderinterface_create(shader->program);
-
- return shader;
-}
-
-#undef DEBUG_SHADER_GEOMETRY
-#undef DEBUG_SHADER_FRAGMENT
-#undef DEBUG_SHADER_VERTEX
-#undef DEBUG_SHADER_NONE
-
-static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_is_alloc)
-{
- bool is_alloc = false;
- if (str_arr == NULL) {
- *r_is_alloc = false;
- return NULL;
- }
- /* Skip empty strings (avoid alloc if we can). */
- while (str_arr[0] && str_arr[0][0] == '\0') {
- str_arr++;
- }
- int i;
- for (i = 0; str_arr[i]; i++) {
- if (i != 0 && str_arr[i][0] != '\0') {
- is_alloc = true;
- }
- }
- *r_is_alloc = is_alloc;
- if (is_alloc) {
- return BLI_string_join_arrayN(str_arr, i);
- }
- else {
- return str_arr[0];
- }
-}
-
-/**
- * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
- *
- * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
- *
- * It has the advantage that each item can be conditionally included
- * without having to build the string inline, then free it.
- *
- * \param params: NULL terminated arrays of strings.
- *
- * Example:
- * \code{.c}
- * sh = GPU_shader_create_from_arrays({
- * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
- * .geom = (const char *[]){shader_geom_glsl, NULL},
- * .frag = (const char *[]){shader_frag_glsl, NULL},
- * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
- * });
- * \endcode
- */
-struct GPUShader *GPU_shader_create_from_arrays_impl(
- const struct GPU_ShaderCreateFromArray_Params *params)
-{
- struct {
- const char *str;
- bool is_alloc;
- } str_dst[4] = {{0}};
- const char **str_src[4] = {params->vert, params->frag, params->geom, params->defs};
-
- for (int i = 0; i < ARRAY_SIZE(str_src); i++) {
- str_dst[i].str = string_join_array_maybe_alloc(str_src[i], &str_dst[i].is_alloc);
- }
-
- GPUShader *sh = GPU_shader_create(
- str_dst[0].str, str_dst[1].str, str_dst[2].str, NULL, str_dst[3].str, __func__);
-
- for (int i = 0; i < ARRAY_SIZE(str_dst); i++) {
- if (str_dst[i].is_alloc) {
- MEM_freeN((void *)str_dst[i].str);
- }
- }
- return sh;
-}
-
-void GPU_shader_bind(GPUShader *shader)
-{
- BLI_assert(shader && shader->program);
-
- glUseProgram(shader->program);
- GPU_matrix_bind(shader->interface);
- GPU_shader_set_srgb_uniform(shader->interface);
-}
-
-void GPU_shader_unbind(void)
-{
- glUseProgram(0);
-}
-
-bool GPU_shader_transform_feedback_enable(GPUShader *shader, uint vbo_id)
-{
- if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) {
- return false;
- }
-
- glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id);
-
- switch (shader->feedback_transform_type) {
- case GPU_SHADER_TFB_POINTS:
- glBeginTransformFeedback(GL_POINTS);
- return true;
- case GPU_SHADER_TFB_LINES:
- glBeginTransformFeedback(GL_LINES);
- return true;
- case GPU_SHADER_TFB_TRIANGLES:
- glBeginTransformFeedback(GL_TRIANGLES);
- return true;
- default:
- return false;
- }
-}
-
-void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
-{
- glEndTransformFeedback();
-}
-
-void GPU_shader_free(GPUShader *shader)
-{
-#if 0 /* Would be nice to have, but for now the Deferred compilation \
- * does not have a GPUContext. */
- BLI_assert(GPU_context_active_get() != NULL);
-#endif
- BLI_assert(shader);
-
- if (shader->vertex) {
- glDeleteShader(shader->vertex);
- }
- if (shader->geometry) {
- glDeleteShader(shader->geometry);
- }
- if (shader->fragment) {
- glDeleteShader(shader->fragment);
- }
- if (shader->program) {
- glDeleteProgram(shader->program);
- }
-
- if (shader->interface) {
- GPU_shaderinterface_discard(shader->interface);
- }
-
- MEM_freeN(shader);
-}
-
-int GPU_shader_get_uniform(GPUShader *shader, const char *name)
-{
- BLI_assert(shader && shader->program);
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name);
- return uniform ? uniform->location : -1;
-}
-
-int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
-{
- BLI_assert(shader && shader->program);
- return GPU_shaderinterface_uniform_builtin(shader->interface, builtin);
-}
-
-int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
-{
- BLI_assert(shader && shader->program);
- return GPU_shaderinterface_block_builtin(shader->interface, builtin);
-}
-
-int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
-{
- BLI_assert(shader && shader->program);
- const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
- return ubo ? ubo->location : -1;
-}
-
-int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
-{
- BLI_assert(shader && shader->program);
- const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
- return ubo ? ubo->binding : -1;
-}
-
-int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
-{
- BLI_assert(shader && shader->program);
- const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name);
- return tex ? tex->binding : -1;
-}
-
-void *GPU_shader_get_interface(GPUShader *shader)
-{
- return shader->interface;
-}
-
-/* Clement : Temp */
-int GPU_shader_get_program(GPUShader *shader)
-{
- return (int)shader->program;
-}
-
-void GPU_shader_uniform_float(GPUShader *UNUSED(shader), int location, float value)
-{
- if (location == -1) {
- return;
- }
-
- glUniform1f(location, value);
-}
-
-void GPU_shader_uniform_vector(
- GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
-{
- if (location == -1 || value == NULL) {
- return;
- }
-
- switch (length) {
- case 1:
- glUniform1fv(location, arraysize, value);
- break;
- case 2:
- glUniform2fv(location, arraysize, value);
- break;
- case 3:
- glUniform3fv(location, arraysize, value);
- break;
- case 4:
- glUniform4fv(location, arraysize, value);
- break;
- case 9:
- glUniformMatrix3fv(location, arraysize, 0, value);
- break;
- case 16:
- glUniformMatrix4fv(location, arraysize, 0, value);
- break;
- default:
- BLI_assert(0);
- break;
- }
-}
-
-void GPU_shader_uniform_vector_int(
- GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
-{
- if (location == -1) {
- return;
- }
-
- switch (length) {
- case 1:
- glUniform1iv(location, arraysize, value);
- break;
- case 2:
- glUniform2iv(location, arraysize, value);
- break;
- case 3:
- glUniform3iv(location, arraysize, value);
- break;
- case 4:
- glUniform4iv(location, arraysize, value);
- break;
- default:
- BLI_assert(0);
- break;
- }
-}
-
-void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
-{
- if (location == -1) {
- return;
- }
-
- glUniform1i(location, value);
-}
-
-void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface)
-{
- int32_t loc = GPU_shaderinterface_uniform_builtin(interface, GPU_UNIFORM_SRGB_TRANSFORM);
- if (loc != -1) {
- glUniform1i(loc, g_shader_builtin_srgb_transform);
- }
-}
-
-int GPU_shader_get_attribute(GPUShader *shader, const char *name)
-{
- BLI_assert(shader && shader->program);
- const GPUShaderInput *attr = GPU_shaderinterface_attr(shader->interface, name);
- return attr ? attr->location : -1;
-}
-
-char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len)
-{
- BLI_assert(GLEW_ARB_get_program_binary);
- char *r_binary;
- int binary_len = 0;
-
- glGetProgramiv(shader->program, GL_PROGRAM_BINARY_LENGTH, &binary_len);
- r_binary = MEM_mallocN(binary_len, __func__);
- glGetProgramBinary(shader->program, binary_len, NULL, r_binary_format, r_binary);
-
- if (r_binary_len) {
- *r_binary_len = binary_len;
- }
-
- return r_binary;
-}
-
-void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
-{
- g_shader_builtin_srgb_transform = use_srgb_to_linear;
-}
-
static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
[GPU_SHADER_TEXT] =
{
@@ -1242,6 +516,7 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
return *sh_p;
}
+
GPUShader *GPU_shader_get_builtin_shader(eGPUBuiltinShader shader)
{
return GPU_shader_get_builtin_shader_with_config(shader, GPU_SHADER_CFG_DEFAULT);
diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h
index e4443e79a8d..2c52568ac25 100644
--- a/source/blender/gpu/intern/gpu_shader_private.h
+++ b/source/blender/gpu/intern/gpu_shader_private.h
@@ -21,9 +21,12 @@
#ifndef __GPU_SHADER_PRIVATE_H__
#define __GPU_SHADER_PRIVATE_H__
-#include "GPU_glew.h"
#include "GPU_shader_interface.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct GPUShader {
/** Handle for full program (links shader stages below). */
GLuint program;
@@ -45,6 +48,10 @@ struct GPUShader {
};
/* XXX do not use it. Special hack to use OCIO with batch API. */
-void immGetProgram(GLuint *program, GPUShaderInterface **shaderface);
+GPUShader *immGetShader(void);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* __GPU_SHADER_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.cc
index bd7aff9772b..794c7a3eb97 100644
--- a/source/blender/gpu/intern/gpu_state.c
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -268,6 +268,12 @@ void GPU_clip_distances(int distances_new)
distances_enabled = distances_new;
}
+bool GPU_mipmap_enabled(void)
+{
+ /* TODO(fclem) this used to be a userdef option. */
+ return true;
+}
+
/** \name GPU Push/Pop State
* \{ */
@@ -276,33 +282,18 @@ void GPU_clip_distances(int distances_new)
typedef struct {
eGPUAttrMask mask;
- /* GL_ENABLE_BIT */
+ /* GL_BLEND_BIT */
uint is_blend : 1;
- uint is_cull_face : 1;
- uint is_depth_test : 1;
- /* uint is_lighting : 1; */ /* UNUSED */
- 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;
- uint is_framebuffer_srgb : 1;
-
- bool is_clip_plane[6];
/* GL_DEPTH_BUFFER_BIT */
- /* uint is_depth_test : 1; */
+ 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; */
+ uint is_scissor_test : 1;
/* GL_VIEWPORT_BIT */
int viewport[4];
@@ -315,7 +306,8 @@ typedef struct {
} GPUAttrStack;
static GPUAttrStack state = {
- .top = 0,
+ {},
+ 0,
};
#define AttrStack state
@@ -338,26 +330,6 @@ void gpuPushAttr(eGPUAttrMask mask)
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_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);
@@ -366,7 +338,6 @@ void gpuPushAttr(eGPUAttrMask mask)
if ((mask & GPU_VIEWPORT_BIT) != 0) {
glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far);
glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport);
- Attr.is_framebuffer_srgb = glIsEnabled(GL_FRAMEBUFFER_SRGB);
}
if ((mask & GPU_BLEND_BIT) != 0) {
@@ -401,30 +372,9 @@ void gpuPopAttr(void)
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_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]);
- restore_mask(GL_FRAMEBUFFER_SRGB, Attr.is_framebuffer_srgb);
}
if ((mask & GPU_SCISSOR_BIT) != 0) {
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.cc
index 4c847236f09..8a3a8a382f8 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_image_types.h"
+#include "DNA_userdef_types.h"
#include "BLI_blenlib.h"
#include "BLI_math_base.h"
@@ -36,7 +37,6 @@
#include "GPU_batch.h"
#include "GPU_context.h"
#include "GPU_debug.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_glew.h"
@@ -45,6 +45,16 @@
#include "gpu_context_private.h"
+#define WARN_NOT_BOUND(_tex) \
+ { \
+ if (_tex->number == -1) { \
+ fprintf(stderr, "Warning : Trying to set parameter on a texture not bound.\n"); \
+ BLI_assert(0); \
+ return; \
+ } \
+ } \
+ ((void)0)
+
static struct GPUTextureGlobal {
/** Texture used in place of invalid textures (not loaded correctly, missing). */
GPUTexture *invalid_tex_1D;
@@ -71,6 +81,8 @@ typedef enum eGPUTextureFormatFlag {
GPU_FORMAT_ARRAY = (1 << 14),
} eGPUTextureFormatFlag;
+ENUM_OPERATORS(eGPUTextureFormatFlag)
+
/* GPUTexture */
struct GPUTexture {
int w, h, d; /* width/height/depth */
@@ -103,7 +115,7 @@ static void gpu_texture_framebuffer_ensure(GPUTexture *tex);
/* ------ Memory Management ------- */
/* Records every texture allocation / free
* to estimate the Texture Pool Memory consumption */
-static uint memory_usage;
+static uint memory_usage = 0;
static uint gpu_texture_memory_footprint_compute(GPUTexture *tex)
{
@@ -161,54 +173,58 @@ uint GPU_texture_memory_usage_get(void)
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),
- ENUM_TO_STRING(TEXTURE_1D_ARRAY),
- ENUM_TO_STRING(TEXTURE_3D),
- ENUM_TO_STRING(TEXTURE_2D_MULTISAMPLE),
- ENUM_TO_STRING(RGBA32F),
- ENUM_TO_STRING(RGBA16F),
- ENUM_TO_STRING(RGBA16UI),
- ENUM_TO_STRING(RGBA16I),
- ENUM_TO_STRING(RGBA16),
- ENUM_TO_STRING(RGBA8UI),
- ENUM_TO_STRING(RGBA8I),
- ENUM_TO_STRING(RGBA8),
- ENUM_TO_STRING(RGB16F),
- ENUM_TO_STRING(RG32F),
- ENUM_TO_STRING(RG16F),
- ENUM_TO_STRING(RG16UI),
- ENUM_TO_STRING(RG16I),
- ENUM_TO_STRING(RG16),
- ENUM_TO_STRING(RG8UI),
- ENUM_TO_STRING(RG8I),
- ENUM_TO_STRING(RG8),
- ENUM_TO_STRING(R8UI),
- ENUM_TO_STRING(R8I),
- ENUM_TO_STRING(R8),
- ENUM_TO_STRING(R32F),
- ENUM_TO_STRING(R32UI),
- ENUM_TO_STRING(R32I),
- ENUM_TO_STRING(R16F),
- ENUM_TO_STRING(R16UI),
- ENUM_TO_STRING(R16I),
- ENUM_TO_STRING(R16),
- ENUM_TO_STRING(R11F_G11F_B10F),
- ENUM_TO_STRING(SRGB8_ALPHA8),
- ENUM_TO_STRING(DEPTH24_STENCIL8),
- ENUM_TO_STRING(DEPTH32F_STENCIL8),
- ENUM_TO_STRING(DEPTH_COMPONENT32F),
- ENUM_TO_STRING(DEPTH_COMPONENT24),
- ENUM_TO_STRING(DEPTH_COMPONENT16),
+#define ENUM_TO_STRING(e) \
+ case GL_##e: { \
+ return STRINGIFY_ARG(e); \
+ }
+
+ switch (e) {
+ 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);
+ ENUM_TO_STRING(TEXTURE_1D_ARRAY);
+ ENUM_TO_STRING(TEXTURE_3D);
+ ENUM_TO_STRING(TEXTURE_2D_MULTISAMPLE);
+ ENUM_TO_STRING(RGBA32F);
+ ENUM_TO_STRING(RGBA16F);
+ ENUM_TO_STRING(RGBA16UI);
+ ENUM_TO_STRING(RGBA16I);
+ ENUM_TO_STRING(RGBA16);
+ ENUM_TO_STRING(RGBA8UI);
+ ENUM_TO_STRING(RGBA8I);
+ ENUM_TO_STRING(RGBA8);
+ ENUM_TO_STRING(RGB16F);
+ ENUM_TO_STRING(RG32F);
+ ENUM_TO_STRING(RG16F);
+ ENUM_TO_STRING(RG16UI);
+ ENUM_TO_STRING(RG16I);
+ ENUM_TO_STRING(RG16);
+ ENUM_TO_STRING(RG8UI);
+ ENUM_TO_STRING(RG8I);
+ ENUM_TO_STRING(RG8);
+ ENUM_TO_STRING(R8UI);
+ ENUM_TO_STRING(R8I);
+ ENUM_TO_STRING(R8);
+ ENUM_TO_STRING(R32F);
+ ENUM_TO_STRING(R32UI);
+ ENUM_TO_STRING(R32I);
+ ENUM_TO_STRING(R16F);
+ ENUM_TO_STRING(R16UI);
+ ENUM_TO_STRING(R16I);
+ ENUM_TO_STRING(R16);
+ ENUM_TO_STRING(R11F_G11F_B10F);
+ ENUM_TO_STRING(SRGB8_ALPHA8);
+ ENUM_TO_STRING(DEPTH24_STENCIL8);
+ ENUM_TO_STRING(DEPTH32F_STENCIL8);
+ ENUM_TO_STRING(DEPTH_COMPONENT32F);
+ ENUM_TO_STRING(DEPTH_COMPONENT24);
+ ENUM_TO_STRING(DEPTH_COMPONENT16);
+ default:
+ return "Unkown enum";
};
#undef ENUM_TO_STRING
-
- return enum_strings[e];
}
static int gpu_get_component_count(eGPUTextureFormat format)
@@ -423,6 +439,13 @@ static uint gpu_get_bytesize(eGPUTextureFormat data_type)
case GPU_R8:
case GPU_R8UI:
return 1;
+ case GPU_SRGB8_A8_DXT1:
+ case GPU_SRGB8_A8_DXT3:
+ case GPU_SRGB8_A8_DXT5:
+ case GPU_RGBA8_DXT1:
+ case GPU_RGBA8_DXT3:
+ case GPU_RGBA8_DXT5:
+ return 1; /* Incorrect but actual size is fractional. */
default:
BLI_assert(!"Texture format incorrect or unsupported\n");
return 0;
@@ -508,7 +531,18 @@ static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format)
case GPU_RGB16F:
return GL_RGB16F;
/* Special formats texture only */
- /* ** Add Format here */
+ case GPU_SRGB8_A8_DXT1:
+ return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
+ case GPU_SRGB8_A8_DXT3:
+ return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
+ case GPU_SRGB8_A8_DXT5:
+ return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+ case GPU_RGBA8_DXT1:
+ return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ case GPU_RGBA8_DXT3:
+ return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ case GPU_RGBA8_DXT5:
+ return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
/* Depth Formats */
case GPU_DEPTH_COMPONENT32F:
return GL_DEPTH_COMPONENT32F;
@@ -522,99 +556,6 @@ static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format)
}
}
-static eGPUTextureFormat gl_internalformat_to_gpu_format(const GLint glformat)
-{
- /* You can add any of the available type to this list
- * For available types see GPU_texture.h */
- switch (glformat) {
- /* Formats texture & renderbuffer */
- case GL_RGBA8UI:
- return GPU_RGBA8UI;
- case GL_RGBA8I:
- return GPU_RGBA8I;
- case GL_RGBA8:
- return GPU_RGBA8;
- case GL_RGBA32UI:
- return GPU_RGBA32UI;
- case GL_RGBA32I:
- return GPU_RGBA32I;
- case GL_RGBA32F:
- return GPU_RGBA32F;
- case GL_RGBA16UI:
- return GPU_RGBA16UI;
- case GL_RGBA16I:
- return GPU_RGBA16I;
- case GL_RGBA16F:
- return GPU_RGBA16F;
- case GL_RGBA16:
- return GPU_RGBA16;
- case GL_RG8UI:
- return GPU_RG8UI;
- case GL_RG8I:
- return GPU_RG8I;
- case GL_RG8:
- return GPU_RG8;
- case GL_RG32UI:
- return GPU_RG32UI;
- case GL_RG32I:
- return GPU_RG32I;
- case GL_RG32F:
- return GPU_RG32F;
- case GL_RG16UI:
- return GPU_RG16UI;
- case GL_RG16I:
- return GPU_RG16I;
- case GL_RG16F:
- return GPU_RGBA32F;
- case GL_RG16:
- return GPU_RG16;
- case GL_R8UI:
- return GPU_R8UI;
- case GL_R8I:
- return GPU_R8I;
- case GL_R8:
- return GPU_R8;
- case GL_R32UI:
- return GPU_R32UI;
- case GL_R32I:
- return GPU_R32I;
- case GL_R32F:
- return GPU_R32F;
- case GL_R16UI:
- return GPU_R16UI;
- case GL_R16I:
- return GPU_R16I;
- case GL_R16F:
- return GPU_R16F;
- case GL_R16:
- return GPU_R16;
- /* Special formats texture & renderbuffer */
- case GL_R11F_G11F_B10F:
- return GPU_R11F_G11F_B10F;
- case GL_DEPTH32F_STENCIL8:
- return GPU_DEPTH32F_STENCIL8;
- case GL_DEPTH24_STENCIL8:
- return GPU_DEPTH24_STENCIL8;
- case GL_SRGB8_ALPHA8:
- return GPU_SRGB8_A8;
- /* Texture only format */
- case GL_RGB16F:
- return GPU_RGB16F;
- /* Special formats texture only */
- /* ** Add Format here */
- /* Depth Formats */
- case GL_DEPTH_COMPONENT32F:
- return GPU_DEPTH_COMPONENT32F;
- case GL_DEPTH_COMPONENT24:
- return GPU_DEPTH_COMPONENT24;
- case GL_DEPTH_COMPONENT16:
- return GPU_DEPTH_COMPONENT16;
- default:
- BLI_assert(!"Internal format incorrect or unsupported\n");
- }
- return -1;
-}
-
static GLenum gpu_get_gl_datatype(eGPUDataFormat format)
{
switch (format) {
@@ -640,8 +581,8 @@ static float *GPU_texture_rescale_3d(
GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels)
{
const uint xf = w / tex->w, yf = h / tex->h, zf = d / tex->d;
- float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d,
- "GPUTexture Rescaled 3Dtex");
+ float *nfpixels = (float *)MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d,
+ "GPUTexture Rescaled 3Dtex");
if (nfpixels) {
GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
@@ -828,7 +769,7 @@ GPUTexture *GPU_texture_create_nD(int w,
tex_format = GPU_DEPTH32F_STENCIL8;
}
- GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
tex->w = w;
tex->h = h;
tex->d = d;
@@ -837,7 +778,7 @@ GPUTexture *GPU_texture_create_nD(int w,
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
tex->mipmaps = 0;
- tex->format_flag = 0;
+ tex->format_flag = static_cast<eGPUTextureFormatFlag>(0);
tex->number = -1;
if (n == 2) {
@@ -921,7 +862,7 @@ GPUTexture *GPU_texture_create_nD(int w,
data_type,
tex->components,
can_rescale,
- pixels,
+ (float *)pixels,
&rescaled_pixels);
if (G.debug & G_DEBUG_GPU || !valid) {
@@ -952,7 +893,7 @@ GPUTexture *GPU_texture_create_nD(int w,
gpu_texture_memory_footprint_add(tex);
/* Upload Texture */
- const float *pix = (rescaled_pixels) ? rescaled_pixels : pixels;
+ const void *pix = (rescaled_pixels) ? rescaled_pixels : pixels;
if (tex->target == GL_TEXTURE_2D || tex->target == GL_TEXTURE_2D_MULTISAMPLE ||
tex->target == GL_TEXTURE_1D_ARRAY) {
@@ -1002,7 +943,7 @@ GPUTexture *GPU_texture_cube_create(int w,
eGPUDataFormat gpu_data_format,
char err_out[256])
{
- GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
tex->w = w;
tex->h = w;
tex->d = d;
@@ -1126,11 +1067,11 @@ GPUTexture *GPU_texture_cube_create(int w,
/* Special buffer textures. tex_format must be compatible with the buffer content. */
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer)
{
- GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
tex->refcount = 1;
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
- tex->format_flag = 0;
+ tex->format_flag = static_cast<eGPUTextureFormatFlag>(0);
tex->target_base = tex->target = GL_TEXTURE_BUFFER;
tex->mipmaps = 0;
tex->number = -1;
@@ -1176,44 +1117,87 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint
return tex;
}
-GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
+static GLenum convert_target_to_gl(int dimension, bool is_array)
{
- GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->bindcode = bindcode;
+ switch (dimension) {
+ case 1:
+ return is_array ? GL_TEXTURE_1D : GL_TEXTURE_1D_ARRAY;
+ case 2:
+ return is_array ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY;
+ case 3:
+ return GL_TEXTURE_3D;
+ default:
+ BLI_assert(0);
+ return GL_TEXTURE_2D;
+ }
+}
+
+/* Create an error texture that will bind an invalid texture (pink) at draw time. */
+GPUTexture *GPU_texture_create_error(int dimension, bool is_array)
+{
+ GLenum textarget = convert_target_to_gl(dimension, is_array);
+
+ GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
+ tex->bindcode = 0;
tex->refcount = 1;
tex->target = textarget;
tex->target_base = textarget;
tex->samples = 0;
- tex->sampler_state = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO;
- if (GPU_get_mipmap()) {
- tex->sampler_state |= (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER);
- }
+ tex->sampler_state = GPU_SAMPLER_DEFAULT;
tex->number = -1;
- if (!glIsTexture(tex->bindcode)) {
- GPU_print_error_debug("Blender Texture Not Loaded");
+ GPU_print_error_debug("Blender Texture Not Loaded");
+ return tex;
+}
+
+/* DDS texture loading. Return NULL if support is not available. */
+GPUTexture *GPU_texture_create_compressed(
+ int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
+{
+ if (!GLEW_EXT_texture_compression_s3tc) {
+ return NULL;
}
- else {
- GLint w, h, gl_format;
- GLenum gettarget;
- gettarget = (textarget == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : textarget;
-
- glBindTexture(textarget, tex->bindcode);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_INTERNAL_FORMAT, &gl_format);
- tex->w = w;
- tex->h = h;
- tex->format = gl_internalformat_to_gpu_format(gl_format);
- tex->components = gpu_get_component_count(tex->format);
- glBindTexture(textarget, 0);
-
- /* Depending on how this bindcode was obtained, the memory used here could
- * already have been computed.
- * But that is not the case currently. */
- gpu_texture_memory_footprint_add(tex);
+
+ GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
+ tex->w = w;
+ tex->h = h;
+ tex->refcount = 1;
+ tex->target = tex->target_base = GL_TEXTURE_2D;
+ tex->format_flag = static_cast<eGPUTextureFormatFlag>(0);
+ tex->components = gpu_get_component_count(tex_format);
+ tex->mipmaps = miplen - 1;
+ tex->sampler_state = GPU_SAMPLER_DEFAULT;
+ tex->number = -1;
+
+ GLenum internalformat = gpu_format_to_gl_internalformat(tex_format);
+
+ glGenTextures(1, &tex->bindcode);
+ glBindTexture(tex->target, tex->bindcode);
+
+ /* Reset to opengl Defaults. (Untested, might not be needed) */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ int blocksize = (ELEM(tex_format, GPU_RGBA8_DXT1, GPU_SRGB8_A8_DXT1)) ? 8 : 16;
+
+ size_t ofs = 0;
+ for (int mip = 0; mip < miplen && (w || h); mip++, w >>= 1, h >>= 1) {
+ w = max_ii(1, w);
+ h = max_ii(1, h);
+ size_t size = ((w + 3) / 4) * ((h + 3) / 4) * blocksize;
+
+ glCompressedTexImage2D(tex->target, mip, internalformat, w, h, 0, size, (uchar *)data + ofs);
+
+ ofs += size;
}
+ /* Restore Blender default. */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexParameteri(tex->target, GL_TEXTURE_MAX_LEVEL, tex->mipmaps);
+ glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glBindTexture(tex->target, 0);
+
return tex;
}
@@ -1468,7 +1452,8 @@ void GPU_texture_update_sub(GPUTexture *tex,
GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
- glBindTexture(tex->target, tex->bindcode);
+ WARN_NOT_BOUND(tex);
+
switch (tex->target) {
case GL_TEXTURE_1D:
glTexSubImage1D(tex->target, 0, offset_x, width, data_format, data_type, pixels);
@@ -1496,8 +1481,6 @@ void GPU_texture_update_sub(GPUTexture *tex,
default:
BLI_assert(!"tex->target mode not supported");
}
-
- glBindTexture(tex->target, 0);
}
void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int miplvl)
@@ -1791,16 +1774,6 @@ void GPU_texture_unbind_all(void)
glActiveTexture(GL_TEXTURE0);
}
-#define WARN_NOT_BOUND(_tex) \
- { \
- if (_tex->number == -1) { \
- fprintf(stderr, "Warning : Trying to set parameter on a texture not bound.\n"); \
- BLI_assert(0); \
- return; \
- } \
- } \
- ((void)0)
-
void GPU_texture_generate_mipmap(GPUTexture *tex)
{
WARN_NOT_BOUND(tex);
@@ -1944,6 +1917,14 @@ void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter)
SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER);
}
+void GPU_texture_anisotropic_filter(GPUTexture *tex, bool use_aniso)
+{
+ /* Stencil and integer format does not support filtering. */
+ BLI_assert(!(use_aniso) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
+
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_aniso, GPU_SAMPLER_ANISO);
+}
+
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp)
{
SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT);
@@ -2158,7 +2139,7 @@ void GPU_samplers_init(void)
{
glGenSamplers(GPU_SAMPLER_MAX, GG.samplers);
for (int i = 0; i < GPU_SAMPLER_MAX; i++) {
- eGPUSamplerState state = i;
+ eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? GL_REPEAT : clamp_type;
GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type;
@@ -2168,8 +2149,9 @@ void GPU_samplers_init(void)
((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
+ /* TODO(fclem) Anisotropic level should be a render engine parameter. */
float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ?
- GPU_get_anisotropic() :
+ U.anisotropic_filter :
1.0f;
glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s);
diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.cc
index 130e8fe7da1..b2e31894f9d 100644
--- a/source/blender/gpu/intern/gpu_uniformbuffer.c
+++ b/source/blender/gpu/intern/gpu_uniformbuffer.cc
@@ -25,6 +25,7 @@
#include <string.h>
#include "BLI_blenlib.h"
+#include "BLI_math_base.h"
#include "gpu_context_private.h"
#include "gpu_node_graph.h"
@@ -34,217 +35,63 @@
#include "GPU_material.h"
#include "GPU_uniformbuffer.h"
-typedef enum eGPUUniformBufferFlag {
- GPU_UBO_FLAG_INITIALIZED = (1 << 0),
- GPU_UBO_FLAG_DIRTY = (1 << 1),
-} eGPUUniformBufferFlag;
-
-typedef enum eGPUUniformBufferType {
- GPU_UBO_STATIC = 0,
- GPU_UBO_DYNAMIC = 1,
-} eGPUUniformBufferType;
-
-struct GPUUniformBuffer {
- int size; /* in bytes */
- GLuint bindcode; /* opengl identifier for UBO */
- int bindpoint; /* current binding point */
- eGPUUniformBufferType type;
-};
-
-#define GPUUniformBufferStatic GPUUniformBuffer
-
-typedef struct GPUUniformBufferDynamic {
- GPUUniformBuffer buffer;
- void *data; /* Continuous memory block to copy to GPU. */
- char flag;
-} GPUUniformBufferDynamic;
-
-/* Prototypes */
-static eGPUType get_padded_gpu_type(struct LinkData *link);
-static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs);
-
-/* Only support up to this type, if you want to extend it, make sure the
- * padding logic is correct for the new types. */
-#define MAX_UBO_GPU_TYPE GPU_MAT4
-
-static void gpu_uniformbuffer_initialize(GPUUniformBuffer *ubo, const void *data)
-{
- glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
- glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
-}
+typedef struct GPUUniformBuffer {
+ /** Data size in bytes. */
+ int size;
+ /** GL handle for UBO. */
+ GLuint bindcode;
+ /** Current binding point. */
+ int bindpoint;
+ /** Continuous memory block to copy to GPU. Is own by the GPUUniformBuffer. */
+ void *data;
+} GPUUniformBuffer;
GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256])
{
/* Make sure that UBO is padded to size of vec4 */
BLI_assert((size % 16) == 0);
- GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBufferStatic), "GPUUniformBufferStatic");
- ubo->size = size;
- ubo->bindpoint = -1;
-
- /* Generate Buffer object */
- ubo->bindcode = GPU_buf_alloc();
-
- if (!ubo->bindcode) {
- if (err_out) {
- BLI_strncpy(err_out, "GPUUniformBuffer: UBO create failed", 256);
- }
- GPU_uniformbuffer_free(ubo);
- return NULL;
- }
-
- if (ubo->size > GPU_max_ubo_size()) {
+ if (size > GPU_max_ubo_size()) {
if (err_out) {
BLI_strncpy(err_out, "GPUUniformBuffer: UBO too big", 256);
}
- GPU_uniformbuffer_free(ubo);
- return NULL;
- }
-
- gpu_uniformbuffer_initialize(ubo, data);
- return ubo;
-}
-
-/**
- * Create dynamic UBO from parameters
- * Return NULL if failed to create or if \param inputs: is empty.
- *
- * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
- */
-GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_out[256])
-{
- /* There is no point on creating an UBO if there is no arguments. */
- if (BLI_listbase_is_empty(inputs)) {
return NULL;
}
- GPUUniformBufferDynamic *ubo = MEM_callocN(sizeof(GPUUniformBufferDynamic),
- "GPUUniformBufferDynamic");
- ubo->buffer.type = GPU_UBO_DYNAMIC;
- ubo->buffer.bindpoint = -1;
- ubo->flag = GPU_UBO_FLAG_DIRTY;
-
- /* Generate Buffer object. */
- ubo->buffer.bindcode = GPU_buf_alloc();
-
- if (!ubo->buffer.bindcode) {
- if (err_out) {
- BLI_strncpy(err_out, "GPUUniformBuffer: UBO create failed", 256);
- }
- GPU_uniformbuffer_free(&ubo->buffer);
- return NULL;
- }
-
- if (ubo->buffer.size > GPU_max_ubo_size()) {
- if (err_out) {
- BLI_strncpy(err_out, "GPUUniformBuffer: UBO too big", 256);
- }
- GPU_uniformbuffer_free(&ubo->buffer);
- return NULL;
- }
-
- /* Make sure we comply to the ubo alignment requirements. */
- gpu_uniformbuffer_inputs_sort(inputs);
-
- LISTBASE_FOREACH (LinkData *, link, inputs) {
- const eGPUType gputype = get_padded_gpu_type(link);
- ubo->buffer.size += gputype * sizeof(float);
- }
-
- /* Round up to size of vec4 */
- ubo->buffer.size = ((ubo->buffer.size + 15) / 16) * 16;
-
- /* Allocate the data. */
- ubo->data = MEM_mallocN(ubo->buffer.size, __func__);
+ GPUUniformBuffer *ubo = (GPUUniformBuffer *)MEM_mallocN(sizeof(GPUUniformBuffer), __func__);
+ ubo->size = size;
+ ubo->data = NULL;
+ ubo->bindcode = 0;
+ ubo->bindpoint = -1;
- /* Now that we know the total ubo size we can start populating it. */
- float *offset = ubo->data;
- LISTBASE_FOREACH (LinkData *, link, inputs) {
- GPUInput *input = link->data;
- memcpy(offset, input->vec, input->type * sizeof(float));
- offset += get_padded_gpu_type(link);
+ /* Direct init. */
+ if (data != NULL) {
+ GPU_uniformbuffer_update(ubo, data);
}
- /* Note since we may create the UBOs in the CPU in a different thread than the main drawing one,
- * we don't create the UBO in the GPU here. This will happen when we first bind the UBO.
- */
-
- return &ubo->buffer;
-}
-
-/**
- * Free the data
- */
-static void gpu_uniformbuffer_dynamic_free(GPUUniformBuffer *ubo_)
-{
- BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
- GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
-
- ubo->buffer.size = 0;
- if (ubo->data) {
- MEM_freeN(ubo->data);
- }
+ return ubo;
}
void GPU_uniformbuffer_free(GPUUniformBuffer *ubo)
{
- if (ubo->type == GPU_UBO_DYNAMIC) {
- gpu_uniformbuffer_dynamic_free(ubo);
- }
-
+ MEM_SAFE_FREE(ubo->data);
GPU_buf_free(ubo->bindcode);
MEM_freeN(ubo);
}
-static void gpu_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
-{
- glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
- glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
-}
-
-void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
-{
- BLI_assert(ubo->type == GPU_UBO_STATIC);
- gpu_uniformbuffer_update(ubo, data);
-}
-
-/**
- * We need to recalculate the internal data, and re-generate it
- * from its populated items.
- */
-void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_)
-{
- BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
- GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
-
- if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) {
- gpu_uniformbuffer_update(ubo_, ubo->data);
- }
- else {
- ubo->flag |= GPU_UBO_FLAG_INITIALIZED;
- gpu_uniformbuffer_initialize(ubo_, ubo->data);
- }
-
- ubo->flag &= ~GPU_UBO_FLAG_DIRTY;
-}
-
/**
* We need to pad some data types (vec3) on the C side
* To match the GPU expected memory block alignment.
*/
static eGPUType get_padded_gpu_type(LinkData *link)
{
- GPUInput *input = link->data;
+ GPUInput *input = (GPUInput *)link->data;
eGPUType gputype = input->type;
-
/* Unless the vec3 is followed by a float we need to treat it as a vec4. */
if (gputype == GPU_VEC3 && (link->next != NULL) &&
(((GPUInput *)link->next->data)->type != GPU_FLOAT)) {
gputype = GPU_VEC4;
}
-
return gputype;
}
@@ -254,8 +101,9 @@ static eGPUType get_padded_gpu_type(LinkData *link)
*/
static int inputs_cmp(const void *a, const void *b)
{
- const LinkData *link_a = a, *link_b = b;
- const GPUInput *input_a = link_a->data, *input_b = link_b->data;
+ const LinkData *link_a = (const LinkData *)a, *link_b = (const LinkData *)b;
+ const GPUInput *input_a = (const GPUInput *)link_a->data;
+ const GPUInput *input_b = (const GPUInput *)link_b->data;
return input_a->type < input_b->type ? 1 : 0;
}
@@ -265,15 +113,19 @@ static int inputs_cmp(const void *a, const void *b)
*/
static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
{
+/* Only support up to this type, if you want to extend it, make sure the
+ * padding logic is correct for the new types. */
+#define MAX_UBO_GPU_TYPE GPU_MAT4
+
/* Order them as mat4, vec4, vec3, vec2, float. */
BLI_listbase_sort(inputs, inputs_cmp);
/* Creates a lookup table for the different types; */
LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL};
- eGPUType cur_type = MAX_UBO_GPU_TYPE + 1;
+ eGPUType cur_type = static_cast<eGPUType>(MAX_UBO_GPU_TYPE + 1);
LISTBASE_FOREACH (LinkData *, link, inputs) {
- GPUInput *input = link->data;
+ GPUInput *input = (GPUInput *)link->data;
if (input->type == GPU_MAT3) {
/* Alignment for mat3 is not handled currently, so not supported */
@@ -319,6 +171,74 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
link = link_next;
}
+#undef MAX_UBO_GPU_TYPE
+}
+
+/**
+ * Create dynamic UBO from parameters
+ * Return NULL if failed to create or if \param inputs: is empty.
+ *
+ * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
+ */
+GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_out[256])
+{
+ /* There is no point on creating an UBO if there is no arguments. */
+ if (BLI_listbase_is_empty(inputs)) {
+ return NULL;
+ }
+ /* Make sure we comply to the ubo alignment requirements. */
+ gpu_uniformbuffer_inputs_sort(inputs);
+
+ size_t buffer_size = 0;
+
+ LISTBASE_FOREACH (LinkData *, link, inputs) {
+ const eGPUType gputype = get_padded_gpu_type(link);
+ buffer_size += gputype * sizeof(float);
+ }
+ /* Round up to size of vec4. (Opengl Requirement) */
+ size_t alignment = sizeof(float[4]);
+ buffer_size = divide_ceil_u(buffer_size, alignment) * alignment;
+ void *data = MEM_mallocN(buffer_size, __func__);
+
+ /* Now that we know the total ubo size we can start populating it. */
+ float *offset = (float *)data;
+ LISTBASE_FOREACH (LinkData *, link, inputs) {
+ GPUInput *input = (GPUInput *)link->data;
+ memcpy(offset, input->vec, input->type * sizeof(float));
+ offset += get_padded_gpu_type(link);
+ }
+
+ /* Pass data as NULL for late init. */
+ GPUUniformBuffer *ubo = GPU_uniformbuffer_create(buffer_size, NULL, err_out);
+ /* Data will be update just before binding. */
+ ubo->data = data;
+ return ubo;
+}
+
+static void gpu_uniformbuffer_init(GPUUniformBuffer *ubo)
+{
+ BLI_assert(ubo->bindcode == 0);
+ ubo->bindcode = GPU_buf_alloc();
+
+ if (ubo->bindcode == 0) {
+ fprintf(stderr, "GPUUniformBuffer: UBO create failed");
+ BLI_assert(0);
+ return;
+ }
+
+ glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
+ glBufferData(GL_UNIFORM_BUFFER, ubo->size, NULL, GL_DYNAMIC_DRAW);
+}
+
+void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
+{
+ if (ubo->bindcode == 0) {
+ gpu_uniformbuffer_init(ubo);
+ }
+
+ glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number)
@@ -328,28 +248,30 @@ void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number)
return;
}
- if (ubo->type == GPU_UBO_DYNAMIC) {
- GPUUniformBufferDynamic *ubo_dynamic = (GPUUniformBufferDynamic *)ubo;
- if (ubo_dynamic->flag & GPU_UBO_FLAG_DIRTY) {
- GPU_uniformbuffer_dynamic_update(ubo);
- }
+ if (ubo->bindcode == 0) {
+ gpu_uniformbuffer_init(ubo);
}
- if (ubo->bindcode != 0) {
- glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode);
+ if (ubo->data != NULL) {
+ GPU_uniformbuffer_update(ubo, ubo->data);
+ MEM_SAFE_FREE(ubo->data);
}
+ glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode);
ubo->bindpoint = number;
}
void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo)
{
- ubo->bindpoint = -1;
+#ifndef NDEBUG
+ glBindBufferBase(GL_UNIFORM_BUFFER, ubo->bindpoint, 0);
+#endif
+ ubo->bindpoint = 0;
}
-int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo)
+void GPU_uniformbuffer_unbind_all(void)
{
- return ubo->bindpoint;
-}
-
-#undef MAX_UBO_GPU_TYPE
+ for (int i = 0; i < GPU_max_ubo_binds(); i++) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, i, 0);
+ }
+} \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 3b4d469542c..eda6d1c7300 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.c
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -39,17 +39,22 @@ static uint vbo_memory_usage;
static GLenum convert_usage_type_to_gl(GPUUsageType type)
{
- static const GLenum table[] = {
- [GPU_USAGE_STREAM] = GL_STREAM_DRAW,
- [GPU_USAGE_STATIC] = GL_STATIC_DRAW,
- [GPU_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW,
- };
- return table[type];
+ switch (type) {
+ case GPU_USAGE_STREAM:
+ return GL_STREAM_DRAW;
+ case GPU_USAGE_DYNAMIC:
+ return GL_DYNAMIC_DRAW;
+ case GPU_USAGE_STATIC:
+ return GL_STATIC_DRAW;
+ default:
+ BLI_assert(0);
+ return GL_STATIC_DRAW;
+ }
}
GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage)
{
- GPUVertBuf *verts = MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf");
+ GPUVertBuf *verts = (GPUVertBuf *)MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf");
GPU_vertbuf_init(verts, usage);
return verts;
}
@@ -109,7 +114,7 @@ GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts)
}
if (verts->data) {
- verts_dst->data = MEM_dupallocN(verts->data);
+ verts_dst->data = (uchar *)MEM_dupallocN(verts->data);
}
return verts_dst;
}
@@ -161,7 +166,7 @@ void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
#endif
verts->dirty = true;
verts->vertex_len = verts->vertex_alloc = v_len;
- verts->data = MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), "GPUVertBuf data");
+ verts->data = (uchar *)MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), __func__);
}
/* resize buffer keeping existing data */
@@ -178,7 +183,7 @@ void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
#endif
verts->dirty = true;
verts->vertex_len = verts->vertex_alloc = v_len;
- verts->data = MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts));
+ verts->data = (uchar *)MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts));
}
/* Set vertex count but does not change allocation.
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.cc
index 585a22277b2..a59a6a468ce 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -63,21 +63,29 @@ void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src)
memcpy(dest, src, sizeof(GPUVertFormat));
}
-static GLenum convert_comp_type_to_gl(GPUVertCompType type)
+GLenum convert_comp_type_to_gl(GPUVertCompType type)
{
- static const GLenum table[] = {
- [GPU_COMP_I8] = GL_BYTE,
- [GPU_COMP_U8] = GL_UNSIGNED_BYTE,
- [GPU_COMP_I16] = GL_SHORT,
- [GPU_COMP_U16] = GL_UNSIGNED_SHORT,
- [GPU_COMP_I32] = GL_INT,
- [GPU_COMP_U32] = GL_UNSIGNED_INT,
-
- [GPU_COMP_F32] = GL_FLOAT,
-
- [GPU_COMP_I10] = GL_INT_2_10_10_10_REV,
- };
- return table[type];
+ switch (type) {
+ case GPU_COMP_I8:
+ return GL_BYTE;
+ case GPU_COMP_U8:
+ return GL_UNSIGNED_BYTE;
+ case GPU_COMP_I16:
+ return GL_SHORT;
+ case GPU_COMP_U16:
+ return GL_UNSIGNED_SHORT;
+ case GPU_COMP_I32:
+ return GL_INT;
+ case GPU_COMP_U32:
+ return GL_UNSIGNED_INT;
+ case GPU_COMP_F32:
+ return GL_FLOAT;
+ case GPU_COMP_I10:
+ return GL_INT_2_10_10_10_REV;
+ default:
+ BLI_assert(0);
+ return GL_FLOAT;
+ }
}
static uint comp_sz(GPUVertCompType type)
@@ -94,7 +102,7 @@ static uint attr_sz(const GPUVertAttr *a)
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
}
- return a->comp_len * comp_sz(a->comp_type);
+ return a->comp_len * comp_sz(static_cast<GPUVertCompType>(a->comp_type));
}
static uint attr_align(const GPUVertAttr *a)
@@ -102,7 +110,7 @@ static uint attr_align(const GPUVertAttr *a)
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
}
- uint c = comp_sz(a->comp_type);
+ uint c = comp_sz(static_cast<GPUVertCompType>(a->comp_type));
if (a->comp_len == 3 && c <= 2) {
return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */
}
@@ -185,7 +193,6 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format,
attr->names[attr->name_len++] = copy_attr_name(format, name);
attr->comp_type = comp_type;
- attr->gl_comp_type = convert_comp_type_to_gl(comp_type);
attr->comp_len = (comp_type == GPU_COMP_I10) ?
4 :
comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */
@@ -279,7 +286,7 @@ void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr_id, const char *
/* Encode 8 original bytes into 11 safe bytes. */
static void safe_bytes(char out[11], const char data[8])
{
- char safe_chars[63] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+ char safe_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
uint64_t in = *(uint64_t *)data;
for (int i = 0; i < 11; i++) {
@@ -368,14 +375,6 @@ static void show_pack(uint a_idx, uint sz, uint pad)
void VertexFormat_pack(GPUVertFormat *format)
{
- /* For now, attributes are packed in the order they were added,
- * making sure each attribute is naturally aligned (add padding where necessary)
- * Later we can implement more efficient packing w/ reordering
- * (keep attribute ID order, adjust their offsets to reorder in buffer). */
-
- /* TODO: realloc just enough to hold the final combo string. And just enough to
- * hold used attributes, not all 16. */
-
GPUVertAttr *a0 = &format->attrs[0];
a0->offset = 0;
uint offset = a0->sz;
@@ -512,7 +511,6 @@ void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader)
attr->sz = attr->comp_len * 4;
attr->fetch_mode = fetch_mode;
attr->comp_type = comp_type;
- attr->gl_comp_type = convert_comp_type_to_gl(comp_type);
attr += 1;
}
}
diff --git a/source/blender/gpu/intern/gpu_vertex_format_private.h b/source/blender/gpu/intern/gpu_vertex_format_private.h
index a850d17a1dd..7b560a35bd0 100644
--- a/source/blender/gpu/intern/gpu_vertex_format_private.h
+++ b/source/blender/gpu/intern/gpu_vertex_format_private.h
@@ -26,8 +26,17 @@
#ifndef __GPU_VERTEX_FORMAT_PRIVATE_H__
#define __GPU_VERTEX_FORMAT_PRIVATE_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void VertexFormat_pack(GPUVertFormat *format);
uint padding(uint offset, uint alignment);
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len);
+GLenum convert_comp_type_to_gl(GPUVertCompType type);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* __GPU_VERTEX_FORMAT_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 4d31366f53f..ed5297f0a4a 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -38,7 +38,6 @@
#include "DNA_vec_types.h"
#include "GPU_framebuffer.h"
-#include "GPU_glew.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_texture.h"
diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
new file mode 100644
index 00000000000..f7bf3d33361
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
@@ -0,0 +1,87 @@
+
+vec3 calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2)
+{
+ vec3 edge21 = pos2 - pos1;
+ vec3 edge10 = pos1 - pos0;
+ vec3 edge02 = pos0 - pos2;
+ vec3 d21 = normalize(edge21);
+ vec3 d10 = normalize(edge10);
+ vec3 d02 = normalize(edge02);
+
+ vec3 dists;
+ float d = dot(d21, edge02);
+ dists.x = sqrt(dot(edge02, edge02) - d * d);
+ d = dot(d02, edge10);
+ dists.y = sqrt(dot(edge10, edge10) - d * d);
+ d = dot(d10, edge21);
+ dists.z = sqrt(dot(edge21, edge21) - d * d);
+ return dists;
+}
+
+vec2 calc_barycentric_co(int vertid)
+{
+ vec2 bary;
+ bary.x = float((vertid % 3) == 0);
+ bary.y = float((vertid % 3) == 1);
+ return bary;
+}
+
+#ifdef HAIR_SHADER
+
+/* Hairs uv and col attributes are passed by bufferTextures. */
+# define DEFINE_ATTR(type, attr) uniform samplerBuffer attr
+# define GET_ATTR(type, attr) hair_get_customdata_##type(attr)
+
+# define barycentric_get() hair_get_barycentric()
+# define barycentric_resolve(bary) hair_resolve_barycentric(bary)
+
+vec3 orco_get(vec3 local_pos, mat4 modelmatinv, vec4 orco_madd[2], const samplerBuffer orco_samp)
+{
+ /* TODO: fix ORCO with modifiers. */
+ vec3 orco = (modelmatinv * vec4(local_pos, 1.0)).xyz;
+ return orco_madd[0].xyz + orco * orco_madd[1].xyz;
+}
+
+vec4 tangent_get(const samplerBuffer attr, mat3 normalmat)
+{
+ /* Unsupported */
+ return vec4(0.0);
+}
+
+#else /* MESH_SHADER */
+
+# define DEFINE_ATTR(type, attr) in type attr
+# define GET_ATTR(type, attr) attr
+
+/* Calculated in geom shader later with calc_barycentric_co. */
+# define barycentric_get() vec2(0)
+# define barycentric_resolve(bary) bary
+
+vec3 orco_get(vec3 local_pos, mat4 modelmatinv, vec4 orco_madd[2], vec4 orco)
+{
+ /* If the object does not have any deformation, the orco layer calculation is done on the fly
+ * using the orco_madd factors.
+ * We know when there is no orco layer when orco.w is 1.0 because it uses the generic vertex
+ * attrib (which is [0,0,0,1]). */
+ if (orco.w == 0.0) {
+ return orco.xyz * 0.5 + 0.5;
+ }
+ else {
+ return orco_madd[0].xyz + local_pos * orco_madd[1].xyz;
+ }
+}
+
+vec4 tangent_get(vec4 attr, mat3 normalmat)
+{
+ vec4 tangent;
+ tangent.xyz = normalmat * attr.xyz;
+ tangent.w = attr.w;
+ float len_sqr = dot(tangent.xyz, tangent.xyz);
+ /* Normalize only if vector is not null. */
+ if (len_sqr > 0.0) {
+ tangent.xyz *= inversesqrt(len_sqr);
+ }
+ return tangent;
+}
+
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
index d6d6fbab971..eea8d19efce 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -3,7 +3,7 @@ void node_ambient_occlusion(
vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
{
vec3 bent_normal;
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
result_color = result_ao * color;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 3b23ac976ae..6330daa4391 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -1,3 +1,15 @@
+
+float wang_hash_noise(uint s)
+{
+ s = (s ^ 61u) ^ (s >> 16u);
+ s *= 9u;
+ s = s ^ (s >> 4u);
+ s *= 0x27d4eb2du;
+ s = s ^ (s >> 15u);
+
+ return fract(float(s) / 4294967296.0);
+}
+
void node_hair_info(out float is_strand,
out float intercept,
out float thickness,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
index f9691beee6f..d33465fa846 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
@@ -6,7 +6,7 @@ void world_normals_get(out vec3 N)
vec3 B = normalize(cross(worldNormal, hairTangent));
float cos_theta;
if (hairThicknessRes == 1) {
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
/* Random cosine normal distribution on the hair surface. */
cos_theta = rand.x * 2.0 - 1.0;
}
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index cad0be659ec..cf637a06405 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../blenkernel
../blenlib
../blenloader
+ ../gpu
../makesdna
../makesrna
../../../intern/guardedalloc
@@ -63,6 +64,7 @@ set(SRC
intern/thumbs_blend.c
intern/thumbs_font.c
intern/util.c
+ intern/util_gpu.c
intern/writeimage.c
IMB_colormanagement.h
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 478297e61b2..ed56268e436 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -90,6 +90,12 @@ struct Stereo3dFormat;
/**
*
+ * \attention defined in GPU_texture.h
+ */
+struct GPUTexture;
+
+/**
+ *
* \attention Defined in allocimbuf.c
*/
void IMB_init(void);
@@ -729,6 +735,25 @@ const char *IMB_ffmpeg_last_error(void);
/**
*
+ * \attention defined in util_gpu.c
+ */
+struct GPUTexture *IMB_create_gpu_texture(struct ImBuf *ibuf,
+ bool use_high_bitdepth,
+ bool use_premult);
+struct GPUTexture *IMB_touch_gpu_texture(
+ struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth);
+void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
+ struct ImBuf *ibuf,
+ int x,
+ int y,
+ int z,
+ int w,
+ int h,
+ bool use_high_bitdepth,
+ bool use_premult);
+
+/**
+ *
* \attention defined in stereoimbuf.c
*/
void IMB_stereo3d_write_dimensions(const char mode,
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
new file mode 100644
index 00000000000..5d0c6fe2e52
--- /dev/null
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -0,0 +1,261 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ * util.c
+ */
+
+/** \file
+ * \ingroup imbuf
+ */
+
+#include "imbuf.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "MEM_guardedalloc.h"
+
+#include "BKE_global.h"
+
+#include "GPU_extensions.h"
+#include "GPU_texture.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+/* gpu ibuf utils */
+
+static void imb_gpu_get_format(const ImBuf *ibuf,
+ bool high_bitdepth,
+ eGPUDataFormat *r_data_format,
+ eGPUTextureFormat *r_texture_format)
+{
+ const bool float_rect = (ibuf->rect_float != NULL);
+ const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
+ !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
+ high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
+
+ *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
+
+ if (float_rect) {
+ *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+ }
+ else {
+ *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
+ }
+}
+
+/* Return false if no suitable format was found. */
+#ifdef WITH_DDS
+static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format)
+{
+ /* For DDS we only support data, scene linear and sRGB. Converting to
+ * different colorspace would break the compression. */
+ const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
+ !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
+
+ if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
+ *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1;
+ }
+ else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
+ *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3;
+ }
+ else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
+ *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5;
+ }
+ else {
+ return false;
+ }
+ return true;
+}
+#endif
+
+/**
+ * Apply colormanagement and scale buffer if needed.
+ * *r_freedata is set to true if the returned buffer need to be manually freed.
+ **/
+static void *imb_gpu_get_data(const ImBuf *ibuf,
+ const bool do_rescale,
+ const int rescale_size[2],
+ const bool compress_as_srgb,
+ const bool store_premultiplied,
+ bool *r_freedata)
+{
+ const bool is_float_rect = (ibuf->rect_float != NULL);
+ void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect;
+
+ if (is_float_rect) {
+ /* Float image is already in scene linear colorspace or non-color data by
+ * convention, no colorspace conversion needed. But we do require 4 channels
+ * currently. */
+ if (ibuf->channels != 4 || !store_premultiplied) {
+ data_rect = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
+ *r_freedata = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ IMB_colormanagement_imbuf_to_float_texture(
+ (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
+ }
+ }
+ else {
+ /* Byte image is in original colorspace from the file. If the file is sRGB
+ * scene linear, or non-color data no conversion is needed. Otherwise we
+ * compress as scene linear + sRGB transfer function to avoid precision loss
+ * in common cases.
+ *
+ * We must also convert to premultiplied for correct texture interpolation
+ * and consistency with float images. */
+ if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ data_rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
+ *r_freedata = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ /* Texture storage of images is defined by the alpha mode of the image. The
+ * downside of this is that there can be artifacts near alpha edges. However,
+ * this allows us to use sRGB texture formats and preserves color values in
+ * zero alpha areas, and appears generally closer to what game engines that we
+ * want to be compatible with do. */
+ IMB_colormanagement_imbuf_to_byte_texture(
+ (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
+ }
+ }
+
+ if (do_rescale) {
+ uint *rect = (is_float_rect) ? NULL : (uint *)data_rect;
+ float *rect_float = (is_float_rect) ? (float *)data_rect : NULL;
+
+ ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4);
+ IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size));
+
+ data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect;
+ *r_freedata = true;
+ /* Steal the rescaled buffer to avoid double free. */
+ scale_ibuf->rect_float = NULL;
+ scale_ibuf->rect = NULL;
+ IMB_freeImBuf(scale_ibuf);
+ }
+ return data_rect;
+}
+
+/* The ibuf is only here to detect the storage type. The produced texture will have undefined
+ * content. It will need to be populated by using IMB_update_gpu_texture_sub(). */
+GPUTexture *IMB_touch_gpu_texture(ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
+{
+ eGPUDataFormat data_format;
+ eGPUTextureFormat tex_format;
+ imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
+
+ GPUTexture *tex = GPU_texture_create_nD(
+ w, h, layers, 2, NULL, tex_format, data_format, 0, false, NULL);
+
+ GPU_texture_anisotropic_filter(tex, true);
+ return tex;
+}
+
+/* Will update a GPUTexture using the content of the ImBuf. Only one layer will be updated.
+ * Will resize the ibuf if needed.
+ * z is the layer to update. Unused if the texture is 2D. */
+void IMB_update_gpu_texture_sub(GPUTexture *tex,
+ ImBuf *ibuf,
+ int x,
+ int y,
+ int z,
+ int w,
+ int h,
+ bool use_high_bitdepth,
+ bool use_premult)
+{
+ const bool do_rescale = (ibuf->x != w || ibuf->y != h);
+ int size[2] = {w, h};
+
+ eGPUDataFormat data_format;
+ eGPUTextureFormat tex_format;
+ imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
+
+ const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
+ bool freebuf = false;
+
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+
+ /* Update Texture. */
+ GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
+
+ if (freebuf) {
+ MEM_freeN(data);
+ }
+}
+
+GPUTexture *IMB_create_gpu_texture(ImBuf *ibuf, bool use_high_bitdepth, bool use_premult)
+{
+ GPUTexture *tex = NULL;
+ int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)};
+ bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
+
+#ifdef WITH_DDS
+ if (ibuf->ftype == IMB_FTYPE_DDS) {
+ eGPUTextureFormat compressed_format;
+ if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) {
+ fprintf(stderr, "Unable to find a suitable DXT compression,");
+ }
+ else if (do_rescale) {
+ fprintf(stderr, "Unable to load DXT image resolution,");
+ }
+ else if (!is_power_of_2_i(ibuf->x) || !is_power_of_2_i(ibuf->y)) {
+ fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,");
+ }
+ else {
+ tex = GPU_texture_create_compressed(
+ ibuf->x, ibuf->y, ibuf->dds_data.nummipmaps, compressed_format, ibuf->dds_data.data);
+
+ if (tex != NULL) {
+ return tex;
+ }
+ else {
+ fprintf(stderr, "ST3C support not found,");
+ }
+ }
+ /* Fallback to uncompressed texture. */
+ fprintf(stderr, " falling back to uncompressed.\n");
+ }
+#endif
+
+ eGPUDataFormat data_format;
+ eGPUTextureFormat tex_format;
+ imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
+
+ const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
+ bool freebuf = false;
+
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+
+ /* Create Texture. */
+ tex = GPU_texture_create_nD(UNPACK2(size), 0, 2, data, tex_format, data_format, 0, false, NULL);
+
+ GPU_texture_anisotropic_filter(tex, true);
+
+ if (freebuf) {
+ MEM_freeN(data);
+ }
+
+ return tex;
+} \ No newline at end of file
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index e2102abb285..8b42f1a936d 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -118,7 +118,8 @@ typedef struct BrushGpencilSettings {
int sculpt_mode_flag;
/** Preset type (used to reset brushes - internal). */
short preset_type;
- char _pad3[2];
+ /** Brush preselected mode (Active/Material/Vertexcolor). */
+ short brush_draw_mode;
/** Randomness for Hue. */
float random_hue;
@@ -258,6 +259,13 @@ typedef enum eGP_BrushEraserMode {
GP_BRUSH_ERASER_STROKE = 2,
} eGP_BrushEraserMode;
+/* BrushGpencilSettings->brush_draw_mode */
+typedef enum eGP_BrushMode {
+ GP_BRUSH_MODE_ACTIVE = 0,
+ GP_BRUSH_MODE_MATERIAL = 1,
+ GP_BRUSH_MODE_VERTEXCOLOR = 2,
+} eGP_BrushMode;
+
/* BrushGpencilSettings default brush icons */
typedef enum eGP_BrushIcons {
GP_BRUSH_ICON_PENCIL = 1,
@@ -500,7 +508,7 @@ typedef struct Brush {
/** Source for fill tool color gradient application. */
char gradient_fill_mode;
- char _pad0[1];
+ char _pad0[5];
/** Projection shape (sphere, circle). */
char falloff_shape;
@@ -572,6 +580,8 @@ typedef struct Brush {
float cloth_sim_limit;
float cloth_sim_falloff;
+ float cloth_constraint_softbody_strength;
+
/* smooth */
int smooth_deform_type;
float surface_smooth_shape_preservation;
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index b2902407a15..9f724973b6c 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -274,9 +274,12 @@ typedef struct Curve {
int selstart, selend;
/* text data */
- /** Number of characters (strinfo). */
- int len_wchar;
- /** Number of bytes (str - utf8). */
+ /**
+ * Number of characters (unicode code-points)
+ * This is the length of #Curve.strinfo and the result of `BLI_strlen_utf8(cu->str)`.
+ */
+ int len_char32;
+ /** Number of bytes: `strlen(Curve.str)`. */
int len;
char *str;
struct EditFont *editfont;
diff --git a/source/blender/makesdna/DNA_curveprofile_types.h b/source/blender/makesdna/DNA_curveprofile_types.h
index ca00f783905..7af8c3cf3ca 100644
--- a/source/blender/makesdna/DNA_curveprofile_types.h
+++ b/source/blender/makesdna/DNA_curveprofile_types.h
@@ -31,7 +31,7 @@
/** Number of table points per control point. */
#define PROF_RESOL 16
/** Dynamic size of widget's high resolution table. Input should be profile->totpoint. */
-#define PROF_N_TABLE(n_pts) min_ii(PROF_TABLE_MAX, (((n_pts - 1)) * PROF_RESOL) + 1)
+#define PROF_TABLE_LEN(n_pts) min_ii(PROF_TABLE_MAX, (((n_pts - 1)) * PROF_RESOL) + 1)
/**
* Each control point that makes up the profile.
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 0ffb6c8a76a..70512c5094b 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -117,13 +117,13 @@ typedef struct ImageTile {
#define IMA_NEED_FRAME_RECALC (1 << 3)
#define IMA_SHOW_STEREO (1 << 4)
-enum {
- TEXTARGET_TEXTURE_2D = 0,
- TEXTARGET_TEXTURE_CUBE_MAP = 1,
- TEXTARGET_TEXTURE_2D_ARRAY = 2,
- TEXTARGET_TEXTURE_TILE_MAPPING = 3,
- TEXTARGET_COUNT = 4,
-};
+/* Used to get the correct gpu texture from an Image datablock. */
+typedef enum eGPUTextureTarget {
+ TEXTARGET_2D = 0,
+ TEXTARGET_2D_ARRAY,
+ TEXTARGET_TILE_MAPPING,
+ TEXTARGET_COUNT,
+} eGPUTextureTarget;
typedef struct Image {
ID id;
@@ -133,8 +133,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
- /** Not written in file 4 = TEXTARGET_COUNT, 2 = stereo eyes. */
- struct GPUTexture *gputexture[4][2];
+ /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes. */
+ struct GPUTexture *gputexture[3][2];
/* sources from: */
ListBase anims;
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index d750a7f3148..063e5d8af09 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -64,8 +64,8 @@ typedef struct MovieClipProxy {
typedef struct MovieClip_RuntimeGPUTexture {
void *next, *prev;
MovieClipUser user;
- /** Not written in file 4 = TEXTARGET_COUNT. */
- struct GPUTexture *gputexture[4];
+ /** Not written in file 3 = TEXTARGET_COUNT. */
+ struct GPUTexture *gputexture[3];
} MovieClip_RuntimeGPUTexture;
typedef struct MovieClip_Runtime {
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index 5bb0e50e089..afc59b422c5 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -30,16 +30,21 @@ typedef struct Simulation {
struct bNodeTree *nodetree;
- int flag;
+ uint32_t flag;
+
+ /** This is the frame in scene time, that the states correspond to. */
float current_frame;
+
+ /** Time since the start of the simulation in simulation time (which might differ from scene
+ * time). */
float current_simulation_time;
char _pad[4];
/** List containing SimulationState objects. */
struct ListBase states;
- /** List containing PersistentDataHandleItem objects. */
- struct ListBase persistent_data_handles;
+ /** List containing SimulationDependency objects. */
+ struct ListBase dependencies;
} Simulation;
typedef struct SimulationState {
@@ -54,8 +59,8 @@ typedef struct ParticleSimulationState {
SimulationState head;
/** Contains the state of the particles at time Simulation->current_frame. */
- int tot_particles;
- int next_particle_id;
+ int32_t tot_particles;
+ int32_t next_particle_id;
struct CustomData attributes;
} ParticleSimulationState;
@@ -66,20 +71,27 @@ typedef struct ParticleMeshEmitterSimulationState {
char _pad[4];
} ParticleMeshEmitterSimulationState;
-/** Stores a mapping between an integer handle and a corresponding ID data block. */
-typedef struct PersistentDataHandleItem {
- struct PersistentDataHandleItem *next;
- struct PersistentDataHandleItem *prev;
+/** Stores a reference to data that the simulation depends on. This is partially derived from the
+ * simulation node tree. */
+typedef struct SimulationDependency {
+ struct SimulationDependency *next;
+ struct SimulationDependency *prev;
struct ID *id;
- int handle;
- char _pad[4];
-} PersistentDataHandleItem;
+ int32_t handle;
+ uint32_t flag;
+} SimulationDependency;
/* Simulation.flag */
enum {
SIM_DS_EXPAND = (1 << 0),
};
+/* SimulationDependency.flag */
+enum {
+ SIM_DEPENDS_ON_TRANSFORM = (1 << 0),
+ SIM_DEPENDS_ON_GEOMETRY = (1 << 1),
+};
+
#define SIM_TYPE_NAME_PARTICLE_SIMULATION "Particle Simulation"
#define SIM_TYPE_NAME_PARTICLE_MESH_EMITTER "Particle Mesh Emitter"
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index e6f6ce1e208..d50c0055499 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -733,7 +733,7 @@ typedef struct UserDef {
char _pad1[2];
int undomemory;
float gpu_viewport_quality DNA_DEPRECATED;
- short gp_manhattendist, gp_euclideandist, gp_eraser;
+ short gp_manhattandist, gp_euclideandist, gp_eraser;
/** #eGP_UserdefSettings. */
short gp_settings;
char _pad13[4];
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index f2cf72843bd..a73fc747f84 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -67,6 +67,7 @@ DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_f, hardeness)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_s, aspect_ratio)
DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance)
+DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
DNA_STRUCT_RENAME_ELEM(Camera, clipend, clip_end)
DNA_STRUCT_RENAME_ELEM(Camera, clipsta, clip_start)
DNA_STRUCT_RENAME_ELEM(Collection, dupli_ofs, instance_offset)
@@ -90,6 +91,7 @@ DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights)
DNA_STRUCT_RENAME_ELEM(Text, name, filepath)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, scrubbing_background, time_scrub_background)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, show_back_grad, background_type)
+DNA_STRUCT_RENAME_ELEM(UserDef, gp_manhattendist, gp_manhattandist)
DNA_STRUCT_RENAME_ELEM(VFont, name, filepath)
DNA_STRUCT_RENAME_ELEM(View3D, far, clip_end)
DNA_STRUCT_RENAME_ELEM(View3D, near, clip_start)
diff --git a/source/blender/makesdna/intern/dna_utils.c b/source/blender/makesdna/intern/dna_utils.c
index 97f4785374a..3cf5c52a4c6 100644
--- a/source/blender/makesdna/intern/dna_utils.c
+++ b/source/blender/makesdna/intern/dna_utils.c
@@ -235,7 +235,9 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir, GHash **r_struct_map, GHash
if (version_dir == DNA_RENAME_STATIC_FROM_ALIAS) {
const char *renames[][2] = {
- {"int8_t", "char"}, /* Note that a char is always unsigned in Blender. */
+ /* Disable 'int8_t' until we support 'signed char', since changing negative
+ * values to a different type isn't supported and will change the value. */
+ /* {"int8_t", "char"}, */
{"uint8_t", "uchar"},
{"int16_t", "short"},
{"uint16_t", "ushort"},
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 182296c0ba2..48258f39604 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -1530,12 +1530,21 @@ int main(int argc, char **argv)
#endif /* if 0 */
-/* even though DNA supports, 'long' shouldn't be used since it can be either 32 or 64bit,
- * use int or int64_t instead.
+/**
+ * Disable types:
+ *
+ * - 'long': even though DNA supports, 'long' shouldn't be used since it can be either 32 or 64bit,
+ * use int, int32_t or int64_t instead.
+ * - 'int8_t': as DNA doesn't yet support 'signed char' types,
+ * all char types are assumed to be unsigned.
+ * We should be able to support this, it's just not something which has been added yet.
+ *
* Only valid use would be as a runtime variable if an API expected a long,
- * but so far we dont have this happening. */
+ * but so far we don't have this happening.
+ */
#ifdef __GNUC__
# pragma GCC poison long
+# pragma GCC poison int8_t
#endif
#include "DNA_ID.h"
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 71922eb86b5..00ce5488636 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -243,6 +243,12 @@ static EnumPropertyItem rna_enum_gpencil_fill_draw_modes_items[] = {
{GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Edit Lines", "Use edit lines as fill boundary limits"},
{0, NULL, 0, NULL, NULL}};
+static EnumPropertyItem rna_enum_gpencil_brush_modes_items[] = {
+ {GP_BRUSH_MODE_ACTIVE, "ACTIVE", 0, "Active", "Use current mode"},
+ {GP_BRUSH_MODE_MATERIAL, "MATERIAL", 0, "Material", "Use always material mode"},
+ {GP_BRUSH_MODE_VERTEXCOLOR, "VERTEXCOLOR", 0, "Vertex Color", "Use always Vertex Color mode"},
+ {0, NULL, 0, NULL, NULL}};
+
static EnumPropertyItem rna_enum_gpencil_brush_paint_icons_items[] = {
{GP_BRUSH_ICON_PENCIL, "PENCIL", ICON_GPBRUSH_PENCIL, "Pencil", ""},
{GP_BRUSH_ICON_PEN, "PEN", ICON_GPBRUSH_PEN, "Pen", ""},
@@ -359,7 +365,7 @@ static bool rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr)
static bool rna_BrushCapabilitiesSculpt_has_persistence_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return br->sculpt_tool == SCULPT_TOOL_LAYER;
+ return ELEM(br->sculpt_tool, SCULPT_TOOL_LAYER, SCULPT_TOOL_CLOTH);
}
static bool rna_BrushCapabilitiesSculpt_has_pinch_factor_get(PointerRNA *ptr)
@@ -1640,6 +1646,12 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mode", "Mode to draw boundary limits");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ prop = RNA_def_property(srna, "brush_draw_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "brush_draw_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Preselected mode when using this brush");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
prop = RNA_def_property(srna, "trim", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_TRIM_STROKE);
RNA_def_property_boolean_default(prop, false);
@@ -2556,6 +2568,15 @@ static void rna_def_brush(BlenderRNA *brna)
"Area to apply deformation falloff to the effects of the simulation");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "cloth_constraint_softbody_strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "cloth_constraint_softbody_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(
+ prop,
+ "Soft Body Influence",
+ "How much the simulation preserves the original shape, acting as a soft body");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "hardness", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "hardness");
RNA_def_property_range(prop, 0.0f, 1.0f);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 771235c85aa..8a3186ea7fe 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -570,7 +570,7 @@ static void rna_Curve_body_set(PointerRNA *ptr, const char *value)
Curve *cu = (Curve *)ptr->owner_id;
- cu->len_wchar = len_chars;
+ cu->len_char32 = len_chars;
cu->len = len_bytes;
cu->pos = len_chars;
@@ -1206,7 +1206,7 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "body_format", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "strinfo", "len_wchar");
+ RNA_def_property_collection_sdna(prop, NULL, "strinfo", "len_char32");
RNA_def_property_struct_type(prop, "TextCharacterFormat");
RNA_def_property_ui_text(prop, "Character Info", "Stores the style of each character");
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 887bded8540..1c43815d3a2 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -67,7 +67,6 @@ static const EnumPropertyItem image_source_items[] = {
# include "BKE_global.h"
-# include "GPU_draw.h"
# include "GPU_texture.h"
# include "IMB_imbuf.h"
@@ -200,7 +199,7 @@ static void rna_Image_gpu_texture_update(Main *UNUSED(bmain),
Image *ima = (Image *)ptr->owner_id;
if (!G.background) {
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
}
WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
@@ -398,7 +397,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
- GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D][0];
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
@@ -516,7 +515,7 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values)
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID;
BKE_image_mark_dirty(ima, ibuf);
if (!G.background) {
- GPU_free_image(ima);
+ BKE_image_free_gputextures(ima);
}
WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
}
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 41c0e724234..6f876923e52 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -50,8 +50,6 @@
# include "DNA_image_types.h"
# include "DNA_scene_types.h"
-# include "GPU_glew.h"
-
# include "MEM_guardedalloc.h"
static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, ReportList *reports)
@@ -222,23 +220,24 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
BKE_imageuser_default(&iuser);
iuser.framenr = frame;
- GPUTexture *tex = GPU_texture_from_blender(image, &iuser, NULL, GL_TEXTURE_2D);
+ GPUTexture *tex = BKE_image_get_gpu_texture(image, &iuser, NULL);
if (tex == NULL) {
BKE_reportf(reports, RPT_ERROR, "Failed to load image texture '%s'", image->id.name + 2);
- return (int)GL_INVALID_OPERATION;
+ /* TODO(fclem) this error code makes no sense for vulkan. */
+ return 0x0502; /* GL_INVALID_OPERATION */
}
- return GL_NO_ERROR;
+ return 0; /* GL_NO_ERROR */
}
static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
{
- int error = GL_NO_ERROR;
+ int error = 0; /* GL_NO_ERROR */
BKE_image_tag_time(image);
- if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL) {
+ if (image->gputexture[TEXTARGET_2D][0] == NULL) {
error = rna_Image_gl_load(image, reports, frame);
}
@@ -247,7 +246,7 @@ static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
static void rna_Image_gl_free(Image *image)
{
- GPU_free_image(image);
+ BKE_image_free_gputextures(image);
/* remove the nocollect flag, image is available for garbage collection again */
image->flag &= ~IMA_NOCOLLECT;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 6f0192bb810..0359b2ed959 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -38,6 +38,7 @@
#include "BKE_animsys.h"
#include "BKE_image.h"
#include "BKE_node.h"
+#include "BKE_simulation.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -2848,6 +2849,14 @@ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *
}
}
+static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, PointerRNA *ptr)
+{
+ rna_NodeSocketStandard_value_update(C, ptr);
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ Main *bmain = CTX_data_main(C);
+ ntreeUpdateTree(bmain, ntree);
+}
+
/* ******** Node Types ******** */
static void rna_NodeInternalSocketTemplate_name_get(PointerRNA *ptr, char *value)
@@ -8862,7 +8871,8 @@ static void rna_def_node_socket_object(BlenderRNA *brna,
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
+ RNA_def_property_update(
+ prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
/* socket interface */
@@ -8896,7 +8906,8 @@ static void rna_def_node_socket_image(BlenderRNA *brna,
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Image");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
+ RNA_def_property_update(
+ prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
/* socket interface */
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 4157747455d..59cedf8fcb8 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -370,13 +370,14 @@ static void rna_Sequences_remove(
Sequence *seq = seq_ptr->data;
Scene *scene = (Scene *)id;
- if (BLI_remlink_safe(&ed->seqbase, seq) == false) {
+ if (BLI_findindex(&ed->seqbase, seq) == -1) {
BKE_reportf(
reports, RPT_ERROR, "Sequence '%s' not in scene '%s'", seq->name + 2, scene->id.name + 2);
return;
}
- BKE_sequence_free(scene, seq, true);
+ BKE_sequencer_flag_for_removal(scene, &ed->seqbase, seq);
+ BKE_sequencer_remove_flagged_sequences(scene, &ed->seqbase);
RNA_POINTER_INVALIDATE(seq_ptr);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 494fcec4c31..155f5ab3043 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1776,87 +1776,28 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSE
{
SpaceProperties *sbuts = (SpaceProperties *)(ptr->data);
EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- if (sbuts->pathflag & (1 << BCONTEXT_TOOL)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_TOOL);
- }
-
- if (totitem) {
- RNA_enum_item_add_separator(&item, &totitem);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_RENDER)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_RENDER);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_OUTPUT)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_OUTPUT);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_VIEW_LAYER)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_VIEW_LAYER);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_SCENE)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SCENE);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_WORLD)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_WORLD);
- }
- if (totitem) {
- RNA_enum_item_add_separator(&item, &totitem);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_OBJECT)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_OBJECT);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_MODIFIER)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_MODIFIER);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_SHADERFX)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SHADERFX);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_PARTICLE)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_PARTICLE);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_PHYSICS)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_PHYSICS);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_CONSTRAINT)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_CONSTRAINT);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_DATA)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_DATA);
- (item + totitem - 1)->icon = sbuts->dataicon;
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_BONE)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_BONE);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_BONE_CONSTRAINT)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_BONE_CONSTRAINT);
- }
-
- if (sbuts->pathflag & (1 << BCONTEXT_MATERIAL)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_MATERIAL);
- }
+ /* We use 32 tabs maximum here so a flag for each can fit into a 32 bit integer flag.
+ * A theoretical maximum would be BCONTEXT_TOT * 2, with every tab displayed and a spacer
+ * in every other item. But this size is currently limited by the size of integer
+ * supported by RNA enums. */
+ int context_tabs_array[32];
+ int totitem = ED_buttons_tabs_list(sbuts, context_tabs_array);
+ BLI_assert(totitem <= ARRAY_SIZE(context_tabs_array));
+
+ int totitem_added = 0;
+ for (int i = 0; i < totitem; i++) {
+ if (context_tabs_array[i] == -1) {
+ RNA_enum_item_add_separator(&item, &totitem_added);
+ continue;
+ }
- if (totitem) {
- RNA_enum_item_add_separator(&item, &totitem);
- }
+ RNA_enum_items_add_value(&item, &totitem_added, buttons_context_items, context_tabs_array[i]);
- if (sbuts->pathflag & (1 << BCONTEXT_TEXTURE)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_TEXTURE);
+ /* Add the object data icon dynamically for the data tab. */
+ if (context_tabs_array[i] == BCONTEXT_DATA) {
+ (item + totitem_added - 1)->icon = sbuts->dataicon;
+ }
}
RNA_enum_item_end(&item, &totitem);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 00bbff5cf51..6ce6098d0c3 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -179,6 +179,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "BKE_blender.h"
# include "BKE_global.h"
# include "BKE_idprop.h"
+# include "BKE_image.h"
# include "BKE_main.h"
# include "BKE_mesh_runtime.h"
# include "BKE_paint.h"
@@ -187,9 +188,9 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "DEG_depsgraph.h"
-# include "GPU_draw.h"
# include "GPU_extensions.h"
# include "GPU_select.h"
+# include "GPU_texture.h"
# include "BLF_api.h"
@@ -363,13 +364,14 @@ static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- GPU_set_anisotropic(U.anisotropic_filter);
+ GPU_samplers_free();
+ GPU_samplers_init();
rna_userdef_update(bmain, scene, ptr);
}
static void rna_userdef_gl_texture_limit_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- GPU_free_images(bmain);
+ BKE_image_free_all_gputextures(bmain);
rna_userdef_update(bmain, scene, ptr);
}
@@ -4988,7 +4990,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
/* grease pencil */
prop = RNA_def_property(srna, "grease_pencil_manhattan_distance", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "gp_manhattendist");
+ RNA_def_property_int_sdna(prop, NULL, "gp_manhattandist");
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop,
"Grease Pencil Manhattan Distance",
diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc
index d9cc9840e08..edfcc16af85 100644
--- a/source/blender/modifiers/intern/MOD_simulation.cc
+++ b/source/blender/modifiers/intern/MOD_simulation.cc
@@ -114,10 +114,12 @@ static PointCloud *modifyPointCloud(ModifierData *md,
const float3 *positions = (const float3 *)CustomData_get_layer_named(
&state->attributes, CD_PROP_FLOAT3, "Position");
+ const float *radii = (const float *)CustomData_get_layer_named(
+ &state->attributes, CD_PROP_FLOAT, "Radius");
memcpy(pointcloud->co, positions, sizeof(float3) * state->tot_particles);
for (int i = 0; i < state->tot_particles; i++) {
- pointcloud->radius[i] = 0.03f;
+ pointcloud->radius[i] = radii[i];
}
return pointcloud;
@@ -131,6 +133,9 @@ static void panel_draw(const bContext *C, Panel *panel)
PointerRNA ob_ptr;
modifier_panel_get_property_pointers(C, panel, &ob_ptr, &ptr);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
uiItemR(layout, &ptr, "simulation", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "data_path", 0, NULL, ICON_NONE);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 80720f5206a..c53e01ac80f 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -160,7 +160,7 @@ set(SRC
shader/nodes/node_shader_bsdf_velvet.c
shader/nodes/node_shader_bump.c
shader/nodes/node_shader_camera.c
- shader/nodes/node_shader_clamp.c
+ shader/nodes/node_shader_clamp.cc
shader/nodes/node_shader_common.c
shader/nodes/node_shader_curves.c
shader/nodes/node_shader_displacement.c
@@ -278,6 +278,7 @@ set(SRC
intern/node_common.c
intern/node_exec.c
intern/node_socket.cc
+ intern/node_tree_dependencies.cc
intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/node_util.c
@@ -292,6 +293,7 @@ set(SRC
NOD_composite.h
NOD_derived_node_tree.hh
NOD_function.h
+ NOD_node_tree_dependencies.hh
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
NOD_shader.h
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index d79bd9031b8..b39c9fd1a23 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -181,7 +181,7 @@ class DerivedNodeTree : NonCopyable, NonMovable {
Vector<DInputSocket *> input_sockets_;
Vector<DOutputSocket *> output_sockets_;
- Map<const bNodeType *, Vector<DNode *>> nodes_by_type_;
+ MultiValueMap<const bNodeType *, DNode *> nodes_by_type_;
public:
DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs);
@@ -483,13 +483,7 @@ inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname)
inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const
{
- const Vector<DNode *> *nodes = nodes_by_type_.lookup_ptr(nodetype);
- if (nodes == nullptr) {
- return {};
- }
- else {
- return *nodes;
- }
+ return nodes_by_type_.lookup(nodetype);
}
inline Span<const DSocket *> DerivedNodeTree::sockets() const
diff --git a/source/blender/nodes/NOD_node_tree_dependencies.hh b/source/blender/nodes/NOD_node_tree_dependencies.hh
new file mode 100644
index 00000000000..ca7059caa5f
--- /dev/null
+++ b/source/blender/nodes/NOD_node_tree_dependencies.hh
@@ -0,0 +1,79 @@
+/*
+ * 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 __NOD_NODE_TREE_DEPENDENCIES_H__
+#define __NOD_NODE_TREE_DEPENDENCIES_H__
+
+#include "BLI_vector_set.hh"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+
+struct bNodeTree;
+
+namespace blender::nodes {
+
+class NodeTreeDependencies {
+ private:
+ VectorSet<Object *> transform_deps_;
+ VectorSet<Object *> geometry_deps_;
+ VectorSet<ID *> id_deps_;
+
+ public:
+ void add_transform_dependency(Object *object)
+ {
+ if (object == nullptr) {
+ return;
+ }
+ transform_deps_.add(object);
+ id_deps_.add(&object->id);
+ }
+
+ void add_geometry_dependency(Object *object)
+ {
+ if (object == nullptr) {
+ return;
+ }
+ geometry_deps_.add(object);
+ id_deps_.add(&object->id);
+ }
+
+ bool depends_on(ID *id) const
+ {
+ return id_deps_.contains(id);
+ }
+
+ Span<Object *> transform_dependencies()
+ {
+ return transform_deps_;
+ }
+
+ Span<Object *> geometry_dependencies()
+ {
+ return geometry_deps_;
+ }
+
+ Span<ID *> id_dependencies()
+ {
+ return id_deps_;
+ }
+};
+
+NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree);
+
+} // namespace blender::nodes
+
+#endif /* __NOD_NODE_TREE_DEPENDENCIES_H__ */
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index ebf5709ef50..13656c2e940 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -47,6 +47,7 @@
#include "BLI_array.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
#include "BLI_string_ref.hh"
#include "BLI_timeit.hh"
#include "BLI_utility_mixins.hh"
@@ -162,7 +163,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Vector<SocketRef *> sockets_by_id_;
Vector<InputSocketRef *> input_sockets_;
Vector<OutputSocketRef *> output_sockets_;
- Map<const bNodeType *, Vector<NodeRef *>> nodes_by_type_;
+ MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
public:
NodeTreeRef(bNodeTree *btree);
@@ -411,13 +412,7 @@ inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(StringRefNull idname) co
inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const
{
- const Vector<NodeRef *> *nodes = nodes_by_type_.lookup_ptr(nodetype);
- if (nodes == nullptr) {
- return {};
- }
- else {
- return *nodes;
- }
+ return nodes_by_type_.lookup(nodetype);
}
inline Span<const SocketRef *> NodeTreeRef::sockets() const
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index b7c78cb1499..5414ea9208a 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -321,7 +321,7 @@ BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids(
node->id_ = node_index;
const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo;
- nodes_by_type_.lookup_or_add_default(nodetype).append(node);
+ nodes_by_type_.add(nodetype, node);
for (DInputSocket *socket : node->inputs_) {
socket->id_ = sockets_by_id_.append_and_get_index(socket);
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 49868505d68..57c8d51975e 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -586,10 +586,10 @@ static bNodeSocketType *make_socket_type_string()
class ObjectSocketMultiFunction : public blender::fn::MultiFunction {
private:
- const Object *object_;
+ Object *object_;
public:
- ObjectSocketMultiFunction(const Object *object) : object_(object)
+ ObjectSocketMultiFunction(Object *object) : object_(object)
{
blender::fn::MFSignatureBuilder signature = this->get_builder("Object Socket");
signature.depends_on_context();
@@ -631,7 +631,7 @@ static bNodeSocketType *make_socket_type_object()
return blender::fn::MFDataType::ForSingle<blender::bke::PersistentObjectHandle>();
};
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- const Object *object = builder.socket_default_value<bNodeSocketValueObject>()->value;
+ Object *object = builder.socket_default_value<bNodeSocketValueObject>()->value;
builder.construct_generator_fn<ObjectSocketMultiFunction>(object);
};
return socktype;
diff --git a/source/blender/nodes/intern/node_tree_dependencies.cc b/source/blender/nodes/intern/node_tree_dependencies.cc
new file mode 100644
index 00000000000..efe75a10f7e
--- /dev/null
+++ b/source/blender/nodes/intern/node_tree_dependencies.cc
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include "NOD_node_tree_dependencies.hh"
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+namespace blender::nodes {
+
+static void add_dependencies_of_node_tree(bNodeTree &ntree, NodeTreeDependencies &r_dependencies)
+{
+ /* TODO: Do a bit more sophisticated parsing to see which dependencies are really required. */
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->type == SOCK_OBJECT) {
+ Object *object = ((bNodeSocketValueObject *)socket->default_value)->value;
+ if (object != nullptr) {
+ r_dependencies.add_transform_dependency(object);
+ if (object->type == OB_MESH) {
+ r_dependencies.add_geometry_dependency(object);
+ }
+ }
+ }
+ }
+
+ if (node->type == NODE_GROUP) {
+ bNodeTree *group = (bNodeTree *)node->id;
+ if (group != nullptr) {
+ add_dependencies_of_node_tree(*group, r_dependencies);
+ }
+ }
+ }
+}
+
+NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree)
+{
+ NodeTreeDependencies dependencies;
+ add_dependencies_of_node_tree(ntree, dependencies);
+ return dependencies;
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 186ca750f10..47669bc5ca2 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -79,7 +79,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
for (NodeRef *node : nodes_by_id_) {
const bNodeType *nodetype = node->bnode_->typeinfo;
- nodes_by_type_.lookup_or_add_default(nodetype).append(node);
+ nodes_by_type_.add(nodetype, node);
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.c b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 808f9686f0a..1077f616a62 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -50,6 +50,30 @@ static int gpu_shader_clamp(GPUMaterial *mat,
GPU_stack_link(mat, node, "clamp_range", in, out);
}
+static void sh_node_clamp_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> minmax_fn{
+ "Clamp (Min Max)",
+ [](float value, float min, float max) { return std::min(std::max(value, min), max); }};
+ static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> range_fn{
+ "Clamp (Range)", [](float value, float a, float b) {
+ if (a < b) {
+ return clamp_f(value, a, b);
+ }
+ else {
+ return clamp_f(value, b, a);
+ }
+ }};
+
+ int clamp_type = builder.bnode().custom1;
+ if (clamp_type == NODE_CLAMP_MINMAX) {
+ builder.set_matching_fn(minmax_fn);
+ }
+ else {
+ builder.set_matching_fn(range_fn);
+ }
+}
+
void register_node_type_sh_clamp(void)
{
static bNodeType ntype;
@@ -58,6 +82,7 @@ void register_node_type_sh_clamp(void)
node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
node_type_init(&ntype, node_shader_init_clamp);
node_type_gpu(&ntype, gpu_shader_clamp);
+ ntype.expand_in_mf_network = sh_node_clamp_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index deb0ee9037c..30e376f8e09 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -45,6 +45,9 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
float val[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) :
GPU_builtin(GPU_BARYCENTRIC_TEXCO);
+ if (out[5].hasoutput) {
+ GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC);
+ }
/* Opti: don't request orco if not needed. */
GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) :
GPU_attribute(mat, CD_ORCO, "");
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 0cf4b51f307..38e79ebe94d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -19,8 +19,6 @@
#include "../node_shader_util.h"
-#include "GPU_draw.h"
-
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_environment_in[] = {
@@ -59,7 +57,8 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
NodeTexImage *tex_original = node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
- if (GPU_get_mipmap()) {
+ /* TODO(fclem) For now assume mipmap is always enabled. */
+ if (true) {
sampler |= GPU_SAMPLER_MIPMAP;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index cbda72cd228..1a78d2f5bf2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -19,8 +19,6 @@
#include "../node_shader_util.h"
-#include "GPU_draw.h"
-
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_image_in[] = {
@@ -95,7 +93,8 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (tex->interpolation != SHD_INTERP_CLOSEST) {
sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
- sampler_state |= GPU_get_mipmap() ? GPU_SAMPLER_MIPMAP : 0;
+ /* TODO(fclem) For now assume mipmap is always enabled. */
+ sampler_state |= true ? GPU_SAMPLER_MIPMAP : 0;
}
const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART);
diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.c
index e1da1cd34e4..d1ed13e1ffd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.c
@@ -36,6 +36,7 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
+ GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC);
/* node->custom1 is use_pixel_size */
if (node->custom1) {
return GPU_stack_link(
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
index 2de7be2d3eb..859ad81656b 100644
--- a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
@@ -20,7 +20,7 @@
static bNodeSocketTemplate sim_node_particle_mesh_emitter_in[] = {
{SOCK_OBJECT, N_("Object")},
- {SOCK_FLOAT, N_("Rate"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {SOCK_FLOAT, N_("Rate"), 100.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
{-1, ""},
};
diff --git a/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc b/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
index 8696dbe340c..8f5c6818cb4 100644
--- a/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
+++ b/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
@@ -18,6 +18,7 @@
#include "node_simulation_util.h"
static bNodeSocketTemplate sim_node_set_particle_attribute_in[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
{SOCK_STRING, N_("Name")},
{SOCK_FLOAT, N_("Float"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
{SOCK_INT, N_("Int"), 0, 0, 0, 0, -10000, 10000},
@@ -38,7 +39,7 @@ static void sim_node_set_particle_attribute_update(bNodeTree *UNUSED(ntree), bNo
{
int index = 0;
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- if (index >= 1) {
+ if (index >= 2) {
nodeSetSocketAvailability(sock, sock->type == node->custom1);
}
index++;
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 5c6e0b0a308..049b919b4a4 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -82,23 +82,23 @@ bool BPY_execute_text(struct bContext *C,
bool BPY_execute_string_as_number(struct bContext *C,
const char *imports[],
const char *expr,
- const bool verbose,
+ const char *report_prefix,
double *r_value);
bool BPY_execute_string_as_intptr(struct bContext *C,
const char *imports[],
const char *expr,
- const bool verbose,
+ const char *report_prefix,
intptr_t *r_value);
bool BPY_execute_string_as_string_and_size(struct bContext *C,
const char *imports[],
const char *expr,
- const bool verbose,
+ const char *report_prefix,
char **r_value,
size_t *r_value_size);
bool BPY_execute_string_as_string(struct bContext *C,
const char *imports[],
const char *expr,
- const bool verbose,
+ const char *report_prefix,
char **r_value);
bool BPY_execute_string_ex(struct bContext *C,
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 9c84a4bb824..406dbdafe22 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -634,7 +634,7 @@ error_cleanup:
PyObject *PyC_ExceptionBuffer_Simple(void)
{
- PyObject *string_io_buf;
+ PyObject *string_io_buf = NULL;
PyObject *error_type, *error_value, *error_traceback;
@@ -648,7 +648,19 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
return NULL;
}
- string_io_buf = PyObject_Str(error_value);
+ if (PyErr_GivenExceptionMatches(error_type, PyExc_SyntaxError)) {
+ /* Special exception for syntax errors,
+ * in these cases the full error is verbose and not very useful,
+ * just use the initial text so we know what the error is. */
+ if (PyTuple_CheckExact(error_value) && PyTuple_GET_SIZE(error_value) >= 1) {
+ string_io_buf = PyObject_Str(PyTuple_GET_ITEM(error_value, 0));
+ }
+ }
+
+ if (string_io_buf == NULL) {
+ string_io_buf = PyObject_Str(error_value);
+ }
+
/* Python does this too */
if (UNLIKELY(string_io_buf == NULL)) {
string_io_buf = PyUnicode_FromFormat("<unprintable %s object>", Py_TYPE(error_value)->tp_name);
@@ -804,8 +816,12 @@ void PyC_MainModule_Restore(PyObject *main_mod)
Py_XDECREF(main_mod);
}
-/* Must be called before Py_Initialize,
- * expects output of BKE_appdir_folder_id(BLENDER_PYTHON, NULL). */
+/**
+ * - Must be called before #Py_Initialize.
+ * - Expects output of `BKE_appdir_folder_id(BLENDER_PYTHON, NULL)`.
+ * - Note that the `PYTHONPATH` environment variable isn't reliable, see T31506.
+ Use #Py_SetPythonHome instead.
+ */
void PyC_SetHomePath(const char *py_path_bundle)
{
if (py_path_bundle == NULL) {
@@ -824,24 +840,14 @@ void PyC_SetHomePath(const char *py_path_bundle)
/* OSX allow file/directory names to contain : character (represented as / in the Finder)
* but current Python lib (release 3.1.1) doesn't handle these correctly */
if (strchr(py_path_bundle, ':')) {
- printf(
- "Warning : Blender application is located in a path containing : or / chars\
- \nThis may make python import function fail\n");
- }
-# endif
-
-# if 0 /* disable for now [#31506] - campbell */
-# ifdef _WIN32
- /* cmake/MSVC debug build crashes without this, why only
- * in this case is unknown.. */
- {
- /*BLI_setenv("PYTHONPATH", py_path_bundle)*/;
+ fprintf(stderr,
+ "Warning! Blender application is located in a path containing ':' or '/' chars\n"
+ "This may make python import function fail\n");
}
-# endif
# endif
{
- static wchar_t py_path_bundle_wchar[1024];
+ wchar_t py_path_bundle_wchar[1024];
/* Can't use this, on linux gives bug: #23018,
* TODO: try LANG="en_US.UTF-8" /usr/bin/blender, suggested 2008 */
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
index b3df991cf12..f9fe1654db0 100644
--- a/source/blender/python/gpu/gpu_py_batch.c
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -184,8 +184,7 @@ static PyObject *bpygpu_Batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_sh
}
GPUShader *shader = py_shader->shader;
- GPU_batch_program_set(
- self->batch, GPU_shader_get_program(shader), GPU_shader_get_interface(shader));
+ GPU_batch_set_shader(self->batch, shader);
#ifdef USE_GPU_PY_REFERENCES
/* Remove existing user (if any), hold new user. */
@@ -229,9 +228,7 @@ static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args)
}
}
else if (self->batch->program != GPU_shader_get_program(py_program->shader)) {
- GPU_batch_program_set(self->batch,
- GPU_shader_get_program(py_program->shader),
- GPU_shader_get_interface(py_program->shader));
+ GPU_batch_set_shader(self->batch, py_program->shader);
}
GPU_batch_draw(self->batch);
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index 190d4eb1855..c152c920453 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -566,7 +566,7 @@ static PyObject *_py_pgettext(PyObject *args,
PyDoc_STRVAR(
app_translations_pgettext_doc,
- ".. method:: pgettext(msgid, msgctxt)\n"
+ ".. method:: pgettext(msgid, msgctxt=None)\n"
"\n"
" Try to translate the given msgid (with optional msgctxt).\n"
"\n"
@@ -600,7 +600,7 @@ static PyObject *app_translations_pgettext(BlenderAppTranslations *UNUSED(self),
}
PyDoc_STRVAR(app_translations_pgettext_iface_doc,
- ".. method:: pgettext_iface(msgid, msgctxt)\n"
+ ".. method:: pgettext_iface(msgid, msgctxt=None)\n"
"\n"
" Try to translate the given msgid (with optional msgctxt), if labels' translation "
"is enabled.\n"
@@ -622,7 +622,7 @@ static PyObject *app_translations_pgettext_iface(BlenderAppTranslations *UNUSED(
}
PyDoc_STRVAR(app_translations_pgettext_tip_doc,
- ".. method:: pgettext_tip(msgid, msgctxt)\n"
+ ".. method:: pgettext_tip(msgid, msgctxt=None)\n"
"\n"
" Try to translate the given msgid (with optional msgctxt), if tooltips' "
"translation is enabled.\n"
@@ -644,7 +644,7 @@ static PyObject *app_translations_pgettext_tip(BlenderAppTranslations *UNUSED(se
}
PyDoc_STRVAR(app_translations_pgettext_data_doc,
- ".. method:: pgettext_data(msgid, msgctxt)\n"
+ ".. method:: pgettext_data(msgid, msgctxt=None)\n"
"\n"
" Try to translate the given msgid (with optional msgctxt), if new data name's "
"translation is enabled.\n"
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 89ef2f40a30..27eea80f1f6 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -97,7 +97,10 @@ void BPy_reports_write_stdout(const ReportList *reports, const char *header)
}
}
-bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const bool use_location)
+bool BPy_errors_to_report_ex(ReportList *reports,
+ const char *error_prefix,
+ const bool use_full,
+ const bool use_location)
{
PyObject *pystring;
@@ -124,40 +127,38 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo
return 0;
}
+ if (error_prefix == NULL) {
+ /* Not very helpful, better than nothing. */
+ error_prefix = "Python";
+ }
+
if (use_location) {
const char *filename;
int lineno;
- PyObject *pystring_format; /* workaround, see below */
- const char *cstring;
-
PyC_FileAndNum(&filename, &lineno);
if (filename == NULL) {
filename = "<unknown location>";
}
-#if 0 /* ARG!. workaround for a bug in blenders use of vsnprintf */
BKE_reportf(reports,
RPT_ERROR,
- "%s\nlocation: %s:%d\n",
+ TIP_("%s: %s\nlocation: %s:%d\n"),
+ error_prefix,
_PyUnicode_AsString(pystring),
filename,
lineno);
-#else
- pystring_format = PyUnicode_FromFormat(
- TIP_("%s\nlocation: %s:%d\n"), _PyUnicode_AsString(pystring), filename, lineno);
-
- cstring = _PyUnicode_AsString(pystring_format);
- BKE_report(reports, RPT_ERROR, cstring);
-
- /* not exactly needed. just for testing */
- fprintf(stderr, TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
- Py_DECREF(pystring_format); /* workaround */
-#endif
+ /* Not exactly needed. Useful for developers tracking down issues. */
+ fprintf(stderr,
+ TIP_("%s: %s\nlocation: %s:%d\n"),
+ error_prefix,
+ _PyUnicode_AsString(pystring),
+ filename,
+ lineno);
}
else {
- BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(pystring));
+ BKE_reportf(reports, RPT_ERROR, "%s: %s", error_prefix, _PyUnicode_AsString(pystring));
}
Py_DECREF(pystring);
@@ -166,5 +167,5 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo
bool BPy_errors_to_report(ReportList *reports)
{
- return BPy_errors_to_report_ex(reports, true, true);
+ return BPy_errors_to_report_ex(reports, NULL, true, true);
}
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 46206f134ba..11409397028 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -43,8 +43,10 @@ char *BPy_enum_as_string(const struct EnumPropertyItem *item);
short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
void BPy_reports_write_stdout(const struct ReportList *reports, const char *header);
bool BPy_errors_to_report_ex(struct ReportList *reports,
+ const char *error_prefix,
const bool use_full,
const bool use_location);
+bool BPy_errors_to_report_brief_with_prefix(struct ReportList *reports, const char *error_prefix);
bool BPy_errors_to_report(struct ReportList *reports);
/* TODO - find a better solution! */
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 5e2162c9e2d..d48ad2b197c 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -411,8 +411,10 @@ static PyObject *bpy_pydriver_depsgraph_as_pyobject(struct Depsgraph *depsgraph)
return pyrna_struct_CreatePyObject(&depsgraph_ptr);
}
-/* Adds a variable 'depsgraph' to the driver variables. This can then be used to obtain evaluated
- * datablocks, and the current view layer and scene. See T75553. */
+/**
+ * Adds a variable 'depsgraph' to the driver variables. This can then be used to obtain evaluated
+ * data-blocks, and the current view layer and scene. See T75553.
+ */
static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
struct Depsgraph *depsgraph)
{
@@ -428,17 +430,18 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
}
}
-/* This evals py driver expressions, 'expr' is a Python expression that
- * should evaluate to a float number, which is returned.
+/**
+ * This evaluates Python driver expressions, `driver_orig->expression`
+ * is a Python expression that should evaluate to a float number, which is returned.
*
* (old)note: PyGILState_Ensure() isn't always called because python can call
* the bake operator which intern starts a thread which calls scene update
- * which does a driver update. to avoid a deadlock check PyC_IsInterpreterActive()
- * if PyGILState_Ensure() is needed - see [#27683]
+ * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
+ * if #PyGILState_Ensure() is needed, see T27683.
*
- * (new)note: checking if python is running is not threadsafe [#28114]
+ * (new)note: checking if python is running is not thread-safe T28114
* now release the GIL on python operator execution instead, using
- * PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender.
+ * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
*
* For copy-on-write we always cache expressions and write errors in the
* original driver, otherwise these would get freed while editing. Due to
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index a880d2cd285..f91afa414ce 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -258,11 +258,13 @@ void BPY_python_start(int argc, const char **argv)
PyThreadState *py_tstate = NULL;
const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL);
- /* not essential but nice to set our name */
- static wchar_t program_path_wchar[FILE_MAX]; /* python holds a reference */
- BLI_strncpy_wchar_from_utf8(
- program_path_wchar, BKE_appdir_program_path(), ARRAY_SIZE(program_path_wchar));
- Py_SetProgramName(program_path_wchar);
+ /* Not essential but nice to set our name. */
+ {
+ const char *program_path = BKE_appdir_program_path();
+ wchar_t program_path_wchar[FILE_MAX];
+ BLI_strncpy_wchar_from_utf8(program_path_wchar, program_path, ARRAY_SIZE(program_path_wchar));
+ Py_SetProgramName(program_path_wchar);
+ }
/* must run before python initializes */
PyImport_ExtendInittab(bpy_internal_modules);
@@ -615,8 +617,11 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
/**
* \return success
*/
-bool BPY_execute_string_as_number(
- bContext *C, const char *imports[], const char *expr, const bool verbose, double *r_value)
+bool BPY_execute_string_as_number(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ double *r_value)
{
PyGILState_STATE gilstate;
bool ok = true;
@@ -635,8 +640,8 @@ bool BPY_execute_string_as_number(
ok = PyC_RunString_AsNumber(imports, expr, "<expr as number>", r_value);
if (ok == false) {
- if (verbose) {
- BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
+ if (report_prefix != NULL) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
}
else {
PyErr_Clear();
@@ -654,7 +659,7 @@ bool BPY_execute_string_as_number(
bool BPY_execute_string_as_string_and_size(bContext *C,
const char *imports[],
const char *expr,
- const bool verbose,
+ const char *report_prefix,
char **r_value,
size_t *r_value_size)
{
@@ -672,8 +677,8 @@ bool BPY_execute_string_as_string_and_size(bContext *C,
ok = PyC_RunString_AsStringAndSize(imports, expr, "<expr as str>", r_value, r_value_size);
if (ok == false) {
- if (verbose) {
- BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
+ if (report_prefix != NULL) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), false, false, report_prefix);
}
else {
PyErr_Clear();
@@ -685,12 +690,15 @@ bool BPY_execute_string_as_string_and_size(bContext *C,
return ok;
}
-bool BPY_execute_string_as_string(
- bContext *C, const char *imports[], const char *expr, const bool verbose, char **r_value)
+bool BPY_execute_string_as_string(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ char **r_value)
{
size_t value_dummy_size;
return BPY_execute_string_as_string_and_size(
- C, imports, expr, verbose, r_value, &value_dummy_size);
+ C, imports, expr, report_prefix, r_value, &value_dummy_size);
}
/**
@@ -698,8 +706,11 @@ bool BPY_execute_string_as_string(
*
* \return success
*/
-bool BPY_execute_string_as_intptr(
- bContext *C, const char *imports[], const char *expr, const bool verbose, intptr_t *r_value)
+bool BPY_execute_string_as_intptr(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ intptr_t *r_value)
{
BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
@@ -715,8 +726,8 @@ bool BPY_execute_string_as_intptr(
ok = PyC_RunString_AsIntPtr(imports, expr, "<expr as intptr>", r_value);
if (ok == false) {
- if (verbose) {
- BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
+ if (report_prefix != NULL) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
}
else {
PyErr_Clear();
diff --git a/source/blender/simulation/CMakeLists.txt b/source/blender/simulation/CMakeLists.txt
index 243b056db74..cbc6ee65303 100644
--- a/source/blender/simulation/CMakeLists.txt
+++ b/source/blender/simulation/CMakeLists.txt
@@ -43,7 +43,9 @@ set(SRC
intern/implicit_eigen.cpp
intern/particle_allocator.cc
intern/particle_function.cc
+ intern/particle_mesh_emitter.cc
intern/simulation_collect_influences.cc
+ intern/simulation_solver_influences.cc
intern/simulation_solver.cc
intern/simulation_update.cc
@@ -52,7 +54,9 @@ set(SRC
intern/implicit.h
intern/particle_allocator.hh
intern/particle_function.hh
+ intern/particle_mesh_emitter.hh
intern/simulation_collect_influences.hh
+ intern/simulation_solver_influences.hh
intern/simulation_solver.hh
intern/time_interval.hh
diff --git a/source/blender/simulation/SIM_simulation_update.hh b/source/blender/simulation/SIM_simulation_update.hh
index 40b62bfb58a..efdfde8a4de 100644
--- a/source/blender/simulation/SIM_simulation_update.hh
+++ b/source/blender/simulation/SIM_simulation_update.hh
@@ -27,6 +27,8 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
Scene *scene_cow,
Simulation *simulation_cow);
-}
+bool update_simulation_dependencies(Simulation *simulation);
+
+} // namespace blender::sim
#endif /* __SIM_SIMULATION_UPDATE_HH__ */
diff --git a/source/blender/simulation/intern/particle_allocator.cc b/source/blender/simulation/intern/particle_allocator.cc
index eb1e998e63a..e47a6354d81 100644
--- a/source/blender/simulation/intern/particle_allocator.cc
+++ b/source/blender/simulation/intern/particle_allocator.cc
@@ -16,6 +16,8 @@
#include "particle_allocator.hh"
+#include "BLI_rand.hh"
+
namespace blender::sim {
AttributesAllocator::~AttributesAllocator()
@@ -67,8 +69,15 @@ fn::MutableAttributesRef ParticleAllocator::allocate(int size)
ids[pindex] = start_id + pindex;
}
}
+ else if (name == "Hash") {
+ MutableSpan<int> hashes = attributes.get<int>("Hash");
+ RandomNumberGenerator rng(hash_seed_ ^ (uint32_t)next_id_);
+ for (int pindex : IndexRange(size)) {
+ hashes[pindex] = (int)rng.get_uint32();
+ }
+ }
else {
- type.fill_uninitialized(info.default_of(i), attributes.get(i).buffer(), size);
+ type.fill_uninitialized(info.default_of(i), attributes.get(i).data(), size);
}
}
return attributes;
diff --git a/source/blender/simulation/intern/particle_allocator.hh b/source/blender/simulation/intern/particle_allocator.hh
index 1e7578a75ed..1c412508fe6 100644
--- a/source/blender/simulation/intern/particle_allocator.hh
+++ b/source/blender/simulation/intern/particle_allocator.hh
@@ -70,10 +70,11 @@ class ParticleAllocator : NonCopyable, NonMovable {
private:
AttributesAllocator attributes_allocator_;
std::atomic<int> next_id_;
+ uint32_t hash_seed_;
public:
- ParticleAllocator(const fn::AttributesInfo &attributes_info, int next_id)
- : attributes_allocator_(attributes_info), next_id_(next_id)
+ ParticleAllocator(const fn::AttributesInfo &attributes_info, int next_id, uint32_t hash_seed)
+ : attributes_allocator_(attributes_info), next_id_(next_id), hash_seed_(hash_seed)
{
}
diff --git a/source/blender/simulation/intern/particle_function.cc b/source/blender/simulation/intern/particle_function.cc
index 935ef7983d9..035e6d50e21 100644
--- a/source/blender/simulation/intern/particle_function.cc
+++ b/source/blender/simulation/intern/particle_function.cc
@@ -49,19 +49,17 @@ ParticleFunction::ParticleFunction(const fn::MultiFunction *global_fn,
}
}
-ParticleFunctionEvaluator::ParticleFunctionEvaluator(
- const ParticleFunction &particle_fn,
- const SimulationSolveContext &solve_context,
- const ParticleChunkContext &particle_chunk_context)
+ParticleFunctionEvaluator::ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
+ const SimulationSolveContext &solve_context,
+ const ParticleChunkContext &particles)
: particle_fn_(particle_fn),
solve_context_(solve_context),
- particle_chunk_context_(particle_chunk_context),
- mask_(particle_chunk_context_.index_mask()),
+ particles_(particles),
+ mask_(particles_.index_mask),
outputs_(particle_fn_.output_types_.size(), nullptr)
{
- global_context_.add_global_context("PersistentDataHandleMap", &solve_context_.handle_map());
- per_particle_context_.add_global_context("PersistentDataHandleMap",
- &solve_context_.handle_map());
+ global_context_.add_global_context("PersistentDataHandleMap", &solve_context_.handle_map);
+ per_particle_context_.add_global_context("PersistentDataHandleMap", &solve_context_.handle_map);
}
ParticleFunctionEvaluator::~ParticleFunctionEvaluator()
@@ -92,8 +90,10 @@ void ParticleFunctionEvaluator::compute()
fn::GVSpan ParticleFunctionEvaluator::get(int output_index, StringRef expected_name) const
{
#ifdef DEBUG
- StringRef real_name = particle_fn_.output_names_[output_index];
- BLI_assert(expected_name == real_name);
+ if (expected_name != "") {
+ StringRef real_name = particle_fn_.output_names_[output_index];
+ BLI_assert(expected_name == real_name);
+ }
BLI_assert(is_computed_);
#endif
UNUSED_VARS_NDEBUG(expected_name);
@@ -116,8 +116,9 @@ void ParticleFunctionEvaluator::compute_globals()
fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size());
/* Add input parameters. */
+ ParticleFunctionInputContext input_context{solve_context_, particles_};
for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) {
- input->add_input(particle_chunk_context_.attributes(), params, resources_);
+ input->add_input(input_context, params, resources_);
}
/* Add output parameters. */
@@ -143,8 +144,9 @@ void ParticleFunctionEvaluator::compute_per_particle()
fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size());
/* Add input parameters. */
+ ParticleFunctionInputContext input_context{solve_context_, particles_};
for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) {
- input->add_input(particle_chunk_context_.attributes(), params, resources_);
+ input->add_input(input_context, params, resources_);
}
/* Add output parameters. */
diff --git a/source/blender/simulation/intern/particle_function.hh b/source/blender/simulation/intern/particle_function.hh
index eec4a700383..c9b35640b47 100644
--- a/source/blender/simulation/intern/particle_function.hh
+++ b/source/blender/simulation/intern/particle_function.hh
@@ -26,10 +26,15 @@
namespace blender::sim {
+struct ParticleFunctionInputContext {
+ const SimulationSolveContext &solve_context;
+ const ParticleChunkContext &particles;
+};
+
class ParticleFunctionInput {
public:
virtual ~ParticleFunctionInput() = default;
- virtual void add_input(fn::AttributesRef attributes,
+ virtual void add_input(ParticleFunctionInputContext &context,
fn::MFParamsBuilder &params,
ResourceCollector &resources) const = 0;
};
@@ -61,7 +66,7 @@ class ParticleFunctionEvaluator {
ResourceCollector resources_;
const ParticleFunction &particle_fn_;
const SimulationSolveContext &solve_context_;
- const ParticleChunkContext &particle_chunk_context_;
+ const ParticleChunkContext &particles_;
IndexMask mask_;
fn::MFContextBuilder global_context_;
fn::MFContextBuilder per_particle_context_;
@@ -71,13 +76,13 @@ class ParticleFunctionEvaluator {
public:
ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
const SimulationSolveContext &solve_context,
- const ParticleChunkContext &particle_chunk_context);
+ const ParticleChunkContext &particles);
~ParticleFunctionEvaluator();
void compute();
- fn::GVSpan get(int output_index, StringRef expected_name) const;
+ fn::GVSpan get(int output_index, StringRef expected_name = "") const;
- template<typename T> fn::VSpan<T> get(int output_index, StringRef expected_name) const
+ template<typename T> fn::VSpan<T> get(int output_index, StringRef expected_name = "") const
{
return this->get(output_index, expected_name).typed<T>();
}
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.cc b/source/blender/simulation/intern/particle_mesh_emitter.cc
new file mode 100644
index 00000000000..c1482a29cb7
--- /dev/null
+++ b/source/blender/simulation/intern/particle_mesh_emitter.cc
@@ -0,0 +1,352 @@
+/*
+ * 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.
+ */
+
+#include "particle_mesh_emitter.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_rand.hh"
+#include "BLI_vector_adaptor.hh"
+
+#include "BKE_mesh_runtime.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+namespace blender::sim {
+
+ParticleMeshEmitter::~ParticleMeshEmitter() = default;
+
+struct EmitterSettings {
+ Object *object;
+ float rate;
+};
+
+static BLI_NOINLINE void compute_birth_times(float rate,
+ TimeInterval emit_interval,
+ ParticleMeshEmitterSimulationState &state,
+ Vector<float> &r_birth_times)
+{
+ const float time_between_particles = 1.0f / rate;
+ int counter = 0;
+ while (true) {
+ counter++;
+ const float time_offset = counter * time_between_particles;
+ const float birth_time = state.last_birth_time + time_offset;
+ if (birth_time > emit_interval.stop()) {
+ break;
+ }
+ if (birth_time <= emit_interval.start()) {
+ continue;
+ }
+ r_birth_times.append(birth_time);
+ }
+}
+
+static BLI_NOINLINE Span<MLoopTri> get_mesh_triangles(Mesh &mesh)
+{
+ const MLoopTri *triangles = BKE_mesh_runtime_looptri_ensure(&mesh);
+ int amount = BKE_mesh_runtime_looptri_len(&mesh);
+ return Span(triangles, amount);
+}
+
+static BLI_NOINLINE void compute_triangle_areas(Mesh &mesh,
+ Span<MLoopTri> triangles,
+ MutableSpan<float> r_areas)
+{
+ assert_same_size(triangles, r_areas);
+
+ for (int i : triangles.index_range()) {
+ const MLoopTri &tri = triangles[i];
+
+ const float3 v1 = mesh.mvert[mesh.mloop[tri.tri[0]].v].co;
+ const float3 v2 = mesh.mvert[mesh.mloop[tri.tri[1]].v].co;
+ const float3 v3 = mesh.mvert[mesh.mloop[tri.tri[2]].v].co;
+
+ const float area = area_tri_v3(v1, v2, v3);
+ r_areas[i] = area;
+ }
+}
+
+static BLI_NOINLINE void compute_triangle_weights(Mesh &mesh,
+ Span<MLoopTri> triangles,
+ MutableSpan<float> r_weights)
+{
+ assert_same_size(triangles, r_weights);
+ compute_triangle_areas(mesh, triangles, r_weights);
+}
+
+static BLI_NOINLINE void compute_cumulative_distribution(Span<float> weights,
+ MutableSpan<float> r_cumulative_weights)
+{
+ BLI_assert(weights.size() + 1 == r_cumulative_weights.size());
+
+ r_cumulative_weights[0] = 0;
+ for (int i : weights.index_range()) {
+ r_cumulative_weights[i + 1] = r_cumulative_weights[i] + weights[i];
+ }
+}
+
+static void sample_cumulative_distribution_recursive(RandomNumberGenerator &rng,
+ int amount,
+ int start,
+ int one_after_end,
+ Span<float> cumulative_weights,
+ VectorAdaptor<int> &r_sampled_indices)
+{
+ BLI_assert(start <= one_after_end);
+ const int size = one_after_end - start;
+ if (size == 0) {
+ BLI_assert(amount == 0);
+ }
+ else if (amount == 0) {
+ return;
+ }
+ else if (size == 1) {
+ r_sampled_indices.append_n_times(start, amount);
+ }
+ else {
+ const int middle = start + size / 2;
+ const float left_weight = cumulative_weights[middle] - cumulative_weights[start];
+ const float right_weight = cumulative_weights[one_after_end] - cumulative_weights[middle];
+ BLI_assert(left_weight >= 0.0f && right_weight >= 0.0f);
+ const float weight_sum = left_weight + right_weight;
+ BLI_assert(weight_sum > 0.0f);
+
+ const float left_factor = left_weight / weight_sum;
+ const float right_factor = right_weight / weight_sum;
+
+ int left_amount = amount * left_factor;
+ int right_amount = amount * right_factor;
+
+ if (left_amount + right_amount < amount) {
+ BLI_assert(left_amount + right_amount + 1 == amount);
+ const float weight_per_item = weight_sum / amount;
+ const float total_remaining_weight = weight_sum -
+ (left_amount + right_amount) * weight_per_item;
+ const float left_remaining_weight = left_weight - left_amount * weight_per_item;
+ const float left_remaining_factor = left_remaining_weight / total_remaining_weight;
+ if (rng.get_float() < left_remaining_factor) {
+ left_amount++;
+ }
+ else {
+ right_amount++;
+ }
+ }
+
+ sample_cumulative_distribution_recursive(
+ rng, left_amount, start, middle, cumulative_weights, r_sampled_indices);
+ sample_cumulative_distribution_recursive(
+ rng, right_amount, middle, one_after_end, cumulative_weights, r_sampled_indices);
+ }
+}
+
+static BLI_NOINLINE void sample_cumulative_distribution(RandomNumberGenerator &rng,
+ Span<float> cumulative_weights,
+ MutableSpan<int> r_samples)
+{
+ VectorAdaptor<int> sampled_indices(r_samples);
+ sample_cumulative_distribution_recursive(rng,
+ r_samples.size(),
+ 0,
+ cumulative_weights.size() - 1,
+ cumulative_weights,
+ sampled_indices);
+ BLI_assert(sampled_indices.is_full());
+}
+
+static BLI_NOINLINE bool sample_weighted_buckets(RandomNumberGenerator &rng,
+ Span<float> weights,
+ MutableSpan<int> r_samples)
+{
+ Array<float> cumulative_weights(weights.size() + 1);
+ compute_cumulative_distribution(weights, cumulative_weights);
+
+ if (r_samples.size() > 0 && cumulative_weights.as_span().last() == 0.0f) {
+ /* All weights are zero. */
+ return false;
+ }
+
+ sample_cumulative_distribution(rng, cumulative_weights, r_samples);
+ return true;
+}
+
+static BLI_NOINLINE void sample_looptris(RandomNumberGenerator &rng,
+ Mesh &mesh,
+ Span<MLoopTri> triangles,
+ Span<int> triangles_to_sample,
+ MutableSpan<float3> r_sampled_positions,
+ MutableSpan<float3> r_sampled_normals)
+{
+ assert_same_size(triangles_to_sample, r_sampled_positions, r_sampled_normals);
+
+ MLoop *loops = mesh.mloop;
+ MVert *verts = mesh.mvert;
+
+ for (uint i : triangles_to_sample.index_range()) {
+ const uint triangle_index = triangles_to_sample[i];
+ const MLoopTri &triangle = triangles[triangle_index];
+
+ const float3 v1 = verts[loops[triangle.tri[0]].v].co;
+ const float3 v2 = verts[loops[triangle.tri[1]].v].co;
+ const float3 v3 = verts[loops[triangle.tri[2]].v].co;
+
+ const float3 bary_coords = rng.get_barycentric_coordinates();
+
+ float3 position;
+ interp_v3_v3v3v3(position, v1, v2, v3, bary_coords);
+
+ float3 normal;
+ normal_tri_v3(normal, v1, v2, v3);
+
+ r_sampled_positions[i] = position;
+ r_sampled_normals[i] = normal;
+ }
+}
+
+static BLI_NOINLINE bool compute_new_particle_attributes(ParticleEmitterContext &context,
+ EmitterSettings &settings,
+ ParticleMeshEmitterSimulationState &state,
+ Vector<float3> &r_positions,
+ Vector<float3> &r_velocities,
+ Vector<float> &r_birth_times)
+{
+ if (settings.object == nullptr) {
+ return false;
+ }
+ if (settings.rate <= 0.000001f) {
+ return false;
+ }
+ if (settings.object->type != OB_MESH) {
+ return false;
+ }
+ Mesh &mesh = *(Mesh *)settings.object->data;
+ if (mesh.totvert == 0) {
+ return false;
+ }
+
+ const float start_time = context.emit_interval.start();
+ const uint32_t seed = DefaultHash<StringRef>{}(state.head.name);
+ RandomNumberGenerator rng{(*(uint32_t *)&start_time) ^ seed};
+
+ compute_birth_times(settings.rate, context.emit_interval, state, r_birth_times);
+ const int particle_amount = r_birth_times.size();
+ if (particle_amount == 0) {
+ return false;
+ }
+
+ const float last_birth_time = r_birth_times.last();
+ rng.shuffle(r_birth_times.as_mutable_span());
+
+ Span<MLoopTri> triangles = get_mesh_triangles(mesh);
+ if (triangles.is_empty()) {
+ return false;
+ }
+
+ Array<float> triangle_weights(triangles.size());
+ compute_triangle_weights(mesh, triangles, triangle_weights);
+
+ Array<int> triangles_to_sample(particle_amount);
+ if (!sample_weighted_buckets(rng, triangle_weights, triangles_to_sample)) {
+ return false;
+ }
+
+ r_positions.resize(particle_amount);
+ r_velocities.resize(particle_amount);
+ sample_looptris(rng, mesh, triangles, triangles_to_sample, r_positions, r_velocities);
+
+ if (context.solve_context.dependency_animations.is_object_transform_changing(*settings.object)) {
+ Array<float4x4> local_to_world_matrices(particle_amount);
+ context.solve_context.dependency_animations.get_object_transforms(
+ *settings.object, r_birth_times, local_to_world_matrices);
+
+ for (int i : IndexRange(particle_amount)) {
+ const float4x4 &position_to_world = local_to_world_matrices[i];
+ const float4x4 normal_to_world = position_to_world.inverted_transposed_affine();
+ r_positions[i] = position_to_world * r_positions[i];
+ r_velocities[i] = normal_to_world * r_velocities[i];
+ }
+ }
+ else {
+ const float4x4 position_to_world = settings.object->obmat;
+ const float4x4 normal_to_world = position_to_world.inverted_transposed_affine();
+ for (int i : IndexRange(particle_amount)) {
+ r_positions[i] = position_to_world * r_positions[i];
+ r_velocities[i] = normal_to_world * r_velocities[i];
+ }
+ }
+
+ for (int i : IndexRange(particle_amount)) {
+ r_velocities[i].normalize();
+ }
+
+ state.last_birth_time = last_birth_time;
+ return true;
+}
+
+static BLI_NOINLINE EmitterSettings compute_settings(const fn::MultiFunction &inputs_fn,
+ ParticleEmitterContext &context)
+{
+ EmitterSettings parameters;
+
+ fn::MFContextBuilder mf_context;
+ mf_context.add_global_context("PersistentDataHandleMap", &context.solve_context.handle_map);
+
+ fn::MFParamsBuilder mf_params{inputs_fn, 1};
+ bke::PersistentObjectHandle object_handle;
+ mf_params.add_uninitialized_single_output(&object_handle, "Object");
+ mf_params.add_uninitialized_single_output(&parameters.rate, "Rate");
+
+ inputs_fn.call(IndexRange(1), mf_params, mf_context);
+
+ parameters.object = context.solve_context.handle_map.lookup(object_handle);
+ return parameters;
+}
+
+void ParticleMeshEmitter::emit(ParticleEmitterContext &context) const
+{
+ auto *state = context.lookup_state<ParticleMeshEmitterSimulationState>(own_state_name_);
+ if (state == nullptr) {
+ return;
+ }
+
+ EmitterSettings settings = compute_settings(inputs_fn_, context);
+
+ Vector<float3> new_positions;
+ Vector<float3> new_velocities;
+ Vector<float> new_birth_times;
+
+ if (!compute_new_particle_attributes(
+ context, settings, *state, new_positions, new_velocities, new_birth_times)) {
+ return;
+ }
+
+ for (StringRef name : particle_names_) {
+ ParticleAllocator *allocator = context.try_get_particle_allocator(name);
+ if (allocator == nullptr) {
+ continue;
+ }
+
+ int amount = new_positions.size();
+ fn::MutableAttributesRef attributes = allocator->allocate(amount);
+
+ attributes.get<float3>("Position").copy_from(new_positions);
+ attributes.get<float3>("Velocity").copy_from(new_velocities);
+ attributes.get<float>("Birth Time").copy_from(new_birth_times);
+ }
+}
+
+} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.hh b/source/blender/simulation/intern/particle_mesh_emitter.hh
new file mode 100644
index 00000000000..601697c9986
--- /dev/null
+++ b/source/blender/simulation/intern/particle_mesh_emitter.hh
@@ -0,0 +1,49 @@
+/*
+ * 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 __SIM_PARTICLE_MESH_EMITTER_HH__
+#define __SIM_PARTICLE_MESH_EMITTER_HH__
+
+#include "simulation_solver_influences.hh"
+
+#include "FN_multi_function.hh"
+
+namespace blender::sim {
+
+class ParticleMeshEmitter final : public ParticleEmitter {
+ private:
+ std::string own_state_name_;
+ Array<std::string> particle_names_;
+ const fn::MultiFunction &inputs_fn_;
+
+ public:
+ ParticleMeshEmitter(std::string own_state_name,
+ Array<std::string> particle_names,
+ const fn::MultiFunction &inputs_fn)
+ : own_state_name_(std::move(own_state_name)),
+ particle_names_(particle_names),
+ inputs_fn_(inputs_fn)
+ {
+ }
+
+ ~ParticleMeshEmitter();
+
+ void emit(ParticleEmitterContext &context) const override;
+};
+
+} // namespace blender::sim
+
+#endif /* __SIM_PARTICLE_MESH_EMITTER_HH__ */
diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc
index 764e587d157..c744defb7d5 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.cc
+++ b/source/blender/simulation/intern/simulation_collect_influences.cc
@@ -16,6 +16,7 @@
#include "simulation_collect_influences.hh"
#include "particle_function.hh"
+#include "particle_mesh_emitter.hh"
#include "FN_attributes_ref.hh"
#include "FN_multi_function_network_evaluation.hh"
@@ -23,38 +24,125 @@
#include "NOD_node_tree_multi_function.hh"
+#include "DEG_depsgraph_query.h"
+
+#include "BLI_hash.h"
#include "BLI_rand.hh"
+#include "BLI_set.hh"
namespace blender::sim {
+using fn::GVSpan;
+using fn::MFContextBuilder;
+using fn::MFDataType;
+using fn::MFDummyNode;
+using fn::MFFunctionNode;
+using fn::MFInputSocket;
+using fn::MFNetwork;
+using fn::MFNetworkEvaluator;
+using fn::MFNode;
+using fn::MFOutputSocket;
+using fn::MFParamsBuilder;
+using fn::MFParamType;
+using fn::MultiFunction;
+using fn::VSpan;
+using nodes::DerivedNodeTree;
+using nodes::DInputSocket;
+using nodes::DNode;
+using nodes::DOutputSocket;
+using nodes::DParentNode;
+using nodes::MFNetworkTreeMap;
+using nodes::NodeTreeRefMap;
+
struct DummyDataSources {
- Map<const fn::MFOutputSocket *, std::string> particle_attributes;
+ Map<const MFOutputSocket *, std::string> particle_attributes;
+ Set<const MFOutputSocket *> simulation_time;
+ Set<const MFOutputSocket *> scene_time;
};
extern "C" {
void WM_clipboard_text_set(const char *buf, bool selection);
}
-static std::string dnode_to_path(const nodes::DNode &dnode)
+static std::string dnode_to_path(const DNode &dnode)
{
std::string path;
- for (const nodes::DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
+ for (const DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
path = parent->node_ref().name() + "/" + path;
}
path = path + dnode.name();
return path;
}
-static Span<const nodes::DNode *> get_particle_simulation_nodes(const nodes::DerivedNodeTree &tree)
+struct CollectContext : NonCopyable, NonMovable {
+ SimulationInfluences &influences;
+ RequiredStates &required_states;
+ ResourceCollector &resources;
+ MFNetworkTreeMap &network_map;
+ MFNetwork &network;
+ const DerivedNodeTree &tree;
+
+ DummyDataSources data_sources;
+ Span<const DNode *> particle_simulation_nodes;
+ Map<const DNode *, std::string> node_paths;
+
+ CollectContext(SimulationInfluences &influences,
+ RequiredStates &required_states,
+ ResourceCollector &resources,
+ MFNetworkTreeMap &network_map)
+ : influences(influences),
+ required_states(required_states),
+ resources(resources),
+ network_map(network_map),
+ network(network_map.network()),
+ tree(network_map.tree())
+ {
+ particle_simulation_nodes = tree.nodes_by_type("SimulationNodeParticleSimulation");
+ }
+};
+
+static const ParticleAction *create_particle_action(CollectContext &context,
+ const DOutputSocket &dsocket,
+ Span<StringRefNull> particle_names);
+
+static const ParticleAction *create_particle_action(CollectContext &context,
+ const DInputSocket &dsocket,
+ Span<StringRefNull> particle_names)
+{
+ BLI_assert(dsocket.bsocket()->type == SOCK_CONTROL_FLOW);
+ if (dsocket.linked_sockets().size() != 1) {
+ return nullptr;
+ }
+ return create_particle_action(context, *dsocket.linked_sockets()[0], particle_names);
+}
+
+static StringRefNull get_identifier(CollectContext &context, const DNode &dnode)
+{
+ return context.node_paths.lookup_or_add_cb(&dnode, [&]() { return dnode_to_path(dnode); });
+}
+
+static Span<const DNode *> nodes_by_type(CollectContext &context, StringRefNull idname)
+{
+ return context.tree.nodes_by_type(idname);
+}
+
+static Array<StringRefNull> find_linked_particle_simulations(CollectContext &context,
+ const DOutputSocket &output_socket)
{
- return tree.nodes_by_type("SimulationNodeParticleSimulation");
+ VectorSet<StringRefNull> names;
+ for (const DInputSocket *target_socket : output_socket.linked_sockets()) {
+ if (target_socket->node().idname() == "SimulationNodeParticleSimulation") {
+ names.add(get_identifier(context, target_socket->node()));
+ }
+ }
+ return names.as_span();
}
/* Returns true on success. */
-static bool compute_global_inputs(nodes::MFNetworkTreeMap &network_map,
+static bool compute_global_inputs(MFNetworkTreeMap &network_map,
ResourceCollector &resources,
- Span<const fn::MFInputSocket *> sockets,
- MutableSpan<fn::GMutableSpan> r_results)
+ Span<const MFInputSocket *> sockets,
+ MutableSpan<GMutableSpan> r_results)
{
int amount = sockets.size();
if (amount == 0) {
@@ -65,28 +153,28 @@ static bool compute_global_inputs(nodes::MFNetworkTreeMap &network_map,
return false;
}
- fn::MFNetworkEvaluator network_fn{{}, sockets};
- fn::MFParamsBuilder params{network_fn, 1};
+ MFNetworkEvaluator network_fn{{}, sockets};
+ MFParamsBuilder params{network_fn, 1};
for (int param_index : network_fn.param_indices()) {
- fn::MFParamType param_type = network_fn.param_type(param_index);
- BLI_assert(param_type.category() == fn::MFParamType::Category::SingleOutput); /* For now. */
- const fn::CPPType &type = param_type.data_type().single_type();
+ MFParamType param_type = network_fn.param_type(param_index);
+ BLI_assert(param_type.category() == MFParamType::Category::SingleOutput); /* For now. */
+ const CPPType &type = param_type.data_type().single_type();
void *buffer = resources.linear_allocator().allocate(type.size(), type.alignment());
resources.add(buffer, type.destruct_cb(), AT);
- fn::GMutableSpan span{type, buffer, 1};
+ GMutableSpan span{type, buffer, 1};
r_results[param_index] = span;
params.add_uninitialized_single_output(span);
}
- fn::MFContextBuilder context;
+ MFContextBuilder context;
network_fn.call(IndexRange(1), params, context);
return true;
}
static std::optional<Array<std::string>> compute_global_string_inputs(
- nodes::MFNetworkTreeMap &network_map, Span<const fn::MFInputSocket *> sockets)
+ MFNetworkTreeMap &network_map, Span<const MFInputSocket *> sockets)
{
ResourceCollector local_resources;
- Array<fn::GMutableSpan> computed_values(sockets.size(), NoInitialization());
+ Array<GMutableSpan> computed_values(sockets.size(), NoInitialization());
if (!compute_global_inputs(network_map, local_resources, sockets, computed_values)) {
return {};
}
@@ -98,107 +186,177 @@ static std::optional<Array<std::string>> compute_global_string_inputs(
return strings;
}
-static void find_and_deduplicate_particle_attribute_nodes(nodes::MFNetworkTreeMap &network_map,
- DummyDataSources &r_data_sources)
+/**
+ * This will find all the particle attribute input nodes. Then it will compute the attribute names
+ * by evaluating the network (those names should not depend on per particle data). In the end,
+ * input nodes that access the same attribute are combined.
+ */
+static void prepare_particle_attribute_nodes(CollectContext &context)
{
- fn::MFNetwork &network = network_map.network();
- const nodes::DerivedNodeTree &tree = network_map.tree();
-
- Span<const nodes::DNode *> attribute_dnodes = tree.nodes_by_type(
- "SimulationNodeParticleAttribute");
+ Span<const DNode *> attribute_dnodes = nodes_by_type(context, "SimulationNodeParticleAttribute");
- Vector<fn::MFInputSocket *> name_sockets;
- for (const nodes::DNode *dnode : attribute_dnodes) {
- fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0));
+ Vector<MFInputSocket *> name_sockets;
+ for (const DNode *dnode : attribute_dnodes) {
+ MFInputSocket &name_socket = context.network_map.lookup_dummy(dnode->input(0));
name_sockets.append(&name_socket);
}
- std::optional<Array<std::string>> attribute_names = compute_global_string_inputs(network_map,
- name_sockets);
+ std::optional<Array<std::string>> attribute_names = compute_global_string_inputs(
+ context.network_map, name_sockets);
if (!attribute_names.has_value()) {
return;
}
- Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>>
- attribute_nodes_by_name_and_type;
+ MultiValueMap<std::pair<std::string, MFDataType>, MFNode *> attribute_nodes_by_name_and_type;
for (int i : attribute_names->index_range()) {
- attribute_nodes_by_name_and_type
- .lookup_or_add_default(
- {(*attribute_names)[i], name_sockets[i]->node().output(0).data_type()})
- .append(&name_sockets[i]->node());
+ attribute_nodes_by_name_and_type.add(
+ {(*attribute_names)[i], name_sockets[i]->node().output(0).data_type()},
+ &name_sockets[i]->node());
}
- Map<const fn::MFOutputSocket *, std::string> attribute_inputs;
+ Map<const MFOutputSocket *, std::string> attribute_inputs;
for (auto item : attribute_nodes_by_name_and_type.items()) {
StringRef attribute_name = item.key.first;
- fn::MFDataType data_type = item.key.second;
- Span<fn::MFNode *> nodes = item.value;
+ MFDataType data_type = item.key.second;
+ Span<MFNode *> nodes = item.value;
- fn::MFOutputSocket &new_attribute_socket = network.add_input(
+ MFOutputSocket &new_attribute_socket = context.network.add_input(
"Attribute '" + attribute_name + "'", data_type);
- for (fn::MFNode *node : nodes) {
- network.relink(node->output(0), new_attribute_socket);
+ for (MFNode *node : nodes) {
+ context.network.relink(node->output(0), new_attribute_socket);
+ }
+ context.network.remove(nodes);
+
+ context.data_sources.particle_attributes.add_new(&new_attribute_socket, attribute_name);
+ }
+}
+
+static void prepare_time_input_nodes(CollectContext &context)
+{
+ Span<const DNode *> time_input_dnodes = nodes_by_type(context, "SimulationNodeTime");
+ Vector<const DNode *> simulation_time_inputs;
+ Vector<const DNode *> scene_time_inputs;
+ for (const DNode *dnode : time_input_dnodes) {
+ NodeSimInputTimeType type = (NodeSimInputTimeType)dnode->node_ref().bnode()->custom1;
+ switch (type) {
+ case NODE_SIM_INPUT_SIMULATION_TIME: {
+ simulation_time_inputs.append(dnode);
+ break;
+ }
+ case NODE_SIM_INPUT_SCENE_TIME: {
+ scene_time_inputs.append(dnode);
+ break;
+ }
}
- network.remove(nodes);
+ }
- r_data_sources.particle_attributes.add_new(&new_attribute_socket, attribute_name);
+ if (simulation_time_inputs.size() > 0) {
+ MFOutputSocket &new_socket = context.network.add_input("Simulation Time",
+ MFDataType::ForSingle<float>());
+ for (const DNode *dnode : simulation_time_inputs) {
+ MFOutputSocket &old_socket = context.network_map.lookup_dummy(dnode->output(0));
+ context.network.relink(old_socket, new_socket);
+ context.network.remove(old_socket.node());
+ }
+ context.data_sources.simulation_time.add(&new_socket);
+ }
+ if (scene_time_inputs.size() > 0) {
+ MFOutputSocket &new_socket = context.network.add_input("Scene Time",
+ MFDataType::ForSingle<float>());
+ for (const DNode *dnode : scene_time_inputs) {
+ MFOutputSocket &old_socket = context.network_map.lookup_dummy(dnode->output(0));
+ context.network.relink(old_socket, new_socket);
+ context.network.remove(old_socket.node());
+ }
+ context.data_sources.scene_time.add(&new_socket);
}
}
class ParticleAttributeInput : public ParticleFunctionInput {
private:
std::string attribute_name_;
- const fn::CPPType &attribute_type_;
+ const CPPType &attribute_type_;
public:
- ParticleAttributeInput(std::string attribute_name, const fn::CPPType &attribute_type)
+ ParticleAttributeInput(std::string attribute_name, const CPPType &attribute_type)
: attribute_name_(std::move(attribute_name)), attribute_type_(attribute_type)
{
}
- void add_input(fn::AttributesRef attributes,
- fn::MFParamsBuilder &params,
+ void add_input(ParticleFunctionInputContext &context,
+ MFParamsBuilder &params,
ResourceCollector &UNUSED(resources)) const override
{
- std::optional<fn::GSpan> span = attributes.try_get(attribute_name_, attribute_type_);
+ std::optional<GSpan> span = context.particles.attributes.try_get(attribute_name_,
+ attribute_type_);
if (span.has_value()) {
params.add_readonly_single_input(*span);
}
else {
- params.add_readonly_single_input(fn::GVSpan::FromDefault(attribute_type_));
+ params.add_readonly_single_input(GVSpan::FromDefault(attribute_type_));
}
}
};
+class SceneTimeInput : public ParticleFunctionInput {
+ void add_input(ParticleFunctionInputContext &context,
+ MFParamsBuilder &params,
+ ResourceCollector &resources) const override
+ {
+ const float time = DEG_get_ctime(&context.solve_context.depsgraph);
+ float *time_ptr = &resources.construct<float>(AT, time);
+ params.add_readonly_single_input(time_ptr);
+ }
+};
+
+class SimulationTimeInput : public ParticleFunctionInput {
+ void add_input(ParticleFunctionInputContext &context,
+ MFParamsBuilder &params,
+ ResourceCollector &resources) const override
+ {
+ /* TODO: Vary this per particle. */
+ const float time = context.solve_context.solve_interval.stop();
+ float *time_ptr = &resources.construct<float>(AT, time);
+ params.add_readonly_single_input(time_ptr);
+ }
+};
+
static const ParticleFunction *create_particle_function_for_inputs(
- Span<const fn::MFInputSocket *> sockets_to_compute,
- ResourceCollector &resources,
- DummyDataSources &data_sources)
+ CollectContext &context, Span<const MFInputSocket *> sockets_to_compute)
{
BLI_assert(sockets_to_compute.size() >= 1);
- const fn::MFNetwork &network = sockets_to_compute[0]->node().network();
+ const MFNetwork &network = sockets_to_compute[0]->node().network();
- VectorSet<const fn::MFOutputSocket *> dummy_deps;
- VectorSet<const fn::MFInputSocket *> unlinked_input_deps;
+ VectorSet<const MFOutputSocket *> dummy_deps;
+ VectorSet<const MFInputSocket *> unlinked_input_deps;
network.find_dependencies(sockets_to_compute, dummy_deps, unlinked_input_deps);
BLI_assert(unlinked_input_deps.size() == 0);
Vector<const ParticleFunctionInput *> per_particle_inputs;
- for (const fn::MFOutputSocket *socket : dummy_deps) {
- const std::string *attribute_name = data_sources.particle_attributes.lookup_ptr(socket);
- if (attribute_name == nullptr) {
- return nullptr;
+ for (const MFOutputSocket *socket : dummy_deps) {
+ if (context.data_sources.particle_attributes.contains(socket)) {
+ const std::string *attribute_name = context.data_sources.particle_attributes.lookup_ptr(
+ socket);
+ if (attribute_name == nullptr) {
+ return nullptr;
+ }
+ per_particle_inputs.append(&context.resources.construct<ParticleAttributeInput>(
+ AT, *attribute_name, socket->data_type().single_type()));
+ }
+ else if (context.data_sources.scene_time.contains(socket)) {
+ per_particle_inputs.append(&context.resources.construct<SceneTimeInput>(AT));
+ }
+ else if (context.data_sources.simulation_time.contains(socket)) {
+ per_particle_inputs.append(&context.resources.construct<SimulationTimeInput>(AT));
}
- per_particle_inputs.append(&resources.construct<ParticleAttributeInput>(
- AT, *attribute_name, socket->data_type().single_type()));
}
- const fn::MultiFunction &per_particle_fn = resources.construct<fn::MFNetworkEvaluator>(
+ const MultiFunction &per_particle_fn = context.resources.construct<MFNetworkEvaluator>(
AT, dummy_deps.as_span(), sockets_to_compute);
Array<bool> output_is_global(sockets_to_compute.size(), false);
- const ParticleFunction &particle_fn = resources.construct<ParticleFunction>(
+ const ParticleFunction &particle_fn = context.resources.construct<ParticleFunction>(
AT,
nullptr,
&per_particle_fn,
@@ -220,13 +378,12 @@ class ParticleFunctionForce : public ParticleForce {
void add_force(ParticleForceContext &context) const override
{
- IndexMask mask = context.particle_chunk().index_mask();
- MutableSpan<float3> r_combined_force = context.force_dst();
+ IndexMask mask = context.particles.index_mask;
+ MutableSpan<float3> r_combined_force = context.force_dst;
- ParticleFunctionEvaluator evaluator{
- particle_fn_, context.solve_context(), context.particle_chunk()};
+ ParticleFunctionEvaluator evaluator{particle_fn_, context.solve_context, context.particles};
evaluator.compute();
- fn::VSpan<float3> forces = evaluator.get<float3>(0, "Force");
+ VSpan<float3> forces = evaluator.get<float3>(0, "Force");
for (int64_t i : mask) {
r_combined_force[i] += forces[i];
@@ -234,221 +391,366 @@ class ParticleFunctionForce : public ParticleForce {
}
};
-static Vector<const ParticleForce *> create_forces_for_particle_simulation(
- const nodes::DNode &simulation_node,
- nodes::MFNetworkTreeMap &network_map,
- ResourceCollector &resources,
- DummyDataSources &data_sources)
+static void create_forces_for_particle_simulation(CollectContext &context,
+ const DNode &simulation_node)
{
Vector<const ParticleForce *> forces;
- for (const nodes::DOutputSocket *origin_socket :
- simulation_node.input(2, "Forces").linked_sockets()) {
- const nodes::DNode &origin_node = origin_socket->node();
+ for (const DOutputSocket *origin_socket : simulation_node.input(2, "Forces").linked_sockets()) {
+ const DNode &origin_node = origin_socket->node();
if (origin_node.idname() != "SimulationNodeForce") {
continue;
}
- const fn::MFInputSocket &force_socket = network_map.lookup_dummy(
+ const MFInputSocket &force_socket = context.network_map.lookup_dummy(
origin_node.input(0, "Force"));
- const ParticleFunction *particle_fn = create_particle_function_for_inputs(
- {&force_socket}, resources, data_sources);
+ const ParticleFunction *particle_fn = create_particle_function_for_inputs(context,
+ {&force_socket});
if (particle_fn == nullptr) {
continue;
}
- const ParticleForce &force = resources.construct<ParticleFunctionForce>(AT, *particle_fn);
+ const ParticleForce &force = context.resources.construct<ParticleFunctionForce>(AT,
+ *particle_fn);
forces.append(&force);
}
- return forces;
+
+ StringRef particle_name = get_identifier(context, simulation_node);
+ context.influences.particle_forces.add_multiple_as(particle_name, forces);
+}
+
+static void collect_forces(CollectContext &context)
+{
+ for (const DNode *dnode : context.particle_simulation_nodes) {
+ create_forces_for_particle_simulation(context, *dnode);
+ }
+}
+
+static ParticleEmitter *create_particle_emitter(CollectContext &context, const DNode &dnode)
+{
+ Array<StringRefNull> names = find_linked_particle_simulations(context, dnode.output(0));
+ if (names.size() == 0) {
+ return nullptr;
+ }
+
+ Array<const MFInputSocket *> input_sockets{dnode.inputs().size()};
+ for (int i : input_sockets.index_range()) {
+ input_sockets[i] = &context.network_map.lookup_dummy(dnode.input(i));
+ }
+
+ if (context.network.have_dummy_or_unlinked_dependencies(input_sockets)) {
+ return nullptr;
+ }
+
+ MultiFunction &inputs_fn = context.resources.construct<MFNetworkEvaluator>(
+ AT, Span<const MFOutputSocket *>(), input_sockets.as_span());
+
+ StringRefNull own_state_name = get_identifier(context, dnode);
+ context.required_states.add(own_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER);
+ ParticleEmitter &emitter = context.resources.construct<ParticleMeshEmitter>(
+ AT, own_state_name, names.as_span(), inputs_fn);
+ return &emitter;
}
-static void collect_forces(nodes::MFNetworkTreeMap &network_map,
- ResourceCollector &resources,
- DummyDataSources &data_sources,
- SimulationInfluences &r_influences)
+static void collect_emitters(CollectContext &context)
{
- for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) {
- std::string name = dnode_to_path(*dnode);
- Vector<const ParticleForce *> forces = create_forces_for_particle_simulation(
- *dnode, network_map, resources, data_sources);
- r_influences.particle_forces.add_new(std::move(name), std::move(forces));
+ for (const DNode *dnode : nodes_by_type(context, "SimulationNodeParticleMeshEmitter")) {
+ ParticleEmitter *emitter = create_particle_emitter(context, *dnode);
+ if (emitter != nullptr) {
+ context.influences.particle_emitters.append(emitter);
+ }
}
}
-class MyBasicEmitter : public ParticleEmitter {
+static void collect_birth_events(CollectContext &context)
+{
+ for (const DNode *event_dnode : nodes_by_type(context, "SimulationNodeParticleBirthEvent")) {
+ const DInputSocket &execute_input = event_dnode->input(0);
+ if (execute_input.linked_sockets().size() != 1) {
+ continue;
+ }
+
+ Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
+ event_dnode->output(0));
+
+ const DOutputSocket &execute_source = *execute_input.linked_sockets()[0];
+ const ParticleAction *action = create_particle_action(context, execute_source, particle_names);
+ if (action == nullptr) {
+ continue;
+ }
+
+ for (StringRefNull particle_name : particle_names) {
+ context.influences.particle_birth_actions.add_as(particle_name, action);
+ }
+ }
+}
+
+static void collect_time_step_events(CollectContext &context)
+{
+ for (const DNode *event_dnode : nodes_by_type(context, "SimulationNodeParticleTimeStepEvent")) {
+ const DInputSocket &execute_input = event_dnode->input(0);
+ if (execute_input.linked_sockets().size() != 1) {
+ continue;
+ }
+
+ Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
+ event_dnode->output(0));
+
+ const DOutputSocket &execute_source = *execute_input.linked_sockets()[0];
+ const ParticleAction *action = create_particle_action(context, execute_source, particle_names);
+ if (action == nullptr) {
+ continue;
+ }
+
+ NodeSimParticleTimeStepEventType type =
+ (NodeSimParticleTimeStepEventType)event_dnode->node_ref().bnode()->custom1;
+ if (type == NODE_PARTICLE_TIME_STEP_EVENT_BEGIN) {
+ for (StringRefNull particle_name : particle_names) {
+ context.influences.particle_time_step_begin_actions.add_as(particle_name, action);
+ }
+ }
+ else {
+ for (StringRefNull particle_name : particle_names) {
+ context.influences.particle_time_step_end_actions.add_as(particle_name, action);
+ }
+ }
+ }
+}
+
+class SequenceParticleAction : public ParticleAction {
private:
- Array<std::string> names_;
- std::string my_state_;
- const fn::MultiFunction &inputs_fn_;
- uint32_t seed_;
+ Vector<const ParticleAction *> actions_;
public:
- MyBasicEmitter(Array<std::string> names,
- std::string my_state,
- const fn::MultiFunction &inputs_fn,
- uint32_t seed)
- : names_(std::move(names)),
- my_state_(std::move(my_state)),
- inputs_fn_(inputs_fn),
- seed_(seed)
+ SequenceParticleAction(Span<const ParticleAction *> actions) : actions_(std::move(actions))
{
}
- void emit(ParticleEmitterContext &context) const override
+ void execute(ParticleActionContext &context) const override
{
- auto *state = context.solve_context().state_map().lookup<ParticleMeshEmitterSimulationState>(
- my_state_);
- if (state == nullptr) {
- return;
+ for (const ParticleAction *action : actions_) {
+ action->execute(context);
}
+ }
+};
- fn::MFContextBuilder mf_context;
- mf_context.add_global_context("PersistentDataHandleMap",
- &context.solve_context().handle_map());
+class SetParticleAttributeAction : public ParticleAction {
+ private:
+ std::string attribute_name_;
+ const CPPType &cpp_type_;
+ const ParticleFunction &inputs_fn_;
- fn::MFParamsBuilder mf_params{inputs_fn_, 1};
- bke::PersistentObjectHandle object_handle;
- float rate;
- mf_params.add_uninitialized_single_output(&object_handle);
- mf_params.add_uninitialized_single_output(&rate);
- inputs_fn_.call(IndexRange(1), mf_params, mf_context);
+ public:
+ SetParticleAttributeAction(std::string attribute_name,
+ const CPPType &cpp_type,
+ const ParticleFunction &inputs_fn)
+ : attribute_name_(std::move(attribute_name)), cpp_type_(cpp_type), inputs_fn_(inputs_fn)
+ {
+ }
- const Object *object = context.solve_context().handle_map().lookup(object_handle);
- if (object == nullptr) {
+ void execute(ParticleActionContext &context) const override
+ {
+ std::optional<GMutableSpan> attribute_array = context.particles.attributes.try_get(
+ attribute_name_, cpp_type_);
+ if (!attribute_array.has_value()) {
return;
}
- Vector<float3> new_positions;
- Vector<float3> new_velocities;
- Vector<float> new_birth_times;
-
- TimeInterval time_interval = context.simulation_time_interval();
- float start_time = time_interval.start();
- RandomNumberGenerator rng{(*(uint32_t *)&start_time) ^ seed_};
-
- const float time_between_particles = 1.0f / rate;
- while (state->last_birth_time + time_between_particles < time_interval.end()) {
- new_positions.append(rng.get_unit_float3() * 0.3 + float3(object->loc));
- new_velocities.append(rng.get_unit_float3());
- const float birth_time = state->last_birth_time + time_between_particles;
- new_birth_times.append(birth_time);
- state->last_birth_time = birth_time;
- }
-
- for (StringRef name : names_) {
- ParticleAllocator *allocator = context.try_get_particle_allocator(name);
- if (allocator == nullptr) {
- return;
- }
-
- int amount = new_positions.size();
- fn::MutableAttributesRef attributes = allocator->allocate(amount);
+ ParticleFunctionEvaluator evaluator{inputs_fn_, context.solve_context, context.particles};
+ evaluator.compute();
+ GVSpan values = evaluator.get(0);
- initialized_copy_n(new_positions.data(), amount, attributes.get<float3>("Position").data());
- initialized_copy_n(new_velocities.data(), amount, attributes.get<float3>("Velocity").data());
- initialized_copy_n(
- new_birth_times.data(), amount, attributes.get<float>("Birth Time").data());
+ if (values.is_single_element()) {
+ cpp_type_.fill_initialized_indices(
+ values.as_single_element(), attribute_array->data(), context.particles.index_mask);
+ }
+ else {
+ GSpan value_array = values.as_full_array();
+ cpp_type_.copy_to_initialized_indices(
+ value_array.data(), attribute_array->data(), context.particles.index_mask);
}
}
};
-static Vector<const nodes::DNode *> find_linked_particle_simulations(
- const nodes::DOutputSocket &output_socket)
+static const ParticleAction *concatenate_actions(CollectContext &context,
+ Span<const ParticleAction *> actions)
{
- Vector<const nodes::DNode *> simulation_nodes;
- for (const nodes::DInputSocket *target_socket : output_socket.linked_sockets()) {
- if (target_socket->node().idname() == "SimulationNodeParticleSimulation") {
- simulation_nodes.append(&target_socket->node());
+ Vector<const ParticleAction *> non_null_actions;
+ for (const ParticleAction *action : actions) {
+ if (action != nullptr) {
+ non_null_actions.append(action);
}
}
- return simulation_nodes;
+ if (non_null_actions.size() == 0) {
+ return nullptr;
+ }
+ if (non_null_actions.size() == 1) {
+ return non_null_actions[0];
+ }
+ return &context.resources.construct<SequenceParticleAction>(AT, std::move(non_null_actions));
}
-static ParticleEmitter *create_particle_emitter(const nodes::DNode &dnode,
- ResourceCollector &resources,
- nodes::MFNetworkTreeMap &network_map,
- RequiredStates &r_required_states)
+static const ParticleAction *create_set_particle_attribute_action(
+ CollectContext &context, const DOutputSocket &dsocket, Span<StringRefNull> particle_names)
{
- Vector<const nodes::DNode *> simulation_dnodes = find_linked_particle_simulations(
- dnode.output(0));
- if (simulation_dnodes.size() == 0) {
+ const DNode &dnode = dsocket.node();
+ MFInputSocket &name_socket = context.network_map.lookup_dummy(dnode.input(1));
+ MFInputSocket &value_socket = name_socket.node().input(1);
+ std::optional<Array<std::string>> names = compute_global_string_inputs(context.network_map,
+ {&name_socket});
+ if (!names.has_value()) {
return nullptr;
}
- Array<std::string> names{simulation_dnodes.size()};
- for (int i : simulation_dnodes.index_range()) {
- names[i] = dnode_to_path(*simulation_dnodes[i]);
+ std::string attribute_name = (*names)[0];
+ const CPPType &attribute_type = value_socket.data_type().single_type();
+
+ const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context,
+ {&value_socket});
+ if (inputs_fn == nullptr) {
+ return nullptr;
}
- Array<const fn::MFInputSocket *> input_sockets{dnode.inputs().size()};
- for (int i : input_sockets.index_range()) {
- input_sockets[i] = &network_map.lookup_dummy(dnode.input(i));
+ for (StringRef particle_name : particle_names) {
+ context.influences.particle_attributes_builder.lookup_as(particle_name)
+ ->add(attribute_name, attribute_type);
}
- if (network_map.network().have_dummy_or_unlinked_dependencies(input_sockets)) {
+ ParticleAction &this_action = context.resources.construct<SetParticleAttributeAction>(
+ AT, attribute_name, attribute_type, *inputs_fn);
+
+ const ParticleAction *previous_action = create_particle_action(
+ context, dnode.input(0), particle_names);
+
+ return concatenate_actions(context, {previous_action, &this_action});
+}
+
+class ParticleConditionAction : public ParticleAction {
+ private:
+ const ParticleFunction &inputs_fn_;
+ const ParticleAction *action_true_;
+ const ParticleAction *action_false_;
+
+ public:
+ ParticleConditionAction(const ParticleFunction &inputs_fn,
+ const ParticleAction *action_true,
+ const ParticleAction *action_false)
+ : inputs_fn_(inputs_fn), action_true_(action_true), action_false_(action_false)
+ {
+ }
+
+ void execute(ParticleActionContext &context) const override
+ {
+ ParticleFunctionEvaluator evaluator{inputs_fn_, context.solve_context, context.particles};
+ evaluator.compute();
+ VSpan<bool> conditions = evaluator.get<bool>(0, "Condition");
+
+ if (conditions.is_single_element()) {
+ const bool condition = conditions.as_single_element();
+ if (condition) {
+ if (action_true_ != nullptr) {
+ action_true_->execute(context);
+ }
+ }
+ else {
+ if (action_false_ != nullptr) {
+ action_false_->execute(context);
+ }
+ }
+ }
+ else {
+ Span<bool> conditions_array = conditions.as_full_array();
+
+ Vector<int64_t> true_indices;
+ Vector<int64_t> false_indices;
+ for (int i : context.particles.index_mask) {
+ if (conditions_array[i]) {
+ true_indices.append(i);
+ }
+ else {
+ false_indices.append(i);
+ }
+ }
+
+ if (action_true_ != nullptr) {
+ ParticleChunkContext chunk_context{true_indices.as_span(), context.particles.attributes};
+ ParticleActionContext action_context{context.solve_context, chunk_context};
+ action_true_->execute(action_context);
+ }
+ if (action_false_ != nullptr) {
+ ParticleChunkContext chunk_context{false_indices.as_span(), context.particles.attributes};
+ ParticleActionContext action_context{context.solve_context, chunk_context};
+ action_false_->execute(action_context);
+ }
+ }
+ }
+};
+
+static const ParticleAction *create_particle_condition_action(CollectContext &context,
+ const DOutputSocket &dsocket,
+ Span<StringRefNull> particle_names)
+{
+ const DNode &dnode = dsocket.node();
+ MFInputSocket &condition_socket = context.network_map.lookup_dummy(dnode.input(0));
+
+ const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context,
+ {&condition_socket});
+ if (inputs_fn == nullptr) {
return nullptr;
}
- fn::MultiFunction &inputs_fn = resources.construct<fn::MFNetworkEvaluator>(
- AT, Span<const fn::MFOutputSocket *>(), input_sockets.as_span());
+ const ParticleAction *true_action = create_particle_action(
+ context, dnode.input(1), particle_names);
+ const ParticleAction *false_action = create_particle_action(
+ context, dnode.input(2), particle_names);
- std::string my_state_name = dnode_to_path(dnode);
- r_required_states.add(my_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER);
- uint32_t seed = DefaultHash<std::string>{}(my_state_name);
- ParticleEmitter &emitter = resources.construct<MyBasicEmitter>(
- AT, std::move(names), std::move(my_state_name), inputs_fn, seed);
- return &emitter;
+ if (true_action == nullptr && false_action == nullptr) {
+ return nullptr;
+ }
+ return &context.resources.construct<ParticleConditionAction>(
+ AT, *inputs_fn, true_action, false_action);
}
-static void collect_emitters(nodes::MFNetworkTreeMap &network_map,
- ResourceCollector &resources,
- SimulationInfluences &r_influences,
- RequiredStates &r_required_states)
+static const ParticleAction *create_particle_action(CollectContext &context,
+ const DOutputSocket &dsocket,
+ Span<StringRefNull> particle_names)
{
- for (const nodes::DNode *dnode :
- network_map.tree().nodes_by_type("SimulationNodeParticleMeshEmitter")) {
- ParticleEmitter *emitter = create_particle_emitter(
- *dnode, resources, network_map, r_required_states);
- if (emitter != nullptr) {
- r_influences.particle_emitters.append(emitter);
- }
+ const DNode &dnode = dsocket.node();
+ if (dnode.idname() == "SimulationNodeSetParticleAttribute") {
+ return create_set_particle_attribute_action(context, dsocket, particle_names);
+ }
+ if (dnode.idname() == "SimulationNodeExecuteCondition") {
+ return create_particle_condition_action(context, dsocket, particle_names);
}
+ return nullptr;
}
-static void prepare_particle_attribute_builders(nodes::MFNetworkTreeMap &network_map,
- ResourceCollector &resources,
- SimulationInfluences &r_influences)
+static void initialize_particle_attribute_builders(CollectContext &context)
{
- for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) {
- std::string name = dnode_to_path(*dnode);
- fn::AttributesInfoBuilder &builder = resources.construct<fn::AttributesInfoBuilder>(AT);
- builder.add<float3>("Position", {0, 0, 0});
- builder.add<float3>("Velocity", {0, 0, 0});
- builder.add<int>("ID", 0);
+ for (const DNode *dnode : context.particle_simulation_nodes) {
+ StringRef name = get_identifier(context, *dnode);
+ AttributesInfoBuilder &attributes_builder = context.resources.construct<AttributesInfoBuilder>(
+ AT);
+ attributes_builder.add<float3>("Position", {0, 0, 0});
+ attributes_builder.add<float3>("Velocity", {0, 0, 0});
+ attributes_builder.add<int>("ID", 0);
/* TODO: Use bool property, but need to add CD_PROP_BOOL first. */
- builder.add<int>("Dead", 0);
- builder.add<float>("Birth Time", 0.0f);
- r_influences.particle_attributes_builder.add_new(std::move(name), &builder);
+ attributes_builder.add<int>("Dead", 0);
+ /* TODO: Use uint32_t, but we don't have a corresponding custom property type. */
+ attributes_builder.add<int>("Hash", 0);
+ attributes_builder.add<float>("Birth Time", 0.0f);
+ attributes_builder.add<float>("Radius", 0.02f);
+ context.influences.particle_attributes_builder.add_new(name, &attributes_builder);
}
}
-static void find_used_data_blocks(const nodes::DerivedNodeTree &tree,
- SimulationInfluences &r_influences)
+static void optimize_function_network(CollectContext &context)
{
- const bNodeSocketType *socktype = nodeSocketTypeFind("NodeSocketObject");
- BLI_assert(socktype != nullptr);
-
- for (const nodes::DInputSocket *dsocket : tree.input_sockets()) {
- const bNodeSocket *bsocket = dsocket->bsocket();
- if (bsocket->typeinfo == socktype) {
- Object *value = ((const bNodeSocketValueObject *)bsocket->default_value)->value;
- if (value != nullptr) {
- r_influences.used_data_blocks.add(&value->id);
- }
- }
- }
+ fn::mf_network_optimization::constant_folding(context.network, context.resources);
+ fn::mf_network_optimization::common_subnetwork_elimination(context.network);
+ fn::mf_network_optimization::dead_node_removal(context.network);
+ // WM_clipboard_text_set(network.to_dot().c_str(), false);
}
void collect_simulation_influences(Simulation &simulation,
@@ -456,30 +758,28 @@ void collect_simulation_influences(Simulation &simulation,
SimulationInfluences &r_influences,
RequiredStates &r_required_states)
{
- nodes::NodeTreeRefMap tree_refs;
- const nodes::DerivedNodeTree tree{simulation.nodetree, tree_refs};
+ NodeTreeRefMap tree_refs;
+ const DerivedNodeTree tree{simulation.nodetree, tree_refs};
- fn::MFNetwork &network = resources.construct<fn::MFNetwork>(AT);
- nodes::MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources);
+ MFNetwork &network = resources.construct<MFNetwork>(AT);
+ MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources);
- prepare_particle_attribute_builders(network_map, resources, r_influences);
+ CollectContext context{r_influences, r_required_states, resources, network_map};
+ initialize_particle_attribute_builders(context);
- DummyDataSources data_sources;
- find_and_deduplicate_particle_attribute_nodes(network_map, data_sources);
+ prepare_particle_attribute_nodes(context);
+ prepare_time_input_nodes(context);
- fn::mf_network_optimization::constant_folding(network, resources);
- fn::mf_network_optimization::common_subnetwork_elimination(network);
- fn::mf_network_optimization::dead_node_removal(network);
- // WM_clipboard_text_set(network.to_dot().c_str(), false);
+ collect_forces(context);
+ collect_emitters(context);
+ collect_birth_events(context);
+ collect_time_step_events(context);
- collect_forces(network_map, resources, data_sources, r_influences);
- collect_emitters(network_map, resources, r_influences, r_required_states);
+ optimize_function_network(context);
- for (const nodes::DNode *dnode : get_particle_simulation_nodes(tree)) {
- r_required_states.add(dnode_to_path(*dnode), SIM_TYPE_NAME_PARTICLE_SIMULATION);
+ for (const DNode *dnode : context.particle_simulation_nodes) {
+ r_required_states.add(get_identifier(context, *dnode), SIM_TYPE_NAME_PARTICLE_SIMULATION);
}
-
- find_used_data_blocks(tree, r_influences);
}
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_collect_influences.hh b/source/blender/simulation/intern/simulation_collect_influences.hh
index 42cbea6977e..caf5a8c4ffa 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.hh
+++ b/source/blender/simulation/intern/simulation_collect_influences.hh
@@ -21,7 +21,7 @@
#include "BLI_resource_collector.hh"
-#include "simulation_solver.hh"
+#include "simulation_solver_influences.hh"
namespace blender::sim {
diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc
index ee7a8d40035..3c159eb1c58 100644
--- a/source/blender/simulation/intern/simulation_solver.cc
+++ b/source/blender/simulation/intern/simulation_solver.cc
@@ -17,23 +17,16 @@
#include "simulation_solver.hh"
#include "BKE_customdata.h"
-#include "BKE_lib_id.h"
#include "BKE_persistent_data_handle.hh"
#include "BLI_rand.hh"
#include "BLI_set.hh"
-namespace blender::sim {
-
-ParticleForce::~ParticleForce()
-{
-}
+#include "DEG_depsgraph_query.h"
-ParticleEmitter::~ParticleEmitter()
-{
-}
+namespace blender::sim {
-static CustomDataType cpp_to_custom_data_type(const fn::CPPType &type)
+static CustomDataType cpp_to_custom_data_type(const CPPType &type)
{
if (type.is<float3>()) {
return CD_PROP_FLOAT3;
@@ -48,18 +41,18 @@ static CustomDataType cpp_to_custom_data_type(const fn::CPPType &type)
return CD_PROP_FLOAT;
}
-static const fn::CPPType &custom_to_cpp_data_type(CustomDataType type)
+static const CPPType &custom_to_cpp_data_type(CustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT3:
- return fn::CPPType::get<float3>();
+ return CPPType::get<float3>();
case CD_PROP_FLOAT:
- return fn::CPPType::get<float>();
+ return CPPType::get<float>();
case CD_PROP_INT32:
- return fn::CPPType::get<int32_t>();
+ return CPPType::get<int32_t>();
default:
BLI_assert(false);
- return fn::CPPType::get<float>();
+ return CPPType::get<float>();
}
}
@@ -67,33 +60,33 @@ class CustomDataAttributesRef {
private:
Array<void *> buffers_;
int64_t size_;
- const fn::AttributesInfo &info_;
+ const AttributesInfo &info_;
public:
- CustomDataAttributesRef(CustomData &custom_data, int64_t size, const fn::AttributesInfo &info)
+ CustomDataAttributesRef(CustomData &custom_data, int64_t size, const AttributesInfo &info)
: buffers_(info.size(), nullptr), size_(size), info_(info)
{
for (int attribute_index : info.index_range()) {
StringRefNull name = info.name_of(attribute_index);
- const fn::CPPType &cpp_type = info.type_of(attribute_index);
+ const CPPType &cpp_type = info.type_of(attribute_index);
CustomDataType custom_type = cpp_to_custom_data_type(cpp_type);
void *data = CustomData_get_layer_named(&custom_data, custom_type, name.c_str());
buffers_[attribute_index] = data;
}
}
- operator fn::MutableAttributesRef()
+ operator MutableAttributesRef()
{
- return fn::MutableAttributesRef(info_, buffers_, size_);
+ return MutableAttributesRef(info_, buffers_, size_);
}
- operator fn::AttributesRef() const
+ operator AttributesRef() const
{
- return fn::AttributesRef(info_, buffers_, size_);
+ return AttributesRef(info_, buffers_, size_);
}
};
-static void ensure_attributes_exist(ParticleSimulationState *state, const fn::AttributesInfo &info)
+static void ensure_attributes_exist(ParticleSimulationState *state, const AttributesInfo &info)
{
bool found_layer_to_remove;
do {
@@ -101,7 +94,7 @@ static void ensure_attributes_exist(ParticleSimulationState *state, const fn::At
for (int layer_index = 0; layer_index < state->attributes.totlayer; layer_index++) {
CustomDataLayer *layer = &state->attributes.layers[layer_index];
BLI_assert(layer->name != nullptr);
- const fn::CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer->type);
+ const CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer->type);
StringRefNull name = layer->name;
if (!info.has_attribute(name, cpp_type)) {
found_layer_to_remove = true;
@@ -113,7 +106,7 @@ static void ensure_attributes_exist(ParticleSimulationState *state, const fn::At
for (int attribute_index : info.index_range()) {
StringRefNull attribute_name = info.name_of(attribute_index);
- const fn::CPPType &cpp_type = info.type_of(attribute_index);
+ const CPPType &cpp_type = info.type_of(attribute_index);
CustomDataType custom_type = cpp_to_custom_data_type(cpp_type);
if (CustomData_get_layer_named(&state->attributes, custom_type, attribute_name.c_str()) ==
nullptr) {
@@ -128,35 +121,38 @@ static void ensure_attributes_exist(ParticleSimulationState *state, const fn::At
}
}
-BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &solve_context,
- ParticleSimulationState &state,
- const fn::AttributesInfo &attributes_info)
+BLI_NOINLINE static void simulate_particle_chunk(SimulationSolveContext &solve_context,
+ ParticleSimulationState &state,
+ MutableAttributesRef attributes,
+ MutableSpan<float> remaining_durations,
+ float end_time)
{
- CustomDataAttributesRef custom_data_attributes{
- state.attributes, state.tot_particles, attributes_info};
- fn::MutableAttributesRef attributes = custom_data_attributes;
-
- Array<float3> force_vectors{state.tot_particles, {0, 0, 0}};
- const Vector<const ParticleForce *> *forces =
- solve_context.influences().particle_forces.lookup_ptr(state.head.name);
-
- if (forces != nullptr) {
- ParticleChunkContext particle_chunk_context{IndexMask(state.tot_particles), attributes};
- ParticleForceContext particle_force_context{
- solve_context, particle_chunk_context, force_vectors};
+ int particle_amount = attributes.size();
+
+ Span<const ParticleAction *> begin_actions =
+ solve_context.influences.particle_time_step_begin_actions.lookup_as(state.head.name);
+ for (const ParticleAction *action : begin_actions) {
+ ParticleChunkContext particles{IndexMask(particle_amount), attributes};
+ ParticleActionContext action_context{solve_context, particles};
+ action->execute(action_context);
+ }
- for (const ParticleForce *force : *forces) {
- force->add_force(particle_force_context);
- }
+ Array<float3> force_vectors{particle_amount, {0, 0, 0}};
+ Span<const ParticleForce *> forces = solve_context.influences.particle_forces.lookup_as(
+ state.head.name);
+ for (const ParticleForce *force : forces) {
+ ParticleChunkContext particles{IndexMask(particle_amount), attributes};
+ ParticleForceContext particle_force_context{solve_context, particles, force_vectors};
+ force->add_force(particle_force_context);
}
MutableSpan<float3> positions = attributes.get<float3>("Position");
MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
MutableSpan<float> birth_times = attributes.get<float>("Birth Time");
MutableSpan<int> dead_states = attributes.get<int>("Dead");
- float end_time = solve_context.solve_interval().end();
- float time_step = solve_context.solve_interval().duration();
- for (int i : positions.index_range()) {
+
+ for (int i : IndexRange(particle_amount)) {
+ const float time_step = remaining_durations[i];
velocities[i] += force_vectors[i] * time_step;
positions[i] += velocities[i] * time_step;
@@ -164,14 +160,35 @@ BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &sol
dead_states[i] = true;
}
}
+
+ Span<const ParticleAction *> end_actions =
+ solve_context.influences.particle_time_step_end_actions.lookup_as(state.head.name);
+ for (const ParticleAction *action : end_actions) {
+ ParticleChunkContext particles{IndexMask(particle_amount), attributes};
+ ParticleActionContext action_context{solve_context, particles};
+ action->execute(action_context);
+ }
+}
+
+BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &solve_context,
+ ParticleSimulationState &state,
+ const AttributesInfo &attributes_info)
+{
+ CustomDataAttributesRef custom_data_attributes{
+ state.attributes, state.tot_particles, attributes_info};
+ MutableAttributesRef attributes = custom_data_attributes;
+
+ Array<float> remaining_durations(state.tot_particles, solve_context.solve_interval.duration());
+ simulate_particle_chunk(
+ solve_context, state, attributes, remaining_durations, solve_context.solve_interval.stop());
}
BLI_NOINLINE static void run_emitters(SimulationSolveContext &solve_context,
ParticleAllocators &particle_allocators)
{
- for (const ParticleEmitter *emitter : solve_context.influences().particle_emitters) {
+ for (const ParticleEmitter *emitter : solve_context.influences.particle_emitters) {
ParticleEmitterContext emitter_context{
- solve_context, particle_allocators, solve_context.solve_interval()};
+ solve_context, particle_allocators, solve_context.solve_interval};
emitter->emit(emitter_context);
}
}
@@ -181,10 +198,10 @@ BLI_NOINLINE static int count_particles_after_time_step(ParticleSimulationState
{
CustomDataAttributesRef custom_data_attributes{
state.attributes, state.tot_particles, allocator.attributes_info()};
- fn::MutableAttributesRef attributes = custom_data_attributes;
+ MutableAttributesRef attributes = custom_data_attributes;
int new_particle_amount = attributes.get<int>("Dead").count(0);
- for (fn::MutableAttributesRef emitted_attributes : allocator.get_allocations()) {
+ for (MutableAttributesRef emitted_attributes : allocator.get_allocations()) {
new_particle_amount += emitted_attributes.get<int>("Dead").count(0);
}
@@ -199,7 +216,7 @@ BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationSta
CustomDataAttributesRef custom_data_attributes{
state.attributes, state.tot_particles, allocator.attributes_info()};
- Vector<fn::MutableAttributesRef> particle_sources;
+ Vector<MutableAttributesRef> particle_sources;
particle_sources.append(custom_data_attributes);
particle_sources.extend(allocator.get_allocations());
@@ -211,16 +228,16 @@ BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationSta
dead_layer = &layer;
continue;
}
- const fn::CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer.type);
- fn::GMutableSpan new_buffer{
+ const CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer.type);
+ GMutableSpan new_buffer{
cpp_type,
MEM_mallocN_aligned(new_particle_amount * cpp_type.size(), cpp_type.alignment(), AT),
new_particle_amount};
int current = 0;
- for (fn::MutableAttributesRef attributes : particle_sources) {
+ for (MutableAttributesRef attributes : particle_sources) {
Span<int> dead_states = attributes.get<int>("Dead");
- fn::GSpan source_buffer = attributes.get(name);
+ GSpan source_buffer = attributes.get(name);
BLI_assert(source_buffer.type() == cpp_type);
for (int i : attributes.index_range()) {
if (dead_states[i] == 0) {
@@ -233,7 +250,7 @@ BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationSta
if (layer.data != nullptr) {
MEM_freeN(layer.data);
}
- layer.data = new_buffer.buffer();
+ layer.data = new_buffer.data();
}
BLI_assert(dead_layer != nullptr);
@@ -246,56 +263,10 @@ BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationSta
state.next_particle_id += allocator.total_allocated();
}
-static void update_persistent_data_handles(Simulation &simulation,
- const VectorSet<ID *> &used_data_blocks)
-{
- Set<ID *> contained_ids;
- Set<int> used_handles;
-
- /* Remove handles that have been invalidated. */
- LISTBASE_FOREACH_MUTABLE (
- PersistentDataHandleItem *, handle_item, &simulation.persistent_data_handles) {
- if (handle_item->id == nullptr) {
- BLI_remlink(&simulation.persistent_data_handles, handle_item);
- continue;
- }
- if (!used_data_blocks.contains(handle_item->id)) {
- id_us_min(handle_item->id);
- BLI_remlink(&simulation.persistent_data_handles, handle_item);
- MEM_freeN(handle_item);
- continue;
- }
- contained_ids.add_new(handle_item->id);
- used_handles.add_new(handle_item->handle);
- }
-
- /* Add new handles that are not in the list yet. */
- int next_handle = 0;
- for (ID *id : used_data_blocks) {
- if (contained_ids.contains(id)) {
- continue;
- }
-
- /* Find the next available handle. */
- while (used_handles.contains(next_handle)) {
- next_handle++;
- }
- used_handles.add_new(next_handle);
-
- PersistentDataHandleItem *handle_item = (PersistentDataHandleItem *)MEM_callocN(
- sizeof(*handle_item), AT);
- /* Cannot store const pointers in DNA. */
- id_us_plus(id);
- handle_item->id = id;
- handle_item->handle = next_handle;
-
- BLI_addtail(&simulation.persistent_data_handles, handle_item);
- }
-}
-
void initialize_simulation_states(Simulation &simulation,
Depsgraph &UNUSED(depsgraph),
- const SimulationInfluences &UNUSED(influences))
+ const SimulationInfluences &UNUSED(influences),
+ const bke::PersistentDataHandleMap &UNUSED(handle_map))
{
simulation.current_simulation_time = 0.0f;
}
@@ -303,15 +274,10 @@ void initialize_simulation_states(Simulation &simulation,
void solve_simulation_time_step(Simulation &simulation,
Depsgraph &depsgraph,
const SimulationInfluences &influences,
+ const bke::PersistentDataHandleMap &handle_map,
+ const DependencyAnimations &dependency_animations,
float time_step)
{
- update_persistent_data_handles(simulation, influences.used_data_blocks);
-
- bke::PersistentDataHandleMap handle_map;
- LISTBASE_FOREACH (PersistentDataHandleItem *, handle, &simulation.persistent_data_handles) {
- handle_map.add(handle->handle, *handle->id);
- }
-
SimulationStateMap state_map;
LISTBASE_FOREACH (SimulationState *, state, &simulation.states) {
state_map.add(state);
@@ -322,30 +288,32 @@ void solve_simulation_time_step(Simulation &simulation,
influences,
TimeInterval(simulation.current_simulation_time, time_step),
state_map,
- handle_map};
- TimeInterval simulation_time_interval{simulation.current_simulation_time, time_step};
+ handle_map,
+ dependency_animations};
Span<ParticleSimulationState *> particle_simulation_states =
state_map.lookup<ParticleSimulationState>();
- Map<std::string, std::unique_ptr<fn::AttributesInfo>> attribute_infos;
+ Map<std::string, std::unique_ptr<AttributesInfo>> attribute_infos;
Map<std::string, std::unique_ptr<ParticleAllocator>> particle_allocators_map;
for (ParticleSimulationState *state : particle_simulation_states) {
- const fn::AttributesInfoBuilder &builder = *influences.particle_attributes_builder.lookup_as(
+ const AttributesInfoBuilder &builder = *influences.particle_attributes_builder.lookup_as(
state->head.name);
- auto info = std::make_unique<fn::AttributesInfo>(builder);
+ auto info = std::make_unique<AttributesInfo>(builder);
ensure_attributes_exist(state, *info);
+ uint32_t hash_seed = DefaultHash<StringRef>{}(state->head.name);
particle_allocators_map.add_new(
- state->head.name, std::make_unique<ParticleAllocator>(*info, state->next_particle_id));
+ state->head.name,
+ std::make_unique<ParticleAllocator>(*info, state->next_particle_id, hash_seed));
attribute_infos.add_new(state->head.name, std::move(info));
}
ParticleAllocators particle_allocators{particle_allocators_map};
for (ParticleSimulationState *state : particle_simulation_states) {
- const fn::AttributesInfo &attributes_info = *attribute_infos.lookup_as(state->head.name);
+ const AttributesInfo &attributes_info = *attribute_infos.lookup_as(state->head.name);
simulate_existing_particles(solve_context, *state, attributes_info);
}
@@ -353,10 +321,35 @@ void solve_simulation_time_step(Simulation &simulation,
for (ParticleSimulationState *state : particle_simulation_states) {
ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name);
+
+ for (MutableAttributesRef attributes : allocator.get_allocations()) {
+ Span<const ParticleAction *> actions = influences.particle_birth_actions.lookup_as(
+ state->head.name);
+ for (const ParticleAction *action : actions) {
+ ParticleChunkContext chunk_context{IndexRange(attributes.size()), attributes};
+ ParticleActionContext action_context{solve_context, chunk_context};
+ action->execute(action_context);
+ }
+ }
+ }
+
+ for (ParticleSimulationState *state : particle_simulation_states) {
+ ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name);
+
+ for (MutableAttributesRef attributes : allocator.get_allocations()) {
+ Array<float> remaining_durations(attributes.size());
+ Span<float> birth_times = attributes.get<float>("Birth Time");
+ const float end_time = solve_context.solve_interval.stop();
+ for (int i : attributes.index_range()) {
+ remaining_durations[i] = end_time - birth_times[i];
+ }
+ simulate_particle_chunk(solve_context, *state, attributes, remaining_durations, end_time);
+ }
+
remove_dead_and_add_new_particles(*state, allocator);
}
- simulation.current_simulation_time = simulation_time_interval.end();
+ simulation.current_simulation_time = solve_context.solve_interval.stop();
}
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver.hh b/source/blender/simulation/intern/simulation_solver.hh
index 2dc0921ad9e..9d30ea87731 100644
--- a/source/blender/simulation/intern/simulation_solver.hh
+++ b/source/blender/simulation/intern/simulation_solver.hh
@@ -17,259 +17,22 @@
#ifndef __SIM_SIMULATION_SOLVER_HH__
#define __SIM_SIMULATION_SOLVER_HH__
-#include "BLI_float3.hh"
-#include "BLI_span.hh"
-
-#include "DNA_simulation_types.h"
-
-#include "FN_attributes_ref.hh"
-
-#include "BKE_persistent_data_handle.hh"
-#include "BKE_simulation.h"
-
-#include "particle_allocator.hh"
-#include "time_interval.hh"
+#include "simulation_collect_influences.hh"
struct Depsgraph;
namespace blender::sim {
-class ParticleEmitterContext;
-class ParticleForceContext;
-
-class ParticleEmitter {
- public:
- virtual ~ParticleEmitter();
- virtual void emit(ParticleEmitterContext &context) const = 0;
-};
-
-class ParticleForce {
- public:
- virtual ~ParticleForce();
- virtual void add_force(ParticleForceContext &context) const = 0;
-};
-
-struct SimulationInfluences {
- Map<std::string, Vector<const ParticleForce *>> particle_forces;
- Map<std::string, fn::AttributesInfoBuilder *> particle_attributes_builder;
- Vector<const ParticleEmitter *> particle_emitters;
- VectorSet<ID *> used_data_blocks;
-};
-
-class SimulationStateMap {
- private:
- Map<StringRefNull, SimulationState *> states_by_name_;
- Map<StringRefNull, Vector<SimulationState *>> states_by_type_;
-
- public:
- void add(SimulationState *state)
- {
- states_by_name_.add_new(state->name, state);
- states_by_type_.lookup_or_add_default(state->type).append(state);
- }
-
- template<typename StateType> StateType *lookup(StringRef name) const
- {
- const char *type = BKE_simulation_get_state_type_name<StateType>();
- return (StateType *)this->lookup_name_type(name, type);
- }
-
- template<typename StateType> Span<StateType *> lookup() const
- {
- const char *type = BKE_simulation_get_state_type_name<StateType>();
- return this->lookup_type(type).cast<StateType *>();
- }
-
- SimulationState *lookup_name_type(StringRef name, StringRef type) const
- {
- SimulationState *state = states_by_name_.lookup_default_as(name, nullptr);
- if (state == nullptr) {
- return nullptr;
- }
- if (state->type == type) {
- return state;
- }
- return nullptr;
- }
-
- Span<SimulationState *> lookup_type(StringRef type) const
- {
- const Vector<SimulationState *> *states = states_by_type_.lookup_ptr_as(type);
- if (states == nullptr) {
- return {};
- }
- else {
- return states->as_span();
- }
- }
-};
-
-class SimulationSolveContext {
- private:
- Simulation &simulation_;
- Depsgraph &depsgraph_;
- const SimulationInfluences &influences_;
- TimeInterval solve_interval_;
- const SimulationStateMap &state_map_;
- const bke::PersistentDataHandleMap &id_handle_map_;
-
- public:
- SimulationSolveContext(Simulation &simulation,
- Depsgraph &depsgraph,
- const SimulationInfluences &influences,
- TimeInterval solve_interval,
- const SimulationStateMap &state_map,
- const bke::PersistentDataHandleMap &handle_map)
- : simulation_(simulation),
- depsgraph_(depsgraph),
- influences_(influences),
- solve_interval_(solve_interval),
- state_map_(state_map),
- id_handle_map_(handle_map)
- {
- }
-
- TimeInterval solve_interval() const
- {
- return solve_interval_;
- }
-
- const SimulationInfluences &influences() const
- {
- return influences_;
- }
-
- const bke::PersistentDataHandleMap &handle_map() const
- {
- return id_handle_map_;
- }
-
- const SimulationStateMap &state_map() const
- {
- return state_map_;
- }
-};
-
-class ParticleAllocators {
- private:
- Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators_;
-
- public:
- ParticleAllocators(Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators)
- : allocators_(allocators)
- {
- }
-
- ParticleAllocator *try_get_allocator(StringRef particle_simulation_name)
- {
- auto *ptr = allocators_.lookup_ptr_as(particle_simulation_name);
- if (ptr != nullptr) {
- return ptr->get();
- }
- else {
- return nullptr;
- }
- }
-};
-
-class ParticleChunkContext {
- private:
- IndexMask index_mask_;
- fn::MutableAttributesRef attributes_;
-
- public:
- ParticleChunkContext(IndexMask index_mask, fn::MutableAttributesRef attributes)
- : index_mask_(index_mask), attributes_(attributes)
- {
- }
-
- IndexMask index_mask() const
- {
- return index_mask_;
- }
-
- fn::MutableAttributesRef attributes()
- {
- return attributes_;
- }
-
- fn::AttributesRef attributes() const
- {
- return attributes_;
- }
-};
-
-class ParticleEmitterContext {
- private:
- SimulationSolveContext &solve_context_;
- ParticleAllocators &particle_allocators_;
- TimeInterval simulation_time_interval_;
-
- public:
- ParticleEmitterContext(SimulationSolveContext &solve_context,
- ParticleAllocators &particle_allocators,
- TimeInterval simulation_time_interval)
- : solve_context_(solve_context),
- particle_allocators_(particle_allocators),
- simulation_time_interval_(simulation_time_interval)
- {
- }
-
- SimulationSolveContext &solve_context()
- {
- return solve_context_;
- }
-
- ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name)
- {
- return particle_allocators_.try_get_allocator(particle_simulation_name);
- }
-
- TimeInterval simulation_time_interval() const
- {
- return simulation_time_interval_;
- }
-};
-
-class ParticleForceContext {
- private:
- SimulationSolveContext &solve_context_;
- const ParticleChunkContext &particle_chunk_context_;
- MutableSpan<float3> force_dst_;
-
- public:
- ParticleForceContext(SimulationSolveContext &solve_context,
- const ParticleChunkContext &particle_chunk_context,
- MutableSpan<float3> force_dst)
- : solve_context_(solve_context),
- particle_chunk_context_(particle_chunk_context),
- force_dst_(force_dst)
- {
- }
-
- SimulationSolveContext &solve_context()
- {
- return solve_context_;
- }
-
- const ParticleChunkContext &particle_chunk() const
- {
- return particle_chunk_context_;
- }
-
- MutableSpan<float3> force_dst()
- {
- return force_dst_;
- }
-};
-
void initialize_simulation_states(Simulation &simulation,
Depsgraph &depsgraph,
- const SimulationInfluences &influences);
+ const SimulationInfluences &influences,
+ const bke::PersistentDataHandleMap &handle_map);
void solve_simulation_time_step(Simulation &simulation,
Depsgraph &depsgraph,
const SimulationInfluences &influences,
+ const bke::PersistentDataHandleMap &handle_map,
+ const DependencyAnimations &dependency_animations,
float time_step);
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver_influences.cc b/source/blender/simulation/intern/simulation_solver_influences.cc
new file mode 100644
index 00000000000..75c2c820651
--- /dev/null
+++ b/source/blender/simulation/intern/simulation_solver_influences.cc
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "simulation_solver_influences.hh"
+
+#include "DNA_object_types.h"
+
+namespace blender::sim {
+
+ParticleForce::~ParticleForce()
+{
+}
+
+ParticleEmitter::~ParticleEmitter()
+{
+}
+
+ParticleAction::~ParticleAction()
+{
+}
+
+DependencyAnimations::~DependencyAnimations()
+{
+}
+
+bool DependencyAnimations::is_object_transform_changing(Object &UNUSED(object)) const
+{
+ return false;
+}
+
+void DependencyAnimations::get_object_transforms(Object &object,
+ Span<float> simulation_times,
+ MutableSpan<float4x4> r_transforms) const
+{
+ assert_same_size(simulation_times, r_transforms);
+ float4x4 world_matrix = object.obmat;
+ r_transforms.fill(world_matrix);
+}
+
+} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver_influences.hh b/source/blender/simulation/intern/simulation_solver_influences.hh
new file mode 100644
index 00000000000..d3c515bb6a0
--- /dev/null
+++ b/source/blender/simulation/intern/simulation_solver_influences.hh
@@ -0,0 +1,194 @@
+/*
+ * 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 __SIM_SIMULATION_SOLVER_INFLUENCES_HH__
+#define __SIM_SIMULATION_SOLVER_INFLUENCES_HH__
+
+#include "BLI_float3.hh"
+#include "BLI_float4x4.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_span.hh"
+
+#include "DNA_simulation_types.h"
+
+#include "FN_attributes_ref.hh"
+
+#include "BKE_persistent_data_handle.hh"
+#include "BKE_simulation.h"
+
+#include "particle_allocator.hh"
+#include "time_interval.hh"
+
+namespace blender::sim {
+
+using fn::AttributesInfo;
+using fn::AttributesInfoBuilder;
+using fn::AttributesRef;
+using fn::CPPType;
+using fn::GMutableSpan;
+using fn::GSpan;
+using fn::MutableAttributesRef;
+
+struct ParticleEmitterContext;
+struct ParticleForceContext;
+struct ParticleActionContext;
+
+class ParticleEmitter {
+ public:
+ virtual ~ParticleEmitter();
+ virtual void emit(ParticleEmitterContext &context) const = 0;
+};
+
+class ParticleForce {
+ public:
+ virtual ~ParticleForce();
+ virtual void add_force(ParticleForceContext &context) const = 0;
+};
+
+class ParticleAction {
+ public:
+ virtual ~ParticleAction();
+ virtual void execute(ParticleActionContext &context) const = 0;
+};
+
+struct SimulationInfluences {
+ MultiValueMap<std::string, const ParticleForce *> particle_forces;
+ MultiValueMap<std::string, const ParticleAction *> particle_birth_actions;
+ MultiValueMap<std::string, const ParticleAction *> particle_time_step_begin_actions;
+ MultiValueMap<std::string, const ParticleAction *> particle_time_step_end_actions;
+ Map<std::string, AttributesInfoBuilder *> particle_attributes_builder;
+ Vector<const ParticleEmitter *> particle_emitters;
+};
+
+class SimulationStateMap {
+ private:
+ Map<StringRefNull, SimulationState *> states_by_name_;
+ MultiValueMap<StringRefNull, SimulationState *> states_by_type_;
+
+ public:
+ void add(SimulationState *state)
+ {
+ states_by_name_.add_new(state->name, state);
+ states_by_type_.add(state->type, state);
+ }
+
+ template<typename StateType> StateType *lookup(StringRef name) const
+ {
+ const char *type = BKE_simulation_get_state_type_name<StateType>();
+ return (StateType *)this->lookup_name_type(name, type);
+ }
+
+ template<typename StateType> Span<StateType *> lookup() const
+ {
+ const char *type = BKE_simulation_get_state_type_name<StateType>();
+ return this->lookup_type(type).cast<StateType *>();
+ }
+
+ SimulationState *lookup_name_type(StringRef name, StringRef type) const
+ {
+ SimulationState *state = states_by_name_.lookup_default_as(name, nullptr);
+ if (state == nullptr) {
+ return nullptr;
+ }
+ if (state->type == type) {
+ return state;
+ }
+ return nullptr;
+ }
+
+ Span<SimulationState *> lookup_type(StringRef type) const
+ {
+ return states_by_type_.lookup_as(type);
+ }
+};
+
+class DependencyAnimations {
+ public:
+ ~DependencyAnimations();
+
+ virtual bool is_object_transform_changing(Object &object) const;
+ virtual void get_object_transforms(Object &object,
+ Span<float> simulation_times,
+ MutableSpan<float4x4> r_transforms) const;
+};
+
+struct SimulationSolveContext {
+ Simulation &simulation;
+ Depsgraph &depsgraph;
+ const SimulationInfluences &influences;
+ TimeInterval solve_interval;
+ const SimulationStateMap &state_map;
+ const bke::PersistentDataHandleMap &handle_map;
+ const DependencyAnimations &dependency_animations;
+};
+
+class ParticleAllocators {
+ private:
+ Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators_;
+
+ public:
+ ParticleAllocators(Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators)
+ : allocators_(allocators)
+ {
+ }
+
+ ParticleAllocator *try_get_allocator(StringRef particle_simulation_name)
+ {
+ auto *ptr = allocators_.lookup_ptr_as(particle_simulation_name);
+ if (ptr != nullptr) {
+ return ptr->get();
+ }
+ else {
+ return nullptr;
+ }
+ }
+};
+
+struct ParticleChunkContext {
+ IndexMask index_mask;
+ MutableAttributesRef attributes;
+};
+
+struct ParticleEmitterContext {
+ SimulationSolveContext &solve_context;
+ ParticleAllocators &particle_allocators;
+ TimeInterval emit_interval;
+
+ template<typename StateType> StateType *lookup_state(StringRef name)
+ {
+ return solve_context.state_map.lookup<StateType>(name);
+ }
+
+ ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name)
+ {
+ return particle_allocators.try_get_allocator(particle_simulation_name);
+ }
+};
+
+struct ParticleForceContext {
+ SimulationSolveContext &solve_context;
+ ParticleChunkContext &particles;
+ MutableSpan<float3> force_dst;
+};
+
+struct ParticleActionContext {
+ SimulationSolveContext &solve_context;
+ ParticleChunkContext &particles;
+};
+
+} // namespace blender::sim
+
+#endif /* __SIM_SIMULATION_SOLVER_INFLUENCES_HH__ */
diff --git a/source/blender/simulation/intern/simulation_update.cc b/source/blender/simulation/intern/simulation_update.cc
index 09219e0238f..32b582977d0 100644
--- a/source/blender/simulation/intern/simulation_update.cc
+++ b/source/blender/simulation/intern/simulation_update.cc
@@ -17,8 +17,11 @@
#include "SIM_simulation_update.hh"
#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_object.h"
#include "BKE_simulation.h"
+#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
@@ -29,8 +32,11 @@
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_rand.h"
+#include "BLI_set.hh"
#include "BLI_vector.hh"
+#include "NOD_node_tree_dependencies.hh"
+
#include "particle_function.hh"
#include "simulation_collect_influences.hh"
#include "simulation_solver.hh"
@@ -88,6 +94,131 @@ static void update_simulation_state_list(Simulation *simulation,
add_missing_states(simulation, required_states);
}
+class SampledDependencyAnimations : public DependencyAnimations {
+ private:
+ TimeInterval simulation_time_interval_;
+ MultiValueMap<Object *, float4x4> object_transforms_cache_;
+
+ public:
+ SampledDependencyAnimations(TimeInterval simulation_time_interval)
+ : simulation_time_interval_(simulation_time_interval)
+ {
+ }
+
+ void add_object_transforms(Object &object, Span<float4x4> transforms)
+ {
+ object_transforms_cache_.add_multiple(&object, transforms);
+ }
+
+ bool is_object_transform_changing(Object &object) const
+ {
+ return object_transforms_cache_.lookup(&object).size() >= 2;
+ }
+
+ void get_object_transforms(Object &object,
+ Span<float> simulation_times,
+ MutableSpan<float4x4> r_transforms) const
+ {
+ assert_same_size(simulation_times, r_transforms);
+ Span<float4x4> cached_transforms = object_transforms_cache_.lookup(&object);
+ if (cached_transforms.size() == 0) {
+ r_transforms.fill(object.obmat);
+ return;
+ }
+ if (cached_transforms.size() == 1) {
+ r_transforms.fill(cached_transforms[0]);
+ return;
+ }
+
+ for (int i : simulation_times.index_range()) {
+ const float simulation_time = simulation_times[i];
+ if (simulation_time <= simulation_time_interval_.start()) {
+ r_transforms[i] = cached_transforms.first();
+ continue;
+ }
+ if (simulation_time >= simulation_time_interval_.stop()) {
+ r_transforms[i] = cached_transforms.last();
+ continue;
+ }
+ const float factor = simulation_time_interval_.factor_at_time(simulation_time);
+ BLI_assert(factor > 0.0f && factor < 1.0f);
+ const float scaled_factor = factor * (cached_transforms.size() - 1);
+ const int lower_sample = (int)scaled_factor;
+ const int upper_sample = lower_sample + 1;
+ const float mix_factor = scaled_factor - lower_sample;
+ r_transforms[i] = float4x4::interpolate(
+ cached_transforms[lower_sample], cached_transforms[upper_sample], mix_factor);
+ }
+ }
+};
+
+static void sample_object_transforms(Object &object,
+ Depsgraph &depsgraph,
+ Scene &scene,
+ TimeInterval scene_frame_interval,
+ MutableSpan<float4x4> r_transforms)
+{
+ if (r_transforms.size() == 0) {
+ return;
+ }
+ if (r_transforms.size() == 1) {
+ r_transforms[0] = object.obmat;
+ return;
+ }
+
+ Array<float> frames(r_transforms.size());
+ scene_frame_interval.compute_uniform_samples(frames);
+
+ for (int i : frames.index_range()) {
+ float frame = frames[i];
+ const int recursion_depth = 5;
+ BKE_object_modifier_update_subframe(
+ &depsgraph, &scene, &object, false, recursion_depth, frame, eModifierType_None);
+ r_transforms[i] = object.obmat;
+ }
+}
+
+template<typename T> static bool all_values_equal(Span<T> values)
+{
+ if (values.size() == 0) {
+ return true;
+ }
+ for (const T &value : values.drop_front(1)) {
+ if (value != values[0]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void prepare_dependency_animations(Depsgraph &depsgraph,
+ Scene &scene,
+ Simulation &simulation,
+ TimeInterval scene_frame_interval,
+ SampledDependencyAnimations &r_dependency_animations)
+{
+ LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation.dependencies) {
+ ID *id_cow = DEG_get_evaluated_id(&depsgraph, dependency->id);
+ if (id_cow == nullptr) {
+ continue;
+ }
+ if (GS(id_cow->name) != ID_OB) {
+ continue;
+ }
+ Object &object_cow = *(Object *)id_cow;
+ constexpr int sample_count = 10;
+ Array<float4x4, sample_count> transforms(sample_count);
+ sample_object_transforms(object_cow, depsgraph, scene, scene_frame_interval, transforms);
+
+ /* If all samples are the same, only store one. */
+ Span<float4x4> transforms_to_use = (all_values_equal(transforms.as_span())) ?
+ transforms.as_span().take_front(1) :
+ transforms.as_span();
+
+ r_dependency_animations.add_object_transforms(object_cow, transforms_to_use);
+ }
+}
+
void update_simulation_in_depsgraph(Depsgraph *depsgraph,
Scene *scene_cow,
Simulation *simulation_cow)
@@ -108,13 +239,20 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
SimulationInfluences influences;
RequiredStates required_states;
- /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */
- collect_simulation_influences(*simulation_orig, resources, influences, required_states);
+ collect_simulation_influences(*simulation_cow, resources, influences, required_states);
+
+ bke::PersistentDataHandleMap handle_map;
+ LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation_orig->dependencies) {
+ ID *id_cow = DEG_get_evaluated_id(depsgraph, dependency->id);
+ if (id_cow != nullptr) {
+ handle_map.add(dependency->handle, *id_cow);
+ }
+ }
if (current_frame == 1) {
reinitialize_empty_simulation_states(simulation_orig, required_states);
- initialize_simulation_states(*simulation_orig, *depsgraph, influences);
+ initialize_simulation_states(*simulation_orig, *depsgraph, influences, handle_map);
simulation_orig->current_frame = 1;
copy_states_to_cow(simulation_orig, simulation_cow);
@@ -122,12 +260,97 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
else if (current_frame == simulation_orig->current_frame + 1) {
update_simulation_state_list(simulation_orig, required_states);
- float time_step = 1.0f / 24.0f;
- solve_simulation_time_step(*simulation_orig, *depsgraph, influences, time_step);
+ const float fps = scene_cow->r.frs_sec / scene_cow->r.frs_sec_base;
+ const float time_step = 1.0f / fps;
+ TimeInterval scene_frame_interval(current_frame - 1, 1);
+ TimeInterval simulation_time_interval(simulation_orig->current_simulation_time, time_step);
+ SampledDependencyAnimations dependency_animations{simulation_time_interval};
+ prepare_dependency_animations(
+ *depsgraph, *scene_cow, *simulation_orig, scene_frame_interval, dependency_animations);
+
+ solve_simulation_time_step(
+ *simulation_orig, *depsgraph, influences, handle_map, dependency_animations, time_step);
simulation_orig->current_frame = current_frame;
copy_states_to_cow(simulation_orig, simulation_cow);
}
}
+/* Returns true when dependencies have changed. */
+bool update_simulation_dependencies(Simulation *simulation)
+{
+ nodes::NodeTreeDependencies dependencies = nodes::find_node_tree_dependencies(
+ *simulation->nodetree);
+
+ ListBase *dependency_list = &simulation->dependencies;
+
+ bool dependencies_changed = false;
+
+ Map<ID *, SimulationDependency *> dependency_by_id;
+ Map<SimulationDependency *, int> old_flag_by_dependency;
+ Set<int> used_handles;
+
+ /* Remove unused handle items and clear flags that are reinitialized later. */
+ LISTBASE_FOREACH_MUTABLE (SimulationDependency *, dependency, dependency_list) {
+ if (dependencies.depends_on(dependency->id)) {
+ dependency_by_id.add_new(dependency->id, dependency);
+ used_handles.add_new(dependency->handle);
+ old_flag_by_dependency.add_new(dependency, dependency->flag);
+ dependency->flag &= ~(SIM_DEPENDS_ON_TRANSFORM | SIM_DEPENDS_ON_GEOMETRY);
+ }
+ else {
+ if (dependency->id != nullptr) {
+ id_us_min(dependency->id);
+ }
+ BLI_remlink(dependency_list, dependency);
+ MEM_freeN(dependency);
+ dependencies_changed = true;
+ }
+ }
+
+ /* Add handle items for new id dependencies. */
+ int next_handle = 0;
+ for (ID *id : dependencies.id_dependencies()) {
+ dependency_by_id.lookup_or_add_cb(id, [&]() {
+ while (used_handles.contains(next_handle)) {
+ next_handle++;
+ }
+ used_handles.add_new(next_handle);
+
+ SimulationDependency *dependency = (SimulationDependency *)MEM_callocN(sizeof(*dependency),
+ AT);
+ id_us_plus(id);
+ dependency->id = id;
+ dependency->handle = next_handle;
+ BLI_addtail(dependency_list, dependency);
+
+ return dependency;
+ });
+ }
+
+ /* Set appropriate dependency flags. */
+ for (Object *object : dependencies.transform_dependencies()) {
+ SimulationDependency *dependency = dependency_by_id.lookup(&object->id);
+ dependency->flag |= SIM_DEPENDS_ON_TRANSFORM;
+ }
+ for (Object *object : dependencies.geometry_dependencies()) {
+ SimulationDependency *dependency = dependency_by_id.lookup(&object->id);
+ dependency->flag |= SIM_DEPENDS_ON_GEOMETRY;
+ }
+
+ if (!dependencies_changed) {
+ /* Check if any flags have changed. */
+ LISTBASE_FOREACH (SimulationDependency *, dependency, dependency_list) {
+ uint32_t old_flag = old_flag_by_dependency.lookup_default(dependency, 0);
+ uint32_t new_flag = dependency->flag;
+ if (old_flag != new_flag) {
+ dependencies_changed = true;
+ break;
+ }
+ }
+ }
+
+ return dependencies_changed;
+}
+
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/time_interval.hh b/source/blender/simulation/intern/time_interval.hh
index 49600dd10de..5996dc5d25b 100644
--- a/source/blender/simulation/intern/time_interval.hh
+++ b/source/blender/simulation/intern/time_interval.hh
@@ -22,7 +22,7 @@
namespace blender::sim {
/**
- * The start time is inclusive and the end time is exclusive. The duration is zero, the interval
+ * The start time is exclusive and the end time is inclusive. If the duration is zero, the interval
* describes a single point in time.
*/
class TimeInterval {
@@ -41,7 +41,7 @@ class TimeInterval {
return start_;
}
- float end() const
+ float stop() const
{
return start_ + duration_;
}
@@ -50,6 +50,42 @@ class TimeInterval {
{
return duration_;
}
+
+ float time_at_factor(float factor) const
+ {
+ return start_ + factor * duration_;
+ }
+
+ float factor_at_time(float time) const
+ {
+ BLI_assert(duration_ > 0.0f);
+ return (time - start_) / duration_;
+ }
+
+ float safe_factor_at_time(float time) const
+ {
+ if (duration_ > 0.0f) {
+ return this->factor_at_time(time);
+ }
+ return 0.0f;
+ }
+
+ void compute_uniform_samples(MutableSpan<float> r_samples) const
+ {
+ int64_t amount = r_samples.size();
+ if (amount == 0) {
+ return;
+ }
+ if (amount == 1) {
+ r_samples[0] = this->time_at_factor(0.5f);
+ return;
+ }
+
+ const float step = duration_ / (float)(amount - 1);
+ for (int64_t i : r_samples.index_range()) {
+ r_samples[i] = start_ + i * step;
+ }
+ }
};
} // namespace blender::sim
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index e687af15982..90d9ba45637 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -29,7 +29,6 @@
#include "BKE_context.h"
#include "GPU_batch.h"
-#include "GPU_glew.h"
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 396b59ba6e2..2038a82c9fd 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -38,7 +38,6 @@
#include "ED_select_utils.h"
#include "ED_view3d.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
#include "GPU_state.h"
@@ -582,7 +581,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
rcti rect;
/* Almost certainly overkill, but allow for many custom gizmos. */
- GLuint buffer[MAXPICKBUF];
+ uint buffer[MAXPICKBUF];
short hits;
BLI_rcti_init_pt_radius(&rect, co, hotspot);
@@ -625,7 +624,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_with_precalc(&unproj_precalc, co_screen, co_3d_origin);
- GLuint *buf_iter = buffer;
+ uint *buf_iter = buffer;
int hit_found = -1;
float dot_best = FLT_MAX;
@@ -649,7 +648,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
return hit_found;
}
else {
- const GLuint *hit_near = GPU_select_buffer_near(buffer, hits);
+ const uint *hit_near = GPU_select_buffer_near(buffer, hits);
return hit_near ? hit_near[3] : -1;
}
}
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index ad3fc7a1302..5f13adcb971 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -39,7 +39,6 @@
#include "BKE_context.h"
#include "BKE_idtype.h"
-#include "GPU_glew.h"
#include "GPU_shader.h"
#include "GPU_state.h"
#include "GPU_viewport.h"
@@ -424,9 +423,8 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
y,
drag->imb->x,
drag->imb->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
+ GPU_RGBA8,
+ false,
drag->imb->rect,
drag->scale,
drag->scale,
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 16454e473cc..4db6eb6af91 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -51,7 +51,6 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "GPU_draw.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -999,7 +998,7 @@ void wm_draw_update(bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
- GPU_free_unused_buffers();
+ BKE_image_free_unused_gpu_textures();
for (win = wm->windows.first; win; win = win->next) {
#ifdef WIN32
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index eee93fc9459..5a66cbd10eb 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -362,18 +362,8 @@ static void draw_filled_lasso(wmGesture *gt)
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(&state,
- rect.xmin,
- rect.ymin,
- w,
- h,
- GL_RED,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
- pixel_buf,
- 1.0f,
- 1.0f,
- NULL);
+ immDrawPixelsTex(
+ &state, rect.xmin, rect.ymin, w, h, GL_R8, false, pixel_buf, 1.0f, 1.0f, NULL);
GPU_shader_unbind();
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 945d5fd42e4..0390bc1e4ef 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -59,6 +59,7 @@
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_icons.h"
+#include "BKE_image.h"
#include "BKE_keyconfig.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
@@ -120,7 +121,6 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "GPU_draw.h"
#include "GPU_init_exit.h"
#include "GPU_material.h"
@@ -171,7 +171,7 @@ void WM_init_state_start_with_console_set(bool value)
*/
static bool opengl_is_init = false;
-void WM_init_opengl(Main *bmain)
+void WM_init_opengl(Main *UNUSED(bmain))
{
/* must be called only once */
BLI_assert(opengl_is_init == false);
@@ -185,9 +185,6 @@ void WM_init_opengl(Main *bmain)
DRW_opengl_context_create();
GPU_init();
- GPU_set_mipmap(bmain, true);
- GPU_set_linear_mipmap(true);
- GPU_set_anisotropic(U.anisotropic_filter);
GPU_pass_cache_init();
@@ -578,7 +575,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_subdiv_exit();
if (opengl_is_init) {
- GPU_free_unused_buffers();
+ BKE_image_free_unused_gpu_textures();
}
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 74e1c495a00..d0a70596957 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -335,9 +335,8 @@ static void playanim_toscreen(
offs_y + (ps->draw_flip[1] ? span_y : 0.0f),
ibuf->x,
ibuf->y,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- GL_NEAREST,
+ GPU_RGBA8,
+ false,
ibuf->rect,
((ps->draw_flip[0] ? -1.0f : 1.0f)) * (ps->zoom / (float)ps->win_x),
((ps->draw_flip[1] ? -1.0f : 1.0f)) * (ps->zoom / (float)ps->win_y),
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 477579ed620..0cb76404258 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -29,7 +29,6 @@
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "GPU_viewport.h"
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index a675647f57a..9b6bd66c0e5 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -24,8 +24,6 @@
#ifndef __WM_DRAW_H__
#define __WM_DRAW_H__
-#include "GPU_glew.h"
-
struct GPUOffScreen;
struct GPUTexture;
struct GPUViewport;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 8e7101ddcd5..c564f74b771 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -41,8 +41,8 @@
#include "wm_window.h"
#include "wm_xr_intern.h"
-wmSurface *g_xr_surface = NULL;
-CLG_LogRef LOG = {"wm.xr"};
+static wmSurface *g_xr_surface = NULL;
+static CLG_LogRef LOG = {"wm.xr"};
/* -------------------------------------------------------------------- */
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index 282eb9080f5..9a7509f81f3 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -12,7 +12,6 @@ if(WITH_GTESTS)
add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
add_subdirectory(bmesh)
- add_subdirectory(functions)
if(WITH_CODEC_FFMPEG)
add_subdirectory(ffmpeg)
endif()
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index d151dacd7a4..0727d317eaa 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -39,46 +39,31 @@ else()
set(BLI_path_util_extra_libs "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
endif()
-BLENDER_TEST(BLI_array "bf_blenlib")
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_delaunay_2d "bf_blenlib")
-BLENDER_TEST(BLI_disjoint_set "bf_blenlib")
-BLENDER_TEST(BLI_edgehash "bf_blenlib")
BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_heap "bf_blenlib")
BLENDER_TEST(BLI_heap_simple "bf_blenlib")
-BLENDER_TEST(BLI_index_mask "bf_blenlib")
-BLENDER_TEST(BLI_index_range "bf_blenlib")
BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_numaapi")
-BLENDER_TEST(BLI_linear_allocator "bf_blenlib")
BLENDER_TEST(BLI_linklist_lockfree "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_listbase "bf_blenlib")
-BLENDER_TEST(BLI_map "bf_blenlib")
BLENDER_TEST(BLI_math_base "bf_blenlib")
-BLENDER_TEST(BLI_math_base_safe "bf_blenlib")
BLENDER_TEST(BLI_math_bits "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
BLENDER_TEST(BLI_math_geom "bf_blenlib")
BLENDER_TEST(BLI_math_matrix "bf_blenlib")
BLENDER_TEST(BLI_math_vector "bf_blenlib")
BLENDER_TEST(BLI_memiter "bf_blenlib")
-BLENDER_TEST(BLI_memory_utils "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
-BLENDER_TEST(BLI_set "bf_blenlib")
-BLENDER_TEST(BLI_span "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
-BLENDER_TEST(BLI_stack_cxx "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")
-BLENDER_TEST(BLI_string_ref "bf_blenlib")
BLENDER_TEST(BLI_string_utf8 "bf_blenlib")
BLENDER_TEST(BLI_task "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_task_graph "bf_blenlib;bf_intern_numaapi")
-BLENDER_TEST(BLI_vector "bf_blenlib")
-BLENDER_TEST(BLI_vector_set "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_task_performance "bf_blenlib")
diff --git a/tests/gtests/functions/CMakeLists.txt b/tests/gtests/functions/CMakeLists.txt
deleted file mode 100644
index 1246bbd5599..00000000000
--- a/tests/gtests/functions/CMakeLists.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- .
- ..
- ../../../source/blender/blenlib
- ../../../source/blender/functions
- ../../../source/blender/makesdna
- ../../../intern/guardedalloc
-)
-
-setup_libdirs()
-include_directories(${INC})
-
-
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
-set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
-
-if(WITH_BUILDINFO)
- set(BUILDINFO buildinfoobj)
-endif()
-
-BLENDER_TEST(FN_array_spans "bf_blenlib;bf_functions;${BUILDINFO}")
-BLENDER_TEST(FN_attributes_ref "bf_blenlib;bf_functions;${BUILDINFO}")
-BLENDER_TEST(FN_cpp_type "bf_blenlib;bf_functions;${BUILDINFO}")
-BLENDER_TEST(FN_generic_vector_array "bf_blenlib;bf_functions;${BUILDINFO}")
-BLENDER_TEST(FN_multi_function "bf_blenlib;bf_functions;${BUILDINFO}")
-BLENDER_TEST(FN_multi_function_network "bf_blenlib;bf_functions;${BUILDINFO}")
-BLENDER_TEST(FN_spans "bf_blenlib;bf_functions;${BUILDINFO}")
diff --git a/tests/gtests/runner/CMakeLists.txt b/tests/gtests/runner/CMakeLists.txt
index 18d8f57364f..59537aab571 100644
--- a/tests/gtests/runner/CMakeLists.txt
+++ b/tests/gtests/runner/CMakeLists.txt
@@ -36,7 +36,7 @@ endif()
# directly referenced from other code.
get_property(_test_libs GLOBAL PROPERTY BLENDER_TEST_LIBS)
if(WIN32)
- list(APPEND TEST_LIBS ${_test_libs})
+ # Win32 is set using target_link_options after target creation.
elseif(APPLE)
list(APPEND TEST_LIBS "-Wl,-force_load" ${_test_libs})
elseif(UNIX)
@@ -44,7 +44,6 @@ elseif(UNIX)
else()
message(FATAL_ERROR "Unknown how to link whole-archive with your compiler ${CMAKE_CXX_COMPILER_ID}")
endif()
-unset(_test_libs)
# This builds `bin/tests/blender_test`, but does not add it as a single test.
setup_libdirs()
@@ -56,6 +55,18 @@ BLENDER_SRC_GTEST_EX(
)
setup_liblinks(blender_test)
+if(WIN32)
+ foreach(_lib ${_test_libs})
+ # Both target_link_libraries and target_link_options are required here
+ # target_link_libraries will add any dependend libraries, while just setting
+ # the wholearchive flag in target link options will not.
+ target_link_libraries(blender_test ${_lib})
+ target_link_options(blender_test PRIVATE /wholearchive:$<TARGET_FILE:${_lib}>)
+ endforeach()
+endif()
+
+unset(_test_libs)
+
# This runs the blender_test executable with `--gtest_list_tests`, then
# exposes those tests individually to the ctest runner.
# See https://cmake.org/cmake/help/v3.18/module/GoogleTest.html
@@ -66,7 +77,9 @@ set(_GOOGLETEST_DISCOVER_TESTS_SCRIPT
)
gtest_discover_tests(blender_test
- # So that unit tests know where to find files:
+# So that the binary can find its shared libs on window.
+ WORKING_DIRECTORY "$<TARGET_FILE_DIR:blender>"
+# So that unit tests know where to find files:
EXTRA_ARGS
--test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests"
--test-release-dir "${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}"